Setup guide13 minUpdated 2026-05-06

OpenClaw on Docker — the production-grade setup.

Docker is the cleanest way to run OpenClaw long-term. You get process isolation, easy updates, predictable storage, and a setup you can lift between machines without surprises. This is the stack we'd actually deploy in 2026 — and the gotchas we hit getting here.

Quick answers

  • How do I run OpenClaw in Docker?

    Drop the official docker-compose.yml in a directory, add your API key to .env, run docker compose up -d, then docker compose exec openclaw openclaw onboard. Five minutes from zero to running.
  • What's the recommended OpenClaw Docker setup?

    Pin a specific image tag (not latest), mount ./state:/root/.openclaw, set shm_size: 1gb for the browser, bind ports to 127.0.0.1 only, and set memory + CPU limits.
  • Does the browser work inside Docker?

    Yes. Headless Chrome runs in the container with shm_size: 1gb and cap_add: SYS_ADMIN. For multiple concurrent browser sessions, use a sidecar pattern with browserless/chrome.
  • How much RAM should I give the OpenClaw container?

    4 GB minimum, 8 GB if you want browser automation, 16 GB for multi-agent setups. Set hard limits in compose so a runaway agent can't OOM your host.
  • How do I update OpenClaw in Docker?

    docker compose pull then docker compose up -d. Pin versions in production. State survives because it's mounted in.

Architecture

Why Docker

Docker is the deployment most production OpenClaw setups settle on. You get isolation, easy updates, and portable state. Native installs are fine for laptops; Docker is fine everywhere else.

Native installDocker
Skill isolationhost filesystemcontainer only
Updatesmanualcompose pull
Portabilitymachine-specificany Docker host
Browser supporthost Chromeheadless inside
Multi-versioncomplextrivial

Before you start

Requirements

  • Docker 24+ with Compose v2. docker compose version should print 2.x or higher.
  • 4 GB RAM available to the container (8 GB if you want a browser).
  • 20 GB free disk for the image, state directory, and growing memory files.
  • An LLM API key. Stored in .env, never baked into the image.

Copy-paste

The docker-compose.yml

The minimum viable Compose file. Drop into a fresh directory, create a .env alongside it, and you're running.

docker-compose.ymlyaml
services:
  openclaw:
    image: openclaw/openclaw:latest
    container_name: openclaw
    restart: unless-stopped
    ports:
      - "127.0.0.1:18789:18789"
    volumes:
      - ./state:/root/.openclaw
      - /etc/localtime:/etc/localtime:ro
    environment:
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
      - OPENCLAW_TZ=America/Los_Angeles
    shm_size: "1gb"
    cap_add:
      - SYS_ADMIN
    deploy:
      resources:
        limits:
          memory: 4G
          cpus: "2"
    healthcheck:
      test: ["CMD", "openclaw", "gateway", "status"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 30s
.envbash
ANTHROPIC_API_KEY=sk-ant-api03-...

Boot it:

docker compose up -d
docker compose exec openclaw openclaw onboard

State

Volumes that matter

The single critical mount is ./state:/root/.openclaw. That folder contains every piece of state OpenClaw cares about: agent configs, memory, credentials, the SQLite memory index, channel session tokens. Lose it and you're starting over.

Path inside containerWhat's thereBackup priority
~/.openclaw/openclaw.jsonGateway configHigh
~/.openclaw/agents/Per-agent configs and workspacesCritical
~/.openclaw/memory/MEMORY.md, daily notes, SQLite indexCritical
~/.openclaw/credentials/Channel tokens (Telegram, Slack, WhatsApp QR)Critical
~/.openclaw/skills/Installed skillsMedium — reinstallable
~/.openclaw/cron/jobs.jsonScheduled jobsHigh

Backup pattern

tar -czf openclaw-state-$(date +%F).tar.gz state/ nightly via cron. The whole thing is a few hundred MB; storage is cheap.

Tricky bit

Browser inside Docker

OpenClaw's browser tool needs Chromium. Two choices: bundle it in your image (simple, larger image), or run it as a sidecar service (smaller main image, more moving parts).

docker-compose.yml (sidecar pattern)yaml
services:
  openclaw:
    image: openclaw/openclaw:latest
    environment:
      - OPENCLAW_BROWSER_CDP_URL=ws://browser:9222
    depends_on:
      - browser

  browser:
    image: browserless/chrome:latest
    restart: unless-stopped
    shm_size: "2gb"
    environment:
      - MAX_CONCURRENT_SESSIONS=4
      - CONNECTION_TIMEOUT=300000

shm_size matters

Without enough /dev/shm, Chrome crashes silently. Set 1 GB minimum, 2 GB for browser-heavy workloads.

Day 2 ops

Updates and rollback

Pin versions in production. The latest tag is fine for development; production wants deterministic upgrades.

# Update
docker compose pull openclaw
docker compose up -d openclaw
docker image prune -f

# Rollback (assuming you tagged the previous version)
docker compose stop openclaw
sed -i 's|:2026.5.1|:2026.5.0|' docker-compose.yml
docker compose up -d openclaw

Don't OOM your host

Resource limits

An OpenClaw agent that gets stuck in a tool-call loop can easily eat all available memory. Always set hard limits.

docker-compose.yml (limits)yaml
deploy:
  resources:
    limits:
      memory: 4G
      cpus: "2"
    reservations:
      memory: 1G

On Linux, also set kernel-level OOM scoring so Docker kills its own runaway containers before the host kernel kills something more important:

echo 1000 > /proc/$(docker inspect -f '{{.State.Pid}}' openclaw)/oom_score_adj

Visibility

Monitoring + logs

Docker logs are sufficient for development. For production, ship to your existing log stack:

docker-compose.yml (logging)yaml
logging:
  driver: "json-file"
  options:
    max-size: "10m"
    max-file: "5"

The most useful logs to watch:

  • incomplete turn detected: payloads=0 — model returned nothing. Almost always a wrong base URL or bad API key.
  • tool_result orphaned — session got into a bad state, often after compaction. Reset the session.
  • heartbeat skipped — the agent's regular check-in didn't fire. Usually rate-limiting from the LLM provider.

Before you ship

Production checklist

  • Pinned image version (no :latest in production)
  • State volume backed up nightly
  • Memory + CPU limits set
  • Healthcheck configured
  • Logs rotated or shipped
  • Bound to 127.0.0.1 only (or behind a real auth layer)
  • Sandbox mode set to all
  • Day-1 security checklist completed

FAQ

Why Docker over a native install?
Three reasons: process isolation (skills can't trash your host filesystem), portable state (move between machines by tarballing one folder), and predictable updates (`docker compose pull` is atomic). The ergonomics are also better — one config file, one command.
Does the browser work inside Docker?
Yes, with caveats. The container runs headless Chrome via the Chrome DevTools Protocol. You need `--cap-add=SYS_ADMIN` (or `--security-opt=seccomp=unconfined`) for some sandboxing features Chrome expects, plus enough shared memory — set `shm_size: 1gb` in your compose file.
How do I update OpenClaw in Docker?
`docker compose pull && docker compose up -d`. The state directory is mounted in, so memory and credentials survive. Pin a version tag in production (e.g., `openclaw/openclaw:2026.5.0`) so updates are deliberate.
Can I run multiple agents in one container?
Yes — OpenClaw supports multiple agents inside a single gateway, each with its own workspace, channel, and tools.allow. Define them in `~/.openclaw/openclaw.json` under `agents`. Sub-agent spawning still works.
What about running OpenClaw behind a reverse proxy?
Don't expose the gateway port. Bind to 127.0.0.1 inside the container, expose only via SSH tunneling, Tailscale, or a reverse proxy with strong auth. The gateway has no built-in authentication.
How much memory should I allocate?
4 GB minimum, 8 GB if you want browser automation, 16 GB for multi-agent setups. Set hard limits in compose so a runaway agent can't OOM your host.

Want OpenClaw without the ops?

Provision is the managed OpenClaw cloud — agents, channels, browser, and skills, all running. $99/mo. 48-hour free trial.