Skip to content

Docker

Docker is optional. Use it only if you want a containerized gateway or to validate the Docker flow.

  • Yes: you want an isolated, throwaway gateway environment or to run OpenClaw on a host without local installs.
  • No: you are running on your own machine and just want the fastest dev loop. Use the normal install flow instead.
  • Sandboxing note: agent sandboxing uses Docker too, but it does not require the full gateway to run in Docker. See Sandboxing.
  • Docker Desktop (or Docker Engine) + Docker Compose v2
  • At least 2 GB RAM for image build (pnpm install may be OOM-killed on 1 GB hosts with exit 137)
  • Enough disk for images and logs
  • If running on a VPS/public host, review Security hardening for network exposure, especially Docker DOCKER-USER firewall policy.
  1. Build the image

    From the repo root, run the setup script:

    Terminal window
    ./scripts/docker/setup.sh

    This builds the gateway image locally. To use a pre-built image instead:

    Terminal window
    export OPENCLAW_IMAGE="ghcr.io/openclaw/openclaw:latest"
    ./scripts/docker/setup.sh

    Pre-built images are published at the GitHub Container Registry. Common tags: main, latest, `

    (e.g.2026.2.26`).

  2. Complete onboarding

    The setup script runs onboarding automatically. It will:

    • prompt for provider API keys
    • generate a gateway token and write it to .env
    • start the gateway via Docker Compose

    During setup, pre-start onboarding and config writes run through openclaw-gateway directly. openclaw-cli is for commands you run after the gateway container already exists.

  3. Open the Control UI

    Open http://127.0.0.1:18789/ in your browser and paste the token into Settings.

    Need the URL again?

    Terminal window
    docker compose run --rm openclaw-cli dashboard --no-open
  4. Configure channels (optional)

    Use the CLI container to add messaging channels:

    Terminal window
    # WhatsApp (QR)
    docker compose run --rm openclaw-cli channels login
    # Telegram
    docker compose run --rm openclaw-cli channels add --channel telegram --token "

    # Discord
    docker compose run --rm openclaw-cli channels add --channel discord --token "

    ” ```

    Docs: [WhatsApp](/en/channels/whatsapp), [Telegram](/en/channels/telegram), [Discord](/en/channels/discord)

If you prefer to run each step yourself instead of using the setup script:

Terminal window
docker build -t openclaw:local -f Dockerfile .
docker compose run --rm --no-deps --entrypoint node openclaw-gateway \
dist/index.js onboard --mode local --no-install-daemon
docker compose run --rm --no-deps --entrypoint node openclaw-gateway \
dist/index.js config set gateway.mode local
docker compose run --rm --no-deps --entrypoint node openclaw-gateway \
dist/index.js config set gateway.bind lan
docker compose run --rm --no-deps --entrypoint node openclaw-gateway \
dist/index.js config set gateway.controlUi.allowedOrigins \
'["http://localhost:18789","http://127.0.0.1:18789"]' --strict-json
docker compose up -d openclaw-gateway

The setup script accepts these optional environment variables:

VariablePurpose
OPENCLAW_IMAGEUse a remote image instead of building locally
OPENCLAW_DOCKER_APT_PACKAGESInstall extra apt packages during build (space-separated)
OPENCLAW_EXTENSIONSPre-install extension deps at build time (space-separated names)
OPENCLAW_EXTRA_MOUNTSExtra host bind mounts (comma-separated source:target[:opts])
OPENCLAW_HOME_VOLUMEPersist /home/node in a named Docker volume
OPENCLAW_SANDBOXOpt in to sandbox bootstrap (1, true, yes, on)
OPENCLAW_DOCKER_SOCKETOverride Docker socket path

Container probe endpoints (no auth required):

Terminal window
curl -fsS http://127.0.0.1:18789/healthz # liveness
curl -fsS http://127.0.0.1:18789/readyz # readiness

The Docker image includes a built-in HEALTHCHECK that pings /healthz. If checks keep failing, Docker marks the container as unhealthy and orchestration systems can restart or replace it.

Authenticated deep health snapshot:

Terminal window
docker compose exec openclaw-gateway node dist/index.js health --token "$OPENCLAW_GATEWAY_TOKEN"

scripts/docker/setup.sh defaults OPENCLAW_GATEWAY_BIND=lan so host access to http://127.0.0.1:18789 works with Docker port publishing.

  • lan (default): host browser and host CLI can reach the published gateway port.
  • loopback: only processes inside the container network namespace can reach the gateway directly.

Docker Compose bind-mounts OPENCLAW_CONFIG_DIR to /home/node/.openclaw and OPENCLAW_WORKSPACE_DIR to /home/node/.openclaw/workspace, so those paths survive container replacement.

For full persistence details on VM deployments, see Docker VM Runtime - What persists where.

Disk growth hotspots: watch media/, session JSONL files, cron/runs/*.jsonl, and rolling file logs under /tmp/openclaw/.

For easier day-to-day Docker management, install ClawDock:

Terminal window
mkdir -p ~/.clawdock && curl -sL https://raw.githubusercontent.com/openclaw/openclaw/main/scripts/clawdock/clawdock-helpers.sh -o ~/.clawdock/clawdock-helpers.sh
echo 'source ~/.clawdock/clawdock-helpers.sh' >> ~/.zshrc && source ~/.zshrc

If you installed ClawDock from the older scripts/shell-helpers/clawdock-helpers.sh raw path, rerun the install command above so your local helper file tracks the new location.

Then use clawdock-start, clawdock-stop, clawdock-dashboard, etc. Run clawdock-help for all commands. See ClawDock for the full helper guide.

Enable agent sandbox for Docker gateway
Terminal window
export OPENCLAW_SANDBOX=1
./scripts/docker/setup.sh

Custom socket path (e.g. rootless Docker):

Terminal window
export OPENCLAW_SANDBOX=1
export OPENCLAW_DOCKER_SOCKET=/run/user/1000/docker.sock
./scripts/docker/setup.sh

The script mounts docker.sock only after sandbox prerequisites pass. If sandbox setup cannot complete, the script resets agents.defaults.sandbox.mode to off.

Automation / CI (non-interactive)

Disable Compose pseudo-TTY allocation with -T:

Terminal window
docker compose run -T --rm openclaw-cli gateway probe
docker compose run -T --rm openclaw-cli devices list --json
Shared-network security note

openclaw-cli uses network_mode: "service:openclaw-gateway" so CLI commands can reach the gateway over 127.0.0.1. Treat this as a shared trust boundary. The compose config drops NET_RAW/NET_ADMIN and enables no-new-privileges on openclaw-cli.

Permissions and EACCES

The image runs as node (uid 1000). If you see permission errors on /home/node/.openclaw, make sure your host bind mounts are owned by uid 1000:

Terminal window
sudo chown -R 1000:1000 /path/to/openclaw-config /path/to/openclaw-workspace
Faster rebuilds

Order your Dockerfile so dependency layers are cached. This avoids re-running pnpm install unless lockfiles change:

FROM node:24-bookworm
RUN curl -fsSL https://bun.sh/install | bash
ENV PATH="/root/.bun/bin:${PATH}"
RUN corepack enable
WORKDIR /app
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
COPY ui/package.json ./ui/package.json
COPY scripts ./scripts
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
RUN pnpm ui:install
RUN pnpm ui:build
ENV NODE_ENV=production
CMD ["node","dist/index.js"]
Power-user container options

The default image is security-first and runs as non-root node. For a more full-featured container:

  1. Persist /home/node: export OPENCLAW_HOME_VOLUME="openclaw_home"
  2. Bake system deps: export OPENCLAW_DOCKER_APT_PACKAGES="git curl jq"
  3. Install Playwright browsers:
    Terminal window
    docker compose run --rm openclaw-cli \
    node /app/node_modules/playwright-core/cli.js install chromium
  4. Persist browser downloads: set PLAYWRIGHT_BROWSERS_PATH=/home/node/.cache/ms-playwright and use OPENCLAW_HOME_VOLUME or OPENCLAW_EXTRA_MOUNTS.
OpenAI Codex OAuth (headless Docker)

If you pick OpenAI Codex OAuth in the wizard, it opens a browser URL. In Docker or headless setups, copy the full redirect URL you land on and paste it back into the wizard to finish auth.

Base image metadata

The main Docker image uses node:24-bookworm and publishes OCI base-image annotations including org.opencontainers.image.base.name, org.opencontainers.image.source, and others. See OCI image annotations.

See Hetzner (Docker VPS) and Docker VM Runtime for shared VM deployment steps including binary baking, persistence, and updates.

When agents.defaults.sandbox is enabled, the gateway runs agent tool execution (shell, file read/write, etc.) inside isolated Docker containers while the gateway itself stays on the host. This gives you a hard wall around untrusted or multi-tenant agent sessions without containerizing the entire gateway.

Sandbox scope can be per-agent (default), per-session, or shared. Each scope gets its own workspace mounted at /workspace. You can also configure allow/deny tool policies, network isolation, resource limits, and browser containers.

For full configuration, images, security notes, and multi-agent profiles, see:

{
agents: {
defaults: {
sandbox: {
mode: "non-main", // off | non-main | all
scope: "agent", // session | agent | shared
},
},
},
}

Build the default sandbox image:

Terminal window
scripts/sandbox-setup.sh
Image missing or sandbox container not starting

Build the sandbox image with scripts/sandbox-setup.sh or set agents.defaults.sandbox.docker.image to your custom image. Containers are auto-created per session on demand.

Permission errors in sandbox

Set docker.user to a UID:GID that matches your mounted workspace ownership, or chown the workspace folder.

Custom tools not found in sandbox

OpenClaw runs commands with sh -lc (login shell), which sources /etc/profile and may reset PATH. Set docker.env.PATH to prepend your custom tool paths, or add a script under /etc/profile.d/ in your Dockerfile.

OOM-killed during image build (exit 137)

The VM needs at least 2 GB RAM. Use a larger machine class and retry.

Unauthorized or pairing required in Control UI

Fetch a fresh dashboard link and approve the browser device:

Terminal window
docker compose run --rm openclaw-cli dashboard --no-open
docker compose run --rm openclaw-cli devices list
docker compose run --rm openclaw-cli devices approve
More detail: [Dashboard](/en/web/dashboard), [Devices](/en/cli/devices).
Gateway target shows ws://172.x.x.x or pairing errors from Docker CLI

Reset gateway mode and bind:

Terminal window
docker compose run --rm openclaw-cli config set gateway.mode local
docker compose run --rm openclaw-cli config set gateway.bind lan
docker compose run --rm openclaw-cli devices list --url ws://127.0.0.1:18789