Browse docs
Docs / install / docker
Docker
Docker (optional)
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’re 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.
- Containerized Gateway (full OpenClaw in Docker)
- Per-session Agent Sandbox (host gateway + Docker-isolated agent tools)
Requirements
- Docker Desktop (or Docker Engine) + Docker Compose v2
- Enough disk for images + logs
Containerized Gateway (Docker Compose)
Quick start (recommended)
text
./docker-setup.sh- builds the gateway image
- runs the onboarding wizard
- prints optional provider setup hints
- starts the gateway via Docker Compose
- generates a gateway token and writes it to
.env
OPENCLAW_DOCKER_APT_PACKAGES— install extra apt packages during buildOPENCLAW_EXTRA_MOUNTS— add extra host bind mountsOPENCLAW_HOME_VOLUME— persist/home/nodein a named volume
- Open
http://127.0.0.1:18789/in your browser. - Paste the token into the Control UI (Settings → token).
~/.openclaw/~/.openclaw/workspace
Manual flow (compose)
text
docker build -t openclaw:local -f Dockerfile .
docker compose run --rm openclaw-cli onboard
docker compose up -d openclaw-gatewayExtra mounts (optional)
text
export OPENCLAW_EXTRA_MOUNTS="$HOME/.codex:/home/node/.codex:ro,$HOME/github:/home/node/github:rw"
./docker-setup.sh- Paths must be shared with Docker Desktop on macOS/Windows.
- If you edit
OPENCLAW_EXTRA_MOUNTS, rerundocker-setup.shto regenerate the extra compose file. docker-compose.extra.ymlis generated. Don’t hand-edit it.
Persist the entire container home (optional)
text
export OPENCLAW_HOME_VOLUME="openclaw_home"
./docker-setup.shtext
export OPENCLAW_HOME_VOLUME="openclaw_home"
export OPENCLAW_EXTRA_MOUNTS="$HOME/.codex:/home/node/.codex:ro,$HOME/github:/home/node/github:rw"
./docker-setup.sh- If you change
OPENCLAW_HOME_VOLUME, rerundocker-setup.shto regenerate the extra compose file. - The named volume persists until removed with
docker volume rm <name>.
Install extra apt packages (optional)
text
export OPENCLAW_DOCKER_APT_PACKAGES="ffmpeg build-essential"
./docker-setup.sh- This accepts a space-separated list of apt package names.
- If you change
OPENCLAW_DOCKER_APT_PACKAGES, rerundocker-setup.shto rebuild the image.
Faster rebuilds (recommended)
text
FROM node:22-bookworm
# Install Bun (required for build scripts)
RUN curl -fsSL https://bun.sh/install | bash
ENV PATH="/root/.bun/bin:${PATH}"
RUN corepack enable
WORKDIR /app
# Cache dependencies unless package metadata changes
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"]Channel setup (optional)
text
docker compose run --rm openclaw-cli channels logintext
docker compose run --rm openclaw-cli channels add --channel telegram --token "<token>"text
docker compose run --rm openclaw-cli channels add --channel discord --token "<token>"Health check
text
docker compose exec openclaw-gateway node dist/index.js health --token "$OPENCLAW_GATEWAY_TOKEN"E2E smoke test (Docker)
text
scripts/e2e/onboard-docker.shQR import smoke test (Docker)
text
pnpm test:docker:qrNotes
- Gateway bind defaults to
lanfor container use. - The gateway container is the source of truth for sessions (
~/.openclaw/agents/<agentId>/sessions/).
Agent Sandbox (host gateway + Docker tools)
What it does
- scope:
"agent"by default (one container + workspace per agent) - scope:
"session"for per-session isolation - per-scope workspace folder mounted at
/workspace - optional agent workspace access (
agents.defaults.sandbox.workspaceAccess) - allow/deny tool policy (deny wins)
- inbound media is copied into the active sandbox workspace (
media/inbound/*) so tools can read it (withworkspaceAccess: "rw", this lands in the agent workspace)
Per-agent sandbox profiles (multi-agent)
- Full access (personal agent)
- Read-only tools + read-only workspace (family/work agent)
- No filesystem/shell tools (public agent)
Default behavior
- Image:
openclaw-sandbox:bookworm-slim - One container per agent
- Agent workspace access:
workspaceAccess: "none"(default) uses~/.openclaw/sandboxes"ro"keeps the sandbox workspace at/workspaceand mounts the agent workspace read-only at/agent(disableswrite/edit/apply_patch)"rw"mounts the agent workspace read/write at/workspace
"ro"keeps the sandbox workspace at/workspaceand mounts the agent workspace read-only at/agent(disableswrite/edit/apply_patch)"rw"mounts the agent workspace read/write at/workspace- Auto-prune: idle > 24h OR age > 7d
- Network:
noneby default (explicitly opt-in if you need egress) - Default allow:
exec,process,read,write,edit,sessions_list,sessions_history,sessions_send,sessions_spawn,session_status - Default deny:
browser,canvas,nodes,cron,discord,gateway
"ro"keeps the sandbox workspace at/workspaceand mounts the agent workspace read-only at/agent(disableswrite/edit/apply_patch)"rw"mounts the agent workspace read/write at/workspace
Enable sandboxing
- Default
docker.networkis"none"(no egress). readOnlyRoot: trueblocks package installs.usermust be root forapt-get(omituseror setuser: "0:0"). OpenClaw auto-recreates containers whensetupCommand(or docker config) changes unless the container was recently used (within ~5 minutes). Hot containers log a warning with the exactopenclaw sandbox recreate ...command.
text
{
agents: {
defaults: {
sandbox: {
mode: "non-main", // off | non-main | all
scope: "agent", // session | agent | shared (agent is default)
workspaceAccess: "none", // none | ro | rw
workspaceRoot: "~/.openclaw/sandboxes",
docker: {
image: "openclaw-sandbox:bookworm-slim",
workdir: "/workspace",
readOnlyRoot: true,
tmpfs: ["/tmp", "/var/tmp", "/run"],
network: "none",
user: "1000:1000",
capDrop: ["ALL"],
env: { LANG: "C.UTF-8" },
setupCommand: "apt-get update && apt-get install -y git curl jq",
pidsLimit: 256,
memory: "1g",
memorySwap: "2g",
cpus: 1,
ulimits: {
nofile: { soft: 1024, hard: 2048 },
nproc: 256,
},
seccompProfile: "/path/to/seccomp.json",
apparmorProfile: "openclaw-sandbox",
dns: ["1.1.1.1", "8.8.8.8"],
extraHosts: ["internal.service:10.0.0.5"],
},
prune: {
idleHours: 24, // 0 disables idle pruning
maxAgeDays: 7, // 0 disables max-age pruning
},
},
},
},
tools: {
sandbox: {
tools: {
allow: [
"exec",
"process",
"read",
"write",
"edit",
"sessions_list",
"sessions_history",
"sessions_send",
"sessions_spawn",
"session_status",
],
deny: ["browser", "canvas", "nodes", "cron", "discord", "gateway"],
},
},
},
}Build the default sandbox image
text
scripts/sandbox-setup.shSandbox common image (optional)
text
scripts/sandbox-common-setup.shtext
{
agents: {
defaults: {
sandbox: { docker: { image: "openclaw-sandbox-common:bookworm-slim" } },
},
},
}Sandbox browser image
text
scripts/sandbox-browser-setup.sh- Headful (Xvfb) reduces bot blocking vs headless.
- Headless can still be used by setting
agents.defaults.sandbox.browser.headless=true. - No full desktop environment (GNOME) is needed; Xvfb provides the display.
text
{
agents: {
defaults: {
sandbox: {
browser: { enabled: true },
},
},
},
}text
{
agents: {
defaults: {
sandbox: { browser: { image: "my-openclaw-browser" } },
},
},
}- a sandbox browser control URL (for the
browsertool) - a noVNC URL (if enabled and headless=false)
Custom sandbox image
text
docker build -t my-openclaw-sbx -f Dockerfile.sandbox .text
{
agents: {
defaults: {
sandbox: { docker: { image: "my-openclaw-sbx" } },
},
},
}Tool policy (allow/deny)
denywins overallow.- If
allowis empty: all tools (except deny) are available. - If
allowis non-empty: only tools inalloware available (minus deny).
Pruning strategy
prune.idleHours: remove containers not used in X hours (0 = disable)prune.maxAgeDays: remove containers older than X days (0 = disable)
- Keep busy sessions but cap lifetime:
idleHours: 24,maxAgeDays: 7 - Never prune:
idleHours: 0,maxAgeDays: 0
Security notes
- Hard wall only applies to tools (exec/read/write/edit/apply_patch).
- Host-only tools like browser/camera/canvas are blocked by default.
- Allowing
browserin sandbox breaks isolation (browser runs on host).
Troubleshooting
- Image missing: build with
scripts/sandbox-setup.shor setagents.defaults.sandbox.docker.image. - Container not running: it will auto-create per session on demand.
- Permission errors in sandbox: set
docker.userto a UID:GID that matches your mounted workspace ownership (or chown the workspace folder). - Custom tools not found: OpenClaw runs commands with
sh -lc(login shell), which sources/etc/profileand may reset PATH. Setdocker.env.PATHto prepend your custom tool paths (e.g.,/custom/bin:/usr/local/share/npm-global/bin), or add a script under/etc/profile.d/in your Dockerfile.