← Back to cheatsheet

🐳 Docker Setup

Run OpenClaw inside Docker containers for isolation, easy updates, and reproducible deployments. Covers the official image, docker-compose, persistent volumes, environment config, and production patterns.

Docker / Docker Compose~15 min setupVPS or local

πŸ€” Why Docker?

BenefitDetails
IsolationOpenClaw runs in its own container β€” doesn't touch your host Node.js, npm, or system libraries
ReproducibilitySame image, same behavior everywhere β€” local dev, staging, production VPS
Easy updatesdocker pull + restart β€” no npm conflicts, no dependency issues
SecurityContainer boundary limits blast radius if the agent is compromised
VPS-friendlyMost VPS providers (Hostinger, Hetzner, DigitalOcean) have Docker pre-installed or one-click templates
πŸ’‘ Docker vs native install: Use Docker when deploying to a VPS or when you want isolation. Use native install (Linux) when running on your personal machine where you want direct filesystem access and lowest latency.

πŸ“‹ Prerequisites

  • Docker Engine 24+ β€” check with docker --version
  • Docker Compose v2+ β€” check with docker compose version
  • 2 GB RAM minimum (4 GB recommended)
  • 10 GB disk space for images, volumes, and logs
  • AI API key β€” Anthropic, OpenAI, OpenRouter, or Google Gemini

Install Docker (if needed)

# Ubuntu / Debian
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Log out and back in for group change

# Verify
docker run hello-world

⚑ Quick start

Fastest way to get running β€” a single command using the official image:

docker run -d --name openclaw \
  --restart unless-stopped \
  -v openclaw-config:/home/node/.openclaw \
  -v openclaw-workspace:/home/node/.openclaw/workspace \
  -p 127.0.0.1:18789:18789 \
  -e HOME=/home/node \
  ghcr.io/openclaw/openclaw:latest \
  node dist/index.js gateway --port 18789

This starts the gateway on port 18789, bound to localhost only (secure by default). Config and workspace persist in named Docker volumes.

⚠️ Don't skip the 127.0.0.1: prefix. Without it, Docker binds to 0.0.0.0 β€” exposing the Control UI to the internet. See the Security Guide for why this matters.

πŸ“„ Docker Compose setup (recommended)

For production deployments, use a docker-compose.yml file for easier management:

# docker-compose.yml
services:
  openclaw:
    image: ghcr.io/openclaw/openclaw:latest
    container_name: openclaw
    restart: unless-stopped
    env_file: .env
    environment:
      - HOME=/home/node
      - NODE_ENV=production
      - TERM=xterm-256color
    volumes:
      - ./config:/home/node/.openclaw
      - ./workspace:/home/node/.openclaw/workspace
    ports:
      - "127.0.0.1:18789:18789"
    command: >
      node dist/index.js gateway
      --bind 0.0.0.0
      --port 18789
      --allow-unconfigured

Start it

# Start in background
docker compose up -d

# View logs
docker compose logs -f openclaw

# Stop
docker compose down

# Restart after config change
docker compose restart openclaw

πŸ” Environment variables

Create a .env file alongside your docker-compose.yml:

# .env
OPENCLAW_GATEWAY_PORT=18789
OPENCLAW_GATEWAY_BIND=0.0.0.0
OPENCLAW_GATEWAY_TOKEN=your-strong-random-token-here

# AI Provider (pick one)
ANTHROPIC_API_KEY=sk-ant-...
# OPENAI_API_KEY=sk-...
# OPENROUTER_API_KEY=sk-or-...
# GOOGLE_API_KEY=AIza...
🚨 Never commit .env to version control. Add it to .gitignore. Generate a strong gateway token: openssl rand -hex 32

Key variables

VariablePurposeDefault
OPENCLAW_GATEWAY_TOKENAuth token for Control UI accessGenerated on first run
OPENCLAW_GATEWAY_PORTGateway port18789
OPENCLAW_GATEWAY_BINDBind address inside container0.0.0.0 (use port mapping for security)
ANTHROPIC_API_KEYAnthropic Claude API keyβ€”
NODE_ENVproduction for VPS deploymentdevelopment

πŸ’Ύ Persistent volumes

Your agent's config, workspace files, credentials, and cron jobs all live on disk. Docker volumes ensure they survive container restarts and image updates.

Host pathContainer pathContents
./config/home/node/.openclawopenclaw.json, credentials, cron jobs, state
./workspace/home/node/.openclaw/workspaceSOUL.md, AGENTS.md, USER.md, MEMORY.md, daily logs
βœ… Backup strategy: Back up the ./config and ./workspace directories regularly. They contain everything needed to rebuild your agent from scratch. A simple rsync or tar cron job is enough.

πŸ§™ Onboarding inside Docker

Run the interactive setup wizard inside the container:

# Interactive onboarding
docker compose exec openclaw \
  node dist/index.js onboard --install-daemon

# Or non-interactive (for automation)
docker compose exec openclaw \
  node dist/index.js onboard --non-interactive \
  --auth-choice anthropic-api-key \
  --model "anthropic/claude-sonnet-4-5"

The wizard creates openclaw.json, sets up your AI provider, and optionally configures your first channel.

🌐 Accessing the Control UI

Local machine

If Docker runs on your local machine, open http://localhost:18789 and enter your gateway token.

Remote VPS

If Docker runs on a VPS, use an SSH tunnel β€” never expose port 18789 publicly:

# From your local machine
ssh -L 18789:localhost:18789 user@your-vps-ip

# Then open http://localhost:18789 in your browser

For persistent remote access, consider Tailscale β€” bind to your Tailscale IP instead of localhost.

πŸ”„ Updating OpenClaw

# Pull latest image
docker compose pull

# Recreate container with new image
docker compose up -d

# Verify version
docker compose exec openclaw node dist/index.js --version

Your config and workspace volumes are untouched during updates β€” only the application code changes. This is one of Docker's biggest advantages over native installs.

πŸ’‘ Pin to a specific version for production stability:
image: ghcr.io/openclaw/openclaw:2026.3.23
Then update deliberately by changing the tag, not with :latest.

πŸ”’ Tool sandboxing with Docker

OpenClaw supports running tool execution inside nested Docker containers β€” β€œDocker-in-Docker” style sandboxing. This means the gateway runs in one container and spawns child containers for untrusted tool calls.

# Enable in openclaw.json
{
  "agents": {
    "defaults": {
      "sandbox": {
        "mode": "non-main",
        "scope": "session",
        "workspaceAccess": "none"
      }
    }
  }
}

For this to work, mount the Docker socket into the OpenClaw container:

# Add to docker-compose.yml volumes
volumes:
  - ./config:/home/node/.openclaw
  - ./workspace:/home/node/.openclaw/workspace
  - /var/run/docker.sock:/var/run/docker.sock
⚠️ Docker socket = root access. Mounting the Docker socket gives the container the ability to spawn other containers. Only do this if you trust your OpenClaw configuration and have proper DM policies set up. See the Security Guide for details.

πŸ”§ Troubleshooting

ProblemFix
Container won't startdocker compose logs openclaw β€” check for missing env vars or port conflicts
Port already in uselsof -i :18789 on host β€” kill the conflicting process or change the port
Can't access Control UICheck port mapping includes 127.0.0.1: prefix. Use SSH tunnel for remote.
Config changes not applieddocker compose restart openclaw β€” gateway needs restart after config edits
WhatsApp QR not showingdocker compose exec -it openclaw node dist/index.js channels login
Permission denied on volumesCheck ownership: chown -R 1000:1000 ./config ./workspace (node user inside container)
Out of disk spacedocker system prune -af to clean old images/containers
Container keeps restartingdocker compose logs --tail 50 openclaw β€” usually a missing API key or bad config

Useful commands

# Shell into the container
docker compose exec -it openclaw bash

# Run doctor inside container
docker compose exec openclaw node dist/index.js doctor --deep --yes

# Check resource usage
docker stats openclaw

# View container details
docker inspect openclaw | grep -A5 "Mounts"