Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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 chromium package 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).

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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-core version.
  • 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

  1. Build the image: docker build -t puppeteer-alpine ..
  2. Confirm the executable: docker run --rm puppeteer-alpine sh -c 'command -v chromium-browser || command -v chromium'.
  3. Print the browser version: docker run --rm puppeteer-alpine sh -c 'chromium-browser --version || chromium --version'.
  4. Run the Node smoke test as the configured non-root user.
  5. Navigate to a deterministic page and verify a title, status, or screenshot.
  6. 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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Fix: 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.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
Docker Container Linux Devops Programming Coding T-Shirt
  • 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:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

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.