--- summary: "Optional Docker-based setup and onboarding for OpenClaw" read_when: - You want a containerized gateway instead of local installs - You are validating the Docker flow title: "Docker" --- # Docker (optional) Docker is **optional**. Use it only if you want a containerized gateway or to validate the Docker flow. ## Is Docker right for me? - **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](/gateway/sandboxing). ## Prerequisites - 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](/gateway/security#0-4-network-exposure-bind-port-firewall), especially Docker `DOCKER-USER` firewall policy. ## Containerized Gateway From the repo root, run the setup script: ```bash ./scripts/docker/setup.sh ``` This builds the gateway image locally. To use a pre-built image instead: ```bash export OPENCLAW_IMAGE="ghcr.io/openclaw/openclaw:latest" ./scripts/docker/setup.sh ``` Pre-built images are published at the [GitHub Container Registry](https://github.com/openclaw/openclaw/pkgs/container/openclaw). Common tags: `main`, `latest`, `` (e.g. `2026.2.26`). 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 Open `http://127.0.0.1:18789/` in your browser and paste the token into Settings. Need the URL again? ```bash docker compose run --rm openclaw-cli dashboard --no-open ``` Use the CLI container to add messaging channels: ```bash # 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](/channels/whatsapp), [Telegram](/channels/telegram), [Discord](/channels/discord) ### Manual flow If you prefer to run each step yourself instead of using the setup script: ```bash docker build -t openclaw:local -f Dockerfile . docker compose run --rm openclaw-cli onboard docker compose up -d openclaw-gateway ``` Run `docker compose` from the repo root. If you enabled `OPENCLAW_EXTRA_MOUNTS` or `OPENCLAW_HOME_VOLUME`, the setup script writes `docker-compose.extra.yml`; include it with `-f docker-compose.yml -f docker-compose.extra.yml`. ### Environment variables The setup script accepts these optional environment variables: | Variable | Purpose | | ------------------------------ | ---------------------------------------------------------------- | | `OPENCLAW_IMAGE` | Use a remote image instead of building locally | | `OPENCLAW_DOCKER_APT_PACKAGES` | Install extra apt packages during build (space-separated) | | `OPENCLAW_EXTENSIONS` | Pre-install extension deps at build time (space-separated names) | | `OPENCLAW_EXTRA_MOUNTS` | Extra host bind mounts (comma-separated `source:target[:opts]`) | | `OPENCLAW_HOME_VOLUME` | Persist `/home/node` in a named Docker volume | | `OPENCLAW_SANDBOX` | Opt in to sandbox bootstrap (`1`, `true`, `yes`, `on`) | | `OPENCLAW_DOCKER_SOCKET` | Override Docker socket path | ### Health checks Container probe endpoints (no auth required): ```bash 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: ```bash docker compose exec openclaw-gateway node dist/index.js health --token "$OPENCLAW_GATEWAY_TOKEN" ``` ### LAN vs loopback `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. Use bind mode values in `gateway.bind` (`lan` / `loopback` / `custom` / `tailnet` / `auto`), not host aliases like `0.0.0.0` or `127.0.0.1`. ### Storage and persistence 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](/install/docker-vm-runtime#what-persists-where). **Disk growth hotspots:** watch `media/`, session JSONL files, `cron/runs/*.jsonl`, and rolling file logs under `/tmp/openclaw/`. ### Shell helpers (optional) For easier day-to-day Docker management, install `ClawDock`: ```bash 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 use `clawdock-start`, `clawdock-stop`, `clawdock-dashboard`, etc. Run `clawdock-help` for all commands. See the [`ClawDock` Helper README](https://github.com/openclaw/openclaw/blob/main/scripts/shell-helpers/README.md). ```bash export OPENCLAW_SANDBOX=1 ./scripts/docker/setup.sh ``` Custom socket path (e.g. rootless Docker): ```bash 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`. Disable Compose pseudo-TTY allocation with `-T`: ```bash docker compose run -T --rm openclaw-cli gateway probe docker compose run -T --rm openclaw-cli devices list --json ``` `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`. 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: ```bash sudo chown -R 1000:1000 /path/to/openclaw-config /path/to/openclaw-workspace ``` Order your Dockerfile so dependency layers are cached. This avoids re-running `pnpm install` unless lockfiles change: ```dockerfile 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"] ``` 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**: ```bash 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`. 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. 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](https://github.com/opencontainers/image-spec/blob/main/annotations.md). ### Running on a VPS? See [Hetzner (Docker VPS)](/install/hetzner) and [Docker VM Runtime](/install/docker-vm-runtime) for shared VM deployment steps including binary baking, persistence, and updates. ## Agent Sandbox 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: - [Sandboxing](/gateway/sandboxing) -- complete sandbox reference - [OpenShell](/gateway/openshell) -- interactive shell access to sandbox containers - [Multi-Agent Sandbox and Tools](/tools/multi-agent-sandbox-tools) -- per-agent overrides ### Quick enable ```json5 { agents: { defaults: { sandbox: { mode: "non-main", // off | non-main | all scope: "agent", // session | agent | shared }, }, }, } ``` Build the default sandbox image: ```bash scripts/sandbox-setup.sh ``` ## Troubleshooting Build the sandbox image with [`scripts/sandbox-setup.sh`](https://github.com/openclaw/openclaw/blob/main/scripts/sandbox-setup.sh) or set `agents.defaults.sandbox.docker.image` to your custom image. Containers are auto-created per session on demand. Set `docker.user` to a UID:GID that matches your mounted workspace ownership, or chown the workspace folder. 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. The VM needs at least 2 GB RAM. Use a larger machine class and retry. Fetch a fresh dashboard link and approve the browser device: ```bash 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](/web/dashboard), [Devices](/cli/devices). Reset gateway mode and bind: ```bash 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 ```