Latest NewsAgentsAutomationToolsSecurity

How to set up OpenClaw on Docker (step-by-step guide)

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:

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:

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:

  1. Build the Docker image locally
  2. Run the onboarding wizard (interactive — it asks about your AI provider, gateway token, etc.)
  3. Generate a gateway token and write it to .env
  4. 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:

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: