How to Fix Puppeteer’s Browser Launch Issue in Docker Containers with Node-HTML-to-Image
When working with image generation in a Node.js application, one of the most popular libraries is node-html-to-image
, which internally uses Puppeteer
to convert HTML content into image formats like JPEG or PNG. While this library works well in most cases, running it inside a Docker container can sometimes lead to browser launch failures, particularly with Puppeteer.
The Problem: Browser Launch Error in Docker
While generating an image in a Dockerized environment, you might encounter the following error:
codeError: Unable to launch browser, error message: Failed to launch the browser process! spawn /root/.cache/puppeteer/chrome/linux-115.0.5790.102/chrome-linux64/chrome ENOENT
This error occurs because node-html-to-image
uses Puppeteer
by default, which in turn attempts to download and use its own version of Chromium. In many cases, this Chromium version might not be compatible with your Docker environment, leading to errors such as the one mentioned above.
Root Cause
The key issue here is that Puppeteer
tries to download and use a Chromium version that doesn't always align with the operating system or dependencies available in your Docker container. Particularly in Alpine-based containers, Chromium dependencies are strict, and downloading an unsupported version causes launch failures.
The Solution: Control Puppeteer Versions and Chromium Binaries
To solve this issue, I forced node-html-to-image
to use puppeteer-core
, which gives full control over the Chromium version. Instead of allowing Puppeteer to manage Chromium downloads, we specify the exact version supported by Alpine and configure Puppeteer to use that version.
This ensures that there are no unexpected version mismatches that could lead to breakages.
Steps to Implement the Fix
1. Modify the Dockerfile
First, we need to modify the Dockerfile to explicitly install a specific version of Chromium that is compatible with the Alpine base image.
# Prevent Puppeteer from downloading Chromium
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
# Install the specific version of Chromium and required dependencies
RUN apk add --no-cache \
chromium=124.0.6367.78-r0 \
nss \
freetype \
harfbuzz \
ca-certificates \
ttf-freefont
Here, we:
Set
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
to skip Puppeteer’s default Chromium installation.Install a version of Chromium that is available in the Alpine repository.
Install dependencies like
nss
,freetype
,harfbuzz
, and others required by Chromium to function properly.
2. Update the Puppeteer Execution Path
Next, we configure node-html-to-image
to use puppeteer-core
and explicitly set the executablePath
for Puppeteer to point to the installed Chromium binary.
const puppeteerCore = require('puppeteer-core');
const nodeHtmlToImage = require('node-html-to-image');
// Generate email image
try {
await nodeHtmlToImage({
output: `uploads/emails/${email._id}.jpeg`,
html: emailInformation.html,
type: 'jpeg',
puppeteer: puppeteerCore,
puppeteerArgs: {
headless: 'shell',
args: ['--no-sandbox'],
executablePath: process.env.PUPPETEER_EXECUTABLE_PATH, // Path to the manually installed Chromium
},
});
} catch (puppeteerError) {
console.error(`Puppeteer error: ${puppeteerError.message}`);
return res
.status(500)
.send('Error generating image: ' + puppeteerError.message);
}
In this implementation:
puppeteer-core
is used instead of the fullpuppeteer
package, giving us full control over the Chromium version.executablePath
is set to thePUPPETEER_EXECUTABLE_PATH
environment variable, which points to the manually installed version of Chromium.
3. Configure the Environment Variables
Ensure that you set the PUPPETEER_EXECUTABLE_PATH
environment variable in your Docker runtime to match the installed Chromium binary's location. For Alpine, this would typically be:
bashCopy codeENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
This tells Puppeteer exactly where to find the Chromium executable, avoiding any ambiguity.
Why This Fix Works
By combining puppeteer-core
with a specific version of Chromium installed via the Alpine package manager, we eliminate Puppeteer’s dependency on its internal Chromium download. This ensures:
Version Control: You explicitly control which version of Chromium is used, avoiding incompatibility issues.
Stability: The versions of Chromium and Puppeteer are tightly coupled, reducing the likelihood of random breakages due to version mismatches.
Portability: The Docker container remains portable and reproducible, as it relies on a fixed version of Chromium rather than downloading new versions dynamically.
Conclusion
When running node-html-to-image
inside a Docker container, especially on Alpine Linux, you might encounter browser launch issues due to Puppeteer’s Chromium version incompatibility. By using puppeteer-core
, installing the correct Chromium version manually, and configuring the executable path, you can avoid these issues and ensure consistent, reliable image generation.
This approach guarantees that the versions never change, making your solution stable across different environments.
Subscribe to my newsletter
Read articles from Mohamed Zhioua directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Mohamed Zhioua
Mohamed Zhioua
Hеllo, I'm Mohamеd Zhioua, a dеdicatеd Full-Stack JavaScript Dеvеlopеr basеd in Tunis, Tunisia 📍. I'm on a mission to shapе thе futurе through codе.