To run Puppeteer with Chromium in an Alpine-based Docker image, install Chromium from Alpine’s repository, install the libraries and fonts that package requires, point Puppeteer at the package executable, and test the exact Alpine, architecture, Chromium, and Puppeteer versions together. Do not assume Puppeteer’s downloaded Chrome for Testing binary will work on Alpine: the Puppeteer project says Chrome does not support Alpine out of the box and requires compatible system dependencies.
This guide builds that setup, explains the sandbox decision, shows a smoke test, and covers the failure modes that usually make Alpine browser containers unreliable.
What you are building
The container will contain four deliberately pinned layers:
- An Alpine release and CPU architecture.
- The Alpine
chromiumpackage and its runtime libraries. - A Puppeteer version that you test with that Chromium build.
- An explicit executable path, rather than an accidentally downloaded browser.
Alpine’s package names and command aliases can change between branches. The Alpine v3.22 x86_64 package page currently lists Chromium 142.0.7444.59-r0, but that identifier applies only to that branch and architecture; check the package index for your own image before pinning it (Alpine v3.22 Chromium package).
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →#1 Best Overall
Choose the browser installation model
Use Alpine Chromium with Puppeteer
This is the Alpine-specific route. Install Chromium with apk, retain its dependencies, and set executablePath (or PUPPETEER_EXECUTABLE_PATH) to the executable exposed by your selected package.
Use the maintained Puppeteer image instead
Puppeteer also maintains a Docker image that includes Chrome for Testing and its dependencies. The current official Dockerfile uses a Debian Bookworm Node base and a non-root pptruser; it is not an Alpine image. Its documented sandboxed operation requires the container’s SYS_ADMIN capability. See the Puppeteer Docker guide and official Dockerfile.
Choose Alpine when its small base and package control fit your operations team. Choose the maintained image when avoiding Alpine package and browser compatibility maintenance is more important. Official documentation does not establish a universal image-size or performance winner.
Build an Alpine image
Minimal Dockerfile pattern
Use a pinned Node and Alpine tag, then adjust the executable path after inspecting the package in that release:
FROM node:<pinned-node-version>-alpine<release>
RUN apk add --no-cache
chromium
nss
freetype
harfbuzz
ca-certificates
ttf-freefont
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
USER node
CMD ["node", "app.js"]
Puppeteer’s Alpine example uses /usr/bin/chromium-browser. Depending on the Alpine branch, the package may expose both chromium and chromium-browser command names. Verify the actual path in the built image instead of copying it blindly:
docker run --rm your-image sh -c 'command -v chromium-browser || command -v chromium'
The package’s dependency set is release-specific. The example includes NSS, FreeType, HarfBuzz, CA certificates, and FreeFont; current packages may also pull fontconfig, GTK, graphics libraries, and other shared objects. Let apk resolve dependencies from the selected repository, and add application-specific fonts when your pages require them. Details are listed in the Puppeteer troubleshooting guide.
Install only the browser you intend to use
Standard Puppeteer installation downloads a recent Chrome for Testing and, since Puppeteer v21.6.0, a chrome-headless-shell binary. That download is not the Alpine package you installed. If Alpine Chromium is your intended browser, configure it explicitly and prevent an unnoticed browser change from entering production. puppeteer-core never downloads Chrome and requires the caller to provide browser configuration; it is useful when your image owns the browser installation. The distinction is documented in the Puppeteer installation guide.
Install and launch Puppeteer
Package installation
For an application that manages its own Chromium, install a tested Puppeteer version in your project. If you use puppeteer-core, supply the browser path yourself:
Rank #2
npm install puppeteer-core
If you use the full puppeteer package, still set executablePath so the application does not silently use a downloaded browser:
npm install puppeteer
Reliable launch and shutdown
This small program exercises the same user, executable, and runtime settings used by the container:
const puppeteer = require('puppeteer-core');
const executablePath = process.env.PUPPETEER_EXECUTABLE_PATH;
if (!executablePath) throw new Error('PUPPETEER_EXECUTABLE_PATH is not set');
(async () => {
const browser = await puppeteer.launch({
executablePath,
// See the sandbox section before retaining this flag in production.
args: ['--no-sandbox'],
headless: true
});
try {
const page = await browser.newPage();
await page.goto('https://example.com', {
waitUntil: 'networkidle2',
timeout: 30000
});
console.log(await page.title());
} finally {
await browser.close();
}
})();
The finally block matters in workers and test suites: it closes Chromium after navigation errors, assertion failures, and timeouts instead of leaving orphaned processes.
Sandboxing, users, and writable directories
Why --no-sandbox is a trade-off
Puppeteer’s Alpine example includes --no-sandbox, but its documentation also explains that Chrome’s sandbox protects the host from untrusted web content and that disabling it is appropriate only when the content is absolutely trusted. A screenshot service that opens arbitrary URLs should not treat this flag as routine. Prefer a deployment that supports Chrome’s sandbox, run as a non-root user, and grant only the runtime capabilities you have evaluated.
If your container environment cannot provide a working sandbox, isolate the container and understand that --no-sandbox weakens browser isolation. Do not claim that running as a non-root user alone restores the protections removed by that flag.
Run with the production user
Build and smoke-test as the same non-root user that runs the application. Chromium needs writable locations for its profile and cache. Set them to a directory owned by that user when your runtime has a read-only home:
ENV HOME=/tmp/puppeteer
RUN mkdir -p /tmp/puppeteer && chown -R node:node /tmp/puppeteer
USER node
Exact ownership and directory choices depend on your orchestrator. The important check is that the browser can create a profile, shared-memory files, and crash data under the production identity.
Sandboxed alternative
The maintained Puppeteer Docker image documents sandbox mode with SYS_ADMIN. That route uses Debian rather than Alpine, but it gives you a documented browser/dependency bundle and non-root configuration. Compare the security model and operational permissions before switching; do not add SYS_ADMIN merely to make an Alpine image work.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #3
Pin and verify the compatibility matrix
Record these values in your Docker build metadata:
- Node image tag, Alpine branch, and architecture.
- Exact Chromium package version returned by
apk. - Puppeteer or
puppeteer-coreversion. - Executable path and launch arguments.
- Font packages and any extra libraries your pages require.
Puppeteer’s troubleshooting page advises finding the newest Chromium package and using a corresponding Puppeteer-supported browser version. It includes an old illustrative Chromium 100/Puppeteer 13.5.0 pairing; that example is historical, not a current version recommendation. The same page reported timeout issues with Alpine 3.20’s Chromium at the time and said Alpine 3.19 fixed those reports. Treat that as a version-specific historical warning, not proof that current Alpine releases are broken.
After every base-image, Chromium, or Puppeteer update, rebuild and run the smoke test inside the final image. A successful local launch with a different user or browser binary does not validate production.
Smoke-test the built image
- Build the image:
docker build -t puppeteer-alpine .. - Confirm the executable:
docker run --rm puppeteer-alpine sh -c 'command -v chromium-browser || command -v chromium'. - Print the browser version:
docker run --rm puppeteer-alpine sh -c 'chromium-browser --version || chromium --version'. - Run the Node smoke test as the configured non-root user.
- Navigate to a deterministic page and verify a title, status, or screenshot.
- Repeat with the same memory, filesystem, network policy, and capabilities used by your deployment.
Include a page that loads a web font or image if those assets matter to your output. A test that checks only process startup can miss missing fonts, certificate failures, blocked DNS, or rendering-library problems.
Troubleshooting Alpine Puppeteer
Could not find Chrome or Puppeteer downloads an unexpected browser
Cause: the application is using Puppeteer’s managed browser rather than Alpine’s package.
Recommended Free Tools
Fix: set PUPPETEER_EXECUTABLE_PATH, pass executablePath, verify the path with command -v, and use puppeteer-core when you want no browser download.
Failed to launch the browser process
Cause: a missing shared library, incorrect executable path, incompatible browser/library pair, or permissions problem.
Fix: inspect the selected Alpine package’s dependencies, confirm the binary with --version, run as the production user, and rebuild from a clean image. Do not copy dependency lists from a different Alpine branch without checking its package index.
Timeouts during page.goto
Cause: slow or blocked network access, a page that never reaches the chosen lifecycle event, or a version-specific Chromium issue.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Fix: test DNS and outbound access from inside the container, choose an appropriate waitUntil condition, set an explicit timeout, and reproduce against the exact pinned image. Historical Alpine 3.20 timeout reports should not be generalized to every current release.
Blank pages, missing fonts, or broken graphics
Cause: absent font packages, certificates, graphics libraries, or a page whose assets are blocked by network policy.
Fix: install the fonts and libraries required by your pages, include CA certificates, inspect browser console and request failures, and test the rendered output rather than process startup alone.
Sandbox errors
Cause: the container runtime prevents Chrome’s sandbox from initializing, often because of user, namespace, or capability settings.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Fix: first configure a supported non-root sandbox deployment. If your workload is strictly trusted and you accept the isolation trade-off, use --no-sandbox with a separately isolated container; document that decision. For the maintained Puppeteer image’s documented sandbox path, review its SYS_ADMIN requirement.
Works as root, fails as node
Cause: the non-root user cannot write its home, cache, temporary profile, or shared-memory location.
Fix: create and own writable directories, set HOME if necessary, and run the smoke test as node before deployment.
Operational guidance
Performance
Reuse a browser process when your isolation model permits it, create and close pages per job, and cap concurrent pages according to available memory. Full-page captures and pages with lazy-loaded images consume more memory than a viewport screenshot. Measure your own workload; the cited documentation does not provide a universal Alpine-versus-Debian performance benchmark.
Free tools Windows power users keep installed
One-click scans. No signup required.
Best Value
- Docker, Docker Swarm, Docker Compose, Programmer, Developer, Coding, Programming, Software Engineer, Code, DevOps, Deploy, Deployment, Kubernetes, Salt, Puppet, Chef, Terraform, Container, AWS, Azure, Cloud, Geek, Funny, Computer, Software, Tech, IT
- Integration, Scrum, Compile, Compilation, Science, Bug, Debug, Python, Linux, Java, Javascript, Scala, Dotnet, Kotlin
- Lightweight, Classic fit, Double-needle sleeve and bottom hem
Reliability
Set navigation and job timeouts, close pages in finally blocks, recycle a browser after repeated crashes, and log the Alpine, Chromium, Puppeteer, architecture, and launch arguments with failures. Keep a deterministic smoke URL in CI so package updates fail before production traffic reaches them.
Architecture
Chromium availability and package versions differ by architecture. A Dockerfile validated on x86_64 is not automatically validated on arm64. Check the package index for the target architecture and build/test each image variant separately.
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server if maintaining Chromium in Alpine is not the work you want to own. One GET request returns PNG, JPEG, WebP, or PDF. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response identifies the result with X-Page-Verdict and X-Billed headers.
Use the ScreenshotNeo documentation for all options. A minimal call is:
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorscurl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Equivalent Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Equivalent Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. Features include full-page and selector captures, dark mode, device presets, retina scale, PDF controls, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, TTL caching, signed links, async webhooks, bulk capture of 100 URLs per call, usage data, and an OpenAPI specification. Its parameter names are compatible with those used by other screenshot APIs.
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is on every plan. Create a free ScreenshotNeo account to try it without adding a card.
Frequently Asked Questions
Can I use Puppeteer’s downloaded Chrome for Testing on Alpine?
Do not assume it will work. Puppeteer’s documentation says Chrome does not support Alpine out of the box; use a compatible Alpine Chromium package and explicit executable path, or choose the maintained Debian-based Puppeteer image.
Should I use puppeteer or puppeteer-core?
Use puppeteer-core when the image owns Chromium and you want no browser download. The full puppeteer package can also launch Alpine Chromium, but configure its executable path explicitly.
Is Alpine always smaller or faster for browser automation?
The official sources establish packaging and base-image differences, not a universal size or performance result. Benchmark your exact pages, architecture, and concurrency.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

