How to Install OpenClaw with Docker (Complete Guide 2026)
Docker is the recommended and most reliable way to run OpenClaw. It handles dependencies, isolation, and makes upgrades straightforward. This guide covers everything from a basic docker run to a production-ready docker-compose setup with health checks and persistent storage.
Why Docker for OpenClaw?
OpenClaw depends on a specific Node.js version and compiles a WebAssembly sandbox at startup. Docker ensures:
- Consistent environment across Linux, macOS, and Windows
- Easy upgrades by pulling a new image tag
- Resource limits (critical: OpenClaw needs 2048 MB RAM)
- Isolation from other services on the same host
Prerequisites
- Docker Engine 24+ installed (official install docs)
- Docker Compose v2 (included with modern Docker Desktop and Docker Engine)
- At least 2 GB free RAM allocated to Docker
- A Telegram bot token from @BotFather
- An Anthropic API key (or other supported LLM provider key)
Verify your Docker installation:
docker --version # Docker version 24.x.x or higher
docker compose version # Docker Compose version v2.x.x or higher
Quick Start: docker run
The fastest way to get OpenClaw running:
docker run -d --name openclaw --restart unless-stopped -p 8080:8080 -e ANTHROPIC_API_KEY=sk-ant-your-key -e NODE_OPTIONS=--max-old-space-size=1536 -m 2048m alpine/openclaw:latest node /app/openclaw.mjs gateway
Critical: Always set
-m 2048m. OpenClaw's WASM sandbox compilation peaks at ~1.3 GB RAM. Without this limit Docker may not reserve enough memory, and without enough available RAM the container will be OOM-killed (exit code 137).
Watch startup logs:
docker logs -f openclaw
The gateway takes about 5 minutes on first start (WASM compilation). Be patient.
Production Setup: docker-compose
For production, use docker-compose.yml for reproducible, declarative configuration.
Project structure
openclaw/
├── docker-compose.yml
├── .env
└── config/
└── openclaw.json
docker-compose.yml
version: "3.9"
services:
openclaw:
image: alpine/openclaw:latest
container_name: openclaw
restart: unless-stopped
command: node /app/openclaw.mjs gateway
ports:
- "8080:8080"
volumes:
- ./config:/home/node/.openclaw
- openclaw_data:/home/node/.openclaw/data
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- NODE_OPTIONS=--max-old-space-size=1536
- OPENCLAW_GATEWAY_TOKEN=${OPENCLAW_GATEWAY_TOKEN}
deploy:
resources:
limits:
memory: 2048M
reservations:
memory: 512M
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://127.0.0.1:18789/health', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))"]
interval: 30s
timeout: 10s
retries: 5
start_period: 360s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
volumes:
openclaw_data:
.env file
ANTHROPIC_API_KEY=sk-ant-your-key-here
OPENCLAW_GATEWAY_TOKEN=your-secret-token-here
Security tip: Never commit your
.envfile to git. Add it to.gitignore.
OpenClaw Configuration File
Create config/openclaw.json:
{
"gateway": {
"mode": "local",
"controlUi": {
"dangerouslyDisableDeviceAuth": true
}
},
"agents": {
"default": {
"model": "claude-3-5-sonnet-20241022"
}
},
"channels": {
"telegram": {
"enabled": true,
"botToken": "123456789:AABBcc-your-bot-token",
"dmPolicy": "open"
},
"whatsapp": {
"enabled": false,
"dmPolicy": "open",
"selfChatMode": true,
"accounts": {
"default": {
"dmPolicy": "open"
}
}
}
}
}
Important configuration rules:
gateway.modeMUST be"local"— other values cause exit=1- Do NOT include
agents.defaults.systemPromptortemperature— these are unrecognized keys that cause exit=1 - Do NOT include
channels.http— the HTTP channel does not exist in current builds - For WhatsApp, do NOT use
selfPhoneMode,dms, orgroups— useselfChatMode,dmPolicyinstead
Environment Variables Reference
| Variable | Required | Description |
|---|---|---|
| ANTHROPIC_API_KEY | Yes* | Anthropic API key for Claude models |
| NODE_OPTIONS | Yes | Set to --max-old-space-size=1536 |
| OPENCLAW_GATEWAY_TOKEN | Recommended | Pre-set auth token for Control UI |
| OPENAI_API_KEY | No | For GPT models (alternative to Anthropic) |
*One LLM API key is required.
Persistent Storage with Volumes
OpenClaw stores session data, channel auth, and cache in /home/node/.openclaw. Mount this as a volume to persist across container restarts and upgrades:
volumes:
- ./config:/home/node/.openclaw # Config files (bind mount)
- openclaw_data:/home/node/.openclaw/data # Runtime data (named volume)
Using a named volume for the data subdirectory ensures Docker manages the data lifecycle. Use bind mounts for config files so you can edit them directly on the host.
Health Checks
The start_period: 360s (6 minutes) in the health check config gives OpenClaw time to compile the WASM sandbox before health checks begin. Without this, Docker may restart the container prematurely thinking it's unhealthy.
Check container health status:
docker inspect openclaw --format='{{.State.Health.Status}}'
Multi-Container Setup with Redis
For high-traffic deployments, you can add Redis for session caching:
services:
openclaw:
# ... (same as above)
environment:
- REDIS_URL=redis://redis:6379
depends_on:
redis:
condition: service_healthy
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
volumes:
openclaw_data:
redis_data:
Resource Limits by Use Case
| Use Case | Memory Limit | CPU | |---|---|---| | Development / testing | 2048 MB | No limit | | Single-user production | 2048 MB | 1.0 CPU | | Multi-user production | 4096 MB | 2.0 CPUs | | High-traffic | 4096+ MB | 4.0 CPUs |
Updating OpenClaw
To upgrade to the latest version:
docker compose pull
docker compose up -d
Or with plain Docker:
docker pull alpine/openclaw:latest
docker stop openclaw && docker rm openclaw
# Re-run your docker run command
Platform Differences
Linux: Full Docker Engine support. Run exactly as shown. Best performance.
macOS (Docker Desktop): Works but Docker Desktop limits memory by default. Go to Settings → Resources → Memory and set to at least 4 GB.
Windows (Docker Desktop + WSL2): Works with WSL2 backend. Ensure WSL2 memory isn't capped in %USERPROFILE%\.wslconfig. Add:
[wsl2]
memory=4GB
Production Deployment Checklist
Before going live, verify:
- [ ]
-m 2048mormemory: 2048Mis set - [ ]
NODE_OPTIONS=--max-old-space-size=1536is set - [ ] Config JSON validated (
python3 -m json.tool openclaw.json) - [ ] No unrecognized config keys (causes silent exit=1)
- [ ]
gateway.mode: "local"is set - [ ] Bot token is in the config JSON (not just env var)
- [ ]
start_periodin healthcheck is at least 360 seconds - [ ] Named volume created for persistent data
- [ ]
.envfile excluded from git - [ ] Logs configured with rotation (
max-size: "10m") - [ ] Firewall only exposes necessary ports
Troubleshooting
Exit code 1 immediately after start: Config syntax error or unrecognized key. Check logs and validate JSON.
Exit code 137 (OOM): Not enough RAM. Increase -m limit or free up memory on host.
Port already in use: Change the host port (left side of -p): -p 9090:8080.
"Cannot connect to Docker daemon": Run sudo systemctl start docker or add your user to the docker group.
Prefer Zero-Maintenance?
Running OpenClaw in Docker works great but requires server maintenance, updates, and monitoring. ClawMates handles all of this automatically — deploy in one click for $29.99/month with no server management required.