Docker
Run open-wa in Docker for Easy API or as a base image for your own project.

Docker
Use Docker when you want a repeatable runtime with browser dependencies handled for you.
Run the Easy API container
docker run openwa/wa-automatePass the same CLI flags you would normally use with npx @open-wa/wa-automate.
Image tags
Docker tags follow the package version you want to run. Pin a version when you need repeatable deploys, especially for production or rollback testing.
Use a v4 tag such as 4.76.0 for the current stable line. Use latest only when you are intentionally testing the v5 alpha image.
v4/v5 tags
# v4 stable
docker run openwa/wa-automate:4.76.0
# v5 alpha
docker run openwa/wa-automate:latestTypical production shape
- publish the API port explicitly
- persist any required session data or browser state
- add your API key and session id at container start
docker run -p 8080:8080 --init \
-v ./sessions:/sessions \
-e WA_PORT=8080 \
-e WA_SESSION_ID=sales \
-e WA_USER_DATA_DIR=/sessions/sales \
-e WA_API_KEY="your-secure-key" \
openwa/wa-automateVolume mounts
Mount a local directory when you want session data to survive container restarts, and point WA_USER_DATA_DIR at the mounted path for the session.
docker run -p 8080:8080 --init \
-v ./sessions:/sessions \
-e WA_SESSION_ID=sales \
-e WA_USER_DATA_DIR=/sessions/sales \
openwa/wa-automateThe v5 image runs from /usr/src/app. If WA_USER_DATA_DIR is not set and the session is not ephemeral, the runtime derives the browser profile path as /usr/src/app/_IGNORE_<sessionId> by default. Mounting /sessions alone does not move the profile there; set WA_USER_DATA_DIR=/sessions/<sessionId> or mount the derived /usr/src/app/_IGNORE_<sessionId> path directly.
Keep the mounted directory private because it can contain authentication state for the WhatsApp session.
Env vars
Pass runtime configuration with environment variables when that fits your deploy platform better than CLI flags.
docker run -p 8080:8080 \
-e WA_PORT=8080 \
-e WA_API_KEY="your-secure-key" \
-e WA_SESSION_ID=sales \
-e WA_USER_DATA_DIR=/sessions/sales \
-v ./sessions:/sessions \
openwa/wa-automateFor v5 runtime config, use WA_* names such as WA_PORT, WA_API_KEY, WA_SESSION_ID, and WA_USER_DATA_DIR. Bare PORT, API_KEY, and SESSION_ID are not documented as v5 config env vars here.
You can also keep environment values in a file and load them at container start.
docker run -p 8080:8080 --env-file .env openwa/wa-automate--init
Add --init when running the container directly with Docker. The browser can create child processes, and an init process helps clean up zombies when those child processes exit.
docker run -p 8080:8080 --init openwa/wa-automateBrowser resources
The container still runs a browser. Give it enough memory and CPU for WhatsApp Web, especially if you run multiple sessions or process heavy message volume.
If the browser exits unexpectedly, check memory limits, shared memory settings, CPU throttling, and the host architecture before changing application code.
Health checks
Add a health check that calls the Easy API over the published port.
docker run -p 8080:8080 --init \
-e WA_PORT=8080 \
--health-cmd="curl -f http://localhost:8080/api-docs/ || exit 1" \
--health-interval=30s \
--health-timeout=10s \
--health-retries=3 \
openwa/wa-automateUse the same path your deployment actually depends on. If you protect the API with a key, make sure the health check can still reach a suitable unauthenticated endpoint or send the required header.
Docker Compose
Compose is useful when you want the port, volume, environment, and health check committed next to your app config.
services:
openwa:
image: openwa/wa-automate:latest
init: true
ports:
- "8080:8080"
volumes:
- ./sessions:/sessions
environment:
WA_PORT: "8080"
WA_SESSION_ID: sales
WA_USER_DATA_DIR: /sessions/sales
WA_API_KEY: ${WA_API_KEY}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/api-docs/"]
interval: 30s
timeout: 10s
retries: 3Start it with:
WA_API_KEY="your-secure-key" docker compose upRestart verification checklist
Use this local checklist after the first successful authentication. The expected output is illustrative local verification guidance, not captured output from this docs update.
- Start the container with a named session and explicit profile directory:
docker run --name openwa-sales -p 8080:8080 --init \
-v ./sessions:/sessions \
-e WA_PORT=8080 \
-e WA_SESSION_ID=sales \
-e WA_USER_DATA_DIR=/sessions/sales \
-e WA_API_KEY="your-secure-key" \
openwa/wa-automate- Complete the first authentication flow by scanning the QR code or using link-code login.
- Stop and remove only the container, not
./sessions:
docker stop openwa-sales
docker rm openwa-sales- Start the same command again with the same
WA_SESSION_IDandWA_USER_DATA_DIR. - Expected local result: the runtime reuses the profile under
./sessions/salesand reaches the connected session without asking for a new QR code.
Restart proof output, illustrative and abbreviated:
session sales restoring profile from /sessions/sales
session sales connected
api listening on http://localhost:8080The proof is the absence of a fresh QR prompt after restart, plus a connected session using the same mounted profile path. If a QR code appears again, treat persistence as broken. Confirm the volume is mounted at /sessions, WA_USER_DATA_DIR still points to /sessions/sales, and the ./sessions directory was not deleted between runs. Next, add the same mount and env vars to Compose or your deploy platform before moving this session to production.
Secrets
Do not bake API keys, license keys, or session material into your image. Inject secrets at runtime with environment variables, an .env file outside version control, or Docker secrets when your platform supports them.
For Docker secrets, mount the secret file and have your startup script read it before launching the API.
services:
openwa:
image: openwa/wa-automate:4.76.0
secrets:
- openwa_api_key
secrets:
openwa_api_key:
file: ./secrets/openwa_api_key.txtProduction shape
A production Docker deployment usually pins the image tag, publishes only the API port you need, mounts session storage, injects secrets at runtime, runs with --init, allocates enough browser resources, and defines a health check.
Keep the WhatsApp runtime small and focused. Put business logic in your own service, then call Easy API or consume events from it.
Use the image as a base for your own code
If you want the browser/runtime dependencies but not the default entrypoint, override it:
FROM openwa/wa-automate
ENTRYPOINT []
# copy your project and run your own command afterwardsThat lets you build your own app on top of the tested runtime image.
Notes
- Revalidate browser and architecture assumptions against the image you are actually deploying.
- Keep secrets out of the image and inject them at runtime.
- If your goal is remote access rather than containerization, look at Cloudflare Session Proxy.

Was this helpful?
Wally and his cute companion coffee mug are coding day and night to keep this up-to-date!
