{ "title": "Docker (optional)", "content": "Docker is **optional**. Use it only if you want a containerized gateway or to validate the Docker flow.\n\n## Is Docker right for me?\n\n* **Yes**: you want an isolated, throwaway gateway environment or to run OpenClaw on a host without local installs.\n* **No**: you’re running on your own machine and just want the fastest dev loop. Use the normal install flow instead.\n* **Sandboxing note**: agent sandboxing uses Docker too, but it does **not** require the full gateway to run in Docker. See [Sandboxing](/gateway/sandboxing).\n\n* Containerized Gateway (full OpenClaw in Docker)\n* Per-session Agent Sandbox (host gateway + Docker-isolated agent tools)\n\nSandboxing details: [Sandboxing](/gateway/sandboxing)\n\n* Docker Desktop (or Docker Engine) + Docker Compose v2\n* Enough disk for images + logs\n\n## Containerized Gateway (Docker Compose)\n\n### Quick start (recommended)\n\n* builds the gateway image\n* runs the onboarding wizard\n* prints optional provider setup hints\n* starts the gateway via Docker Compose\n* generates a gateway token and writes it to `.env`\n\n* `OPENCLAW_DOCKER_APT_PACKAGES` — install extra apt packages during build\n* `OPENCLAW_EXTRA_MOUNTS` — add extra host bind mounts\n* `OPENCLAW_HOME_VOLUME` — persist `/home/node` in a named volume\n\n* Open `http://127.0.0.1:18789/` in your browser.\n* Paste the token into the Control UI (Settings → token).\n* Need the tokenized URL again? Run `docker compose run --rm openclaw-cli dashboard --no-open`.\n\nIt writes config/workspace on the host:\n\n* `~/.openclaw/`\n* `~/.openclaw/workspace`\n\nRunning on a VPS? See [Hetzner (Docker VPS)](/platforms/hetzner).\n\n### Manual flow (compose)\n\nNote: run `docker compose ...` from the repo root. If you enabled\n`OPENCLAW_EXTRA_MOUNTS` or `OPENCLAW_HOME_VOLUME`, the setup script writes\n`docker-compose.extra.yml`; include it when running Compose elsewhere:\n\n### Control UI token + pairing (Docker)\n\nIf you see “unauthorized” or “disconnected (1008): pairing required”, fetch a\nfresh dashboard link and approve the browser device:\n\nMore detail: [Dashboard](/web/dashboard), [Devices](/cli/devices).\n\n### Extra mounts (optional)\n\nIf you want to mount additional host directories into the containers, set\n`OPENCLAW_EXTRA_MOUNTS` before running `docker-setup.sh`. This accepts a\ncomma-separated list of Docker bind mounts and applies them to both\n`openclaw-gateway` and `openclaw-cli` by generating `docker-compose.extra.yml`.\n\n* Paths must be shared with Docker Desktop on macOS/Windows.\n* If you edit `OPENCLAW_EXTRA_MOUNTS`, rerun `docker-setup.sh` to regenerate the\n extra compose file.\n* `docker-compose.extra.yml` is generated. Don’t hand-edit it.\n\n### Persist the entire container home (optional)\n\nIf you want `/home/node` to persist across container recreation, set a named\nvolume via `OPENCLAW_HOME_VOLUME`. This creates a Docker volume and mounts it at\n`/home/node`, while keeping the standard config/workspace bind mounts. Use a\nnamed volume here (not a bind path); for bind mounts, use\n`OPENCLAW_EXTRA_MOUNTS`.\n\nYou can combine this with extra mounts:\n\n* If you change `OPENCLAW_HOME_VOLUME`, rerun `docker-setup.sh` to regenerate the\n extra compose file.\n* The named volume persists until removed with `docker volume rm `.\n\n### Install extra apt packages (optional)\n\nIf you need system packages inside the image (for example, build tools or media\nlibraries), set `OPENCLAW_DOCKER_APT_PACKAGES` before running `docker-setup.sh`.\nThis installs the packages during the image build, so they persist even if the\ncontainer is deleted.\n\n* This accepts a space-separated list of apt package names.\n* If you change `OPENCLAW_DOCKER_APT_PACKAGES`, rerun `docker-setup.sh` to rebuild\n the image.\n\n### Power-user / full-featured container (opt-in)\n\nThe default Docker image is **security-first** and runs as the non-root `node`\nuser. This keeps the attack surface small, but it means:\n\n* no system package installs at runtime\n* no Homebrew by default\n* no bundled Chromium/Playwright browsers\n\nIf you want a more full-featured container, use these opt-in knobs:\n\n1. **Persist `/home/node`** so browser downloads and tool caches survive:\n\n2. **Bake system deps into the image** (repeatable + persistent):\n\n3. **Install Playwright browsers without `npx`** (avoids npm override conflicts):\n\nIf you need Playwright to install system deps, rebuild the image with\n`OPENCLAW_DOCKER_APT_PACKAGES` instead of using `--with-deps` at runtime.\n\n4. **Persist Playwright browser downloads**:\n\n* Set `PLAYWRIGHT_BROWSERS_PATH=/home/node/.cache/ms-playwright` in\n `docker-compose.yml`.\n* Ensure `/home/node` persists via `OPENCLAW_HOME_VOLUME`, or mount\n `/home/node/.cache/ms-playwright` via `OPENCLAW_EXTRA_MOUNTS`.\n\n### Permissions + EACCES\n\nThe image runs as `node` (uid 1000). If you see permission errors on\n`/home/node/.openclaw`, make sure your host bind mounts are owned by uid 1000.\n\nExample (Linux host):\n\nIf you choose to run as root for convenience, you accept the security tradeoff.\n\n### Faster rebuilds (recommended)\n\nTo speed up rebuilds, order your Dockerfile so dependency layers are cached.\nThis avoids re-running `pnpm install` unless lockfiles change:\n\n```dockerfile theme={null}\nFROM node:22-bookworm", "code_samples": [ { "code": "This script:\n\n* builds the gateway image\n* runs the onboarding wizard\n* prints optional provider setup hints\n* starts the gateway via Docker Compose\n* generates a gateway token and writes it to `.env`\n\nOptional env vars:\n\n* `OPENCLAW_DOCKER_APT_PACKAGES` — install extra apt packages during build\n* `OPENCLAW_EXTRA_MOUNTS` — add extra host bind mounts\n* `OPENCLAW_HOME_VOLUME` — persist `/home/node` in a named volume\n\nAfter it finishes:\n\n* Open `http://127.0.0.1:18789/` in your browser.\n* Paste the token into the Control UI (Settings → token).\n* Need the tokenized URL again? Run `docker compose run --rm openclaw-cli dashboard --no-open`.\n\nIt writes config/workspace on the host:\n\n* `~/.openclaw/`\n* `~/.openclaw/workspace`\n\nRunning on a VPS? See [Hetzner (Docker VPS)](/platforms/hetzner).\n\n### Manual flow (compose)", "language": "unknown" }, { "code": "Note: run `docker compose ...` from the repo root. If you enabled\n`OPENCLAW_EXTRA_MOUNTS` or `OPENCLAW_HOME_VOLUME`, the setup script writes\n`docker-compose.extra.yml`; include it when running Compose elsewhere:", "language": "unknown" }, { "code": "### Control UI token + pairing (Docker)\n\nIf you see “unauthorized” or “disconnected (1008): pairing required”, fetch a\nfresh dashboard link and approve the browser device:", "language": "unknown" }, { "code": "More detail: [Dashboard](/web/dashboard), [Devices](/cli/devices).\n\n### Extra mounts (optional)\n\nIf you want to mount additional host directories into the containers, set\n`OPENCLAW_EXTRA_MOUNTS` before running `docker-setup.sh`. This accepts a\ncomma-separated list of Docker bind mounts and applies them to both\n`openclaw-gateway` and `openclaw-cli` by generating `docker-compose.extra.yml`.\n\nExample:", "language": "unknown" }, { "code": "Notes:\n\n* Paths must be shared with Docker Desktop on macOS/Windows.\n* If you edit `OPENCLAW_EXTRA_MOUNTS`, rerun `docker-setup.sh` to regenerate the\n extra compose file.\n* `docker-compose.extra.yml` is generated. Don’t hand-edit it.\n\n### Persist the entire container home (optional)\n\nIf you want `/home/node` to persist across container recreation, set a named\nvolume via `OPENCLAW_HOME_VOLUME`. This creates a Docker volume and mounts it at\n`/home/node`, while keeping the standard config/workspace bind mounts. Use a\nnamed volume here (not a bind path); for bind mounts, use\n`OPENCLAW_EXTRA_MOUNTS`.\n\nExample:", "language": "unknown" }, { "code": "You can combine this with extra mounts:", "language": "unknown" }, { "code": "Notes:\n\n* If you change `OPENCLAW_HOME_VOLUME`, rerun `docker-setup.sh` to regenerate the\n extra compose file.\n* The named volume persists until removed with `docker volume rm `.\n\n### Install extra apt packages (optional)\n\nIf you need system packages inside the image (for example, build tools or media\nlibraries), set `OPENCLAW_DOCKER_APT_PACKAGES` before running `docker-setup.sh`.\nThis installs the packages during the image build, so they persist even if the\ncontainer is deleted.\n\nExample:", "language": "unknown" }, { "code": "Notes:\n\n* This accepts a space-separated list of apt package names.\n* If you change `OPENCLAW_DOCKER_APT_PACKAGES`, rerun `docker-setup.sh` to rebuild\n the image.\n\n### Power-user / full-featured container (opt-in)\n\nThe default Docker image is **security-first** and runs as the non-root `node`\nuser. This keeps the attack surface small, but it means:\n\n* no system package installs at runtime\n* no Homebrew by default\n* no bundled Chromium/Playwright browsers\n\nIf you want a more full-featured container, use these opt-in knobs:\n\n1. **Persist `/home/node`** so browser downloads and tool caches survive:", "language": "unknown" }, { "code": "2. **Bake system deps into the image** (repeatable + persistent):", "language": "unknown" }, { "code": "3. **Install Playwright browsers without `npx`** (avoids npm override conflicts):", "language": "unknown" }, { "code": "If you need Playwright to install system deps, rebuild the image with\n`OPENCLAW_DOCKER_APT_PACKAGES` instead of using `--with-deps` at runtime.\n\n4. **Persist Playwright browser downloads**:\n\n* Set `PLAYWRIGHT_BROWSERS_PATH=/home/node/.cache/ms-playwright` in\n `docker-compose.yml`.\n* Ensure `/home/node` persists via `OPENCLAW_HOME_VOLUME`, or mount\n `/home/node/.cache/ms-playwright` via `OPENCLAW_EXTRA_MOUNTS`.\n\n### Permissions + EACCES\n\nThe image runs as `node` (uid 1000). If you see permission errors on\n`/home/node/.openclaw`, make sure your host bind mounts are owned by uid 1000.\n\nExample (Linux host):", "language": "unknown" }, { "code": "If you choose to run as root for convenience, you accept the security tradeoff.\n\n### Faster rebuilds (recommended)\n\nTo speed up rebuilds, order your Dockerfile so dependency layers are cached.\nThis avoids re-running `pnpm install` unless lockfiles change:", "language": "unknown" } ], "headings": [ { "level": "h2", "text": "Is Docker right for me?", "id": "is-docker-right-for-me?" }, { "level": "h2", "text": "Requirements", "id": "requirements" }, { "level": "h2", "text": "Containerized Gateway (Docker Compose)", "id": "containerized-gateway-(docker-compose)" }, { "level": "h3", "text": "Quick start (recommended)", "id": "quick-start-(recommended)" }, { "level": "h3", "text": "Manual flow (compose)", "id": "manual-flow-(compose)" }, { "level": "h3", "text": "Control UI token + pairing (Docker)", "id": "control-ui-token-+-pairing-(docker)" }, { "level": "h3", "text": "Extra mounts (optional)", "id": "extra-mounts-(optional)" }, { "level": "h3", "text": "Persist the entire container home (optional)", "id": "persist-the-entire-container-home-(optional)" }, { "level": "h3", "text": "Install extra apt packages (optional)", "id": "install-extra-apt-packages-(optional)" }, { "level": "h3", "text": "Power-user / full-featured container (opt-in)", "id": "power-user-/-full-featured-container-(opt-in)" }, { "level": "h3", "text": "Permissions + EACCES", "id": "permissions-+-eacces" }, { "level": "h3", "text": "Faster rebuilds (recommended)", "id": "faster-rebuilds-(recommended)" } ], "url": "llms-txt#docker-(optional)", "links": [] }