Running OpenClaw in Docker means you don’t have to install Node.js, manage dependencies, or worry about your AI assistant messing with your host system. The container runs, your config lives in mounted volumes, and updates are a rebuild away.
This guide walks through the full setup from scratch. I’m assuming you’ve got Docker installed and a terminal open.
Why run OpenClaw in Docker?
Three practical reasons:
- Isolation. OpenClaw and its dependencies stay inside the container. Nothing gets installed on your host beyond Docker itself.
- Portability. Move your setup between machines by copying your
~/.openclawfolder and running the same compose file. - Clean updates. Rebuild the image when a new version drops. Your config and memory persist in mounted volumes.
If you’re running OpenClaw on your daily-driver laptop and don’t care about isolation, the normal install (npm i -g openclaw) is simpler. Docker makes more sense for VPS deployments, shared servers, or if you just prefer containers.
Prerequisites
You need:
- Docker Engine or Docker Desktop (with Compose v2)
- Git (to clone the repo)
- An API key for your AI provider (OpenAI, Anthropic, etc.)
- A bot token if you’re connecting Telegram or Discord
Check Docker is working:
docker compose version
If that errors out, you need to install or update Docker. On Linux, make sure you have the docker-compose-plugin package, not the old standalone docker-compose.
Quick setup (the one-liner way)
OpenClaw ships a setup script that handles the build, onboarding wizard, and first start:
git clone https://github.com/openclaw/openclaw.git
cd openclaw
./docker-setup.sh
The script will:
- Build the Docker image locally
- Run the onboarding wizard (interactive — it asks about your AI provider, gateway token, etc.)
- Generate a gateway token and write it to
.env - Start the gateway via Docker Compose
After it finishes, open http://127.0.0.1:18789/ in your browser and paste in the gateway token to access the Control UI.
That’s genuinely it for most people. The rest of this guide covers what’s happening under the hood and how to customize things.
Manual setup (step by step)
If you’d rather understand each piece, here’s the manual flow.
1. Clone and build
git clone https://github.com/openclaw/openclaw.git
cd openclaw
docker build -t openclaw:local -f Dockerfile .
The image is based on node:22-bookworm. It installs Bun (used for build scripts), runs pnpm install, and builds the gateway. Expect it to take a few minutes on first build.
2. Create your config directories
mkdir -p ~/.openclaw
mkdir -p ~/.openclaw/workspace
These directories get mounted into the container. All your OpenClaw config, memory files, credentials, and workspace data lives here.
3. Run onboarding
docker compose run --rm openclaw-cli onboard --no-install-daemon
This runs the interactive setup wizard. It’ll ask you to:
- Pick your AI provider and enter an API key
- Set a gateway token (or let it generate one)
- Choose gateway bind settings
When it asks about gateway bind, pick lan — this is correct for container use. When it asks about installing a daemon, say no (Docker handles that).
4. Start the gateway
docker compose up -d openclaw-gateway
Done. The gateway is running in the background.
Check it’s healthy:
docker compose exec openclaw-gateway node dist/index.js health --token "YOUR_TOKEN"
The docker-compose.yml explained
Here’s what the official compose file looks like, with annotations:
services:
openclaw-gateway:
image: ${OPENCLAW_IMAGE:-openclaw:local}
environment:
HOME: /home/node
TERM: xterm-256color
OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN}
volumes:
- ${OPENCLAW_CONFIG_DIR:-~/.openclaw}:/home/node/.openclaw
- ${OPENCLAW_WORKSPACE_DIR:-~/.openclaw/workspace}:/home/node/.openclaw/workspace
ports:
- "${OPENCLAW_GATEWAY_PORT:-18789}:18789"
- "${OPENCLAW_BRIDGE_PORT:-18790}:18790"
init: true
restart: unless-stopped
command:
[
"node", "dist/index.js", "gateway",
"--bind", "${OPENCLAW_GATEWAY_BIND:-lan}",
"--port", "18789",
]
openclaw-cli:
image: ${OPENCLAW_IMAGE:-openclaw:local}
environment:
HOME: /home/node
TERM: xterm-256color
OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN}
BROWSER: echo
volumes:
- ${OPENCLAW_CONFIG_DIR:-~/.openclaw}:/home/node/.openclaw
- ${OPENCLAW_WORKSPACE_DIR:-~/.openclaw/workspace}:/home/node/.openclaw/workspace
stdin_open: true
tty: true
init: true
entrypoint: ["node", "dist/index.js"]
Two services: openclaw-gateway runs the always-on gateway, and openclaw-cli is a one-shot container for running CLI commands (onboarding, adding channels, etc.).
The .env file (generated by docker-setup.sh or created manually) feeds the variables:
OPENCLAW_CONFIG_DIR=/home/youruser/.openclaw
OPENCLAW_WORKSPACE_DIR=/home/youruser/.openclaw/workspace
OPENCLAW_GATEWAY_PORT=18789
OPENCLAW_BRIDGE_PORT=18790
OPENCLAW_GATEWAY_BIND=lan
OPENCLAW_GATEWAY_TOKEN=your_token_here
OPENCLAW_IMAGE=openclaw:local
Persistent storage
This is the part that trips people up. Your OpenClaw data lives in two places:
| Path in container | Host mount | What’s in it |
|---|---|---|
/home/node/.openclaw |
~/.openclaw |
Config, credentials, agent sessions, memory |
/home/node/.openclaw/workspace |
~/.openclaw/workspace |
Your workspace files (AGENTS.md, skills, projects) |
Both are bind-mounted from your host. As long as you don’t delete ~/.openclaw, your data survives container rebuilds, restarts, and upgrades.
Persisting the full home directory
If you want things like Playwright browser downloads or npm caches to persist, use a named volume for the entire /home/node:
export OPENCLAW_HOME_VOLUME="openclaw_home"
./docker-setup.sh
This creates a Docker volume called openclaw_home and mounts it at /home/node, while keeping the standard config/workspace bind mounts on top.
Connecting Telegram
With the gateway running in Docker:
docker compose run --rm openclaw-cli channels add --channel telegram --token "YOUR_BOT_TOKEN"
Then restart the gateway to pick up the new channel:
docker compose restart openclaw-gateway
Your Telegram bot should come online within a few seconds.
Connecting WhatsApp
WhatsApp needs a QR code scan, which makes it slightly more involved in Docker:
docker compose run --rm openclaw-cli channels login
This displays a QR code in your terminal. Scan it with WhatsApp on your phone (Settings → Linked Devices → Link a Device). The session gets saved to your mounted ~/.openclaw directory, so it persists across container restarts.
Connecting Discord
Same pattern as Telegram:
docker compose run --rm openclaw-cli channels add --channel discord --token "YOUR_BOT_TOKEN"
docker compose restart openclaw-gateway
Installing extra packages in the container
Need ffmpeg, git, or other system packages? Bake them into the image at build time:
export OPENCLAW_DOCKER_APT_PACKAGES="ffmpeg git curl jq"
./docker-setup.sh
This adds an apt-get install step to the Docker build. The packages persist in the image — no need to reinstall them after container restarts.
Adding extra host mounts
Want to give OpenClaw access to files outside ~/.openclaw? Use extra mounts:
export OPENCLAW_EXTRA_MOUNTS="$HOME/documents:/home/node/documents:ro,$HOME/projects:/home/node/projects:rw"
./docker-setup.sh
This generates a docker-compose.extra.yml that gets merged in. Note the :ro (read-only) and :rw (read-write) suffixes — use read-only unless you specifically need the container to write to those directories.
Common issues and fixes
“Permission denied” errors on mounted volumes
The container runs as user node (uid 1000). If your host directories are owned by a different user, you’ll get EACCES errors.
Fix on Linux:
sudo chown -R 1000:1000 ~/.openclaw
On macOS with Docker Desktop, this usually isn’t an issue because Docker handles the uid mapping.
“Unauthorized” or “disconnected (1008)” in the Control UI
Your gateway token doesn’t match. Fetch a fresh dashboard link:
docker compose run --rm openclaw-cli dashboard --no-open
If you see “pairing required,” approve the browser device:
docker compose run --rm openclaw-cli devices list
docker compose run --rm openclaw-cli devices approve <requestId>
Container keeps restarting
Check the logs:
docker compose logs -f openclaw-gateway
Common causes: missing API key in config, corrupted session files, or port 18789 already in use on the host.
WhatsApp QR code not showing
Make sure stdin_open: true and tty: true are set for the CLI service (they are in the default compose file). Run with --rm to avoid orphan containers:
docker compose run --rm openclaw-cli channels login
Updating OpenClaw
When a new version comes out:
cd openclaw
git pull
docker build -t openclaw:local -f Dockerfile .
docker compose down
docker compose up -d openclaw-gateway
Your config and workspace persist in the mounted volumes. The rebuild picks up the latest code.
Performance tips
Use Docker’s build cache. The Dockerfile is structured so dependency installation (pnpm install) is cached unless package.json or the lockfile changes. Don’t run docker build --no-cache unless you have a reason to.
Allocate enough memory. OpenClaw itself is fairly lightweight, but if you’re using browser automation (Playwright), the Chromium process can eat 500MB+. Give your Docker VM at least 4GB if you’re on Docker Desktop.
Use init: true. The compose file already includes this. It ensures zombie processes get reaped properly inside the container.
Consider the pre-built browser image. If you need browser automation, build with Chromium baked in rather than installing it at runtime:
docker build --build-arg OPENCLAW_INSTALL_BROWSER=1 -t openclaw:local -f Dockerfile .
This adds ~300MB to the image but skips the 60-90 second Playwright install on every container start.
Shell helpers (optional)
For day-to-day management, install the ClawDock helper scripts:
mkdir -p ~/.clawdock && curl -sL https://raw.githubusercontent.com/openclaw/openclaw/main/scripts/shell-helpers/clawdock-helpers.sh -o ~/.clawdock/clawdock-helpers.sh
echo 'source ~/.clawdock/clawdock-helpers.sh' >> ~/.zshrc && source ~/.zshrc
Then you get shortcuts like clawdock-start, clawdock-stop, clawdock-dashboard. Run clawdock-help to see all available commands.
What’s next
Once your Docker setup is running, you might want to:
- Set up the memory system so your assistant remembers conversations
- Pick the best free AI model for your use case
- Look into agent sandboxing if you want isolated tool execution without running the whole gateway in Docker