Remote OpenClaw Blog
OpenClaw Docker Compose: Complete Configuration Guide
What changed
This post was reviewed and updated to reflect current deployment, security hardening, and operations guidance.
What should operators know about OpenClaw Docker Compose: Complete Configuration Guide?
Answer: Here is the simplest working docker-compose.yml for OpenClaw: This guide covers practical deployment decisions, security controls, and operations steps to run OpenClaw, ClawDBot, or MOLTBot reliably in production on your own VPS.
Complete guide to configuring OpenClaw with Docker Compose. Full docker-compose.yml structure, environment variables, volumes, ports, multi-service setup, updating, and common issues.
Marketplace
Free skills and AI personas for OpenClaw — deploy a pre-built agent in 15 minutes.
Browse the Marketplace →Join the Community
Join 500+ OpenClaw operators sharing deployment guides, security configs, and workflow automations.
What Is the Minimum docker-compose.yml?
Here is the simplest working docker-compose.yml for OpenClaw:
version: "3.8"
services:
openclaw:
image: openclaw/openclaw:latest
container_name: openclaw
restart: unless-stopped
ports:
- "18789:18789"
volumes:
- openclaw_data:/data
env_file:
- .env
volumes:
openclaw_data:
And the corresponding .env file:
ANTHROPIC_API_KEY=sk-ant-your-key-here
GATEWAY_TOKEN=your-secure-random-token
TELEGRAM_BOT_TOKEN=your-telegram-bot-token
This gives you a working OpenClaw instance with Claude as the AI model, Telegram as the messaging platform, persistent data storage, and the web UI accessible on port 18789.
Run it with:
docker compose up -d
That is genuinely all you need to get started. Everything below this section covers advanced configuration and optimization.
What Environment Variables Does OpenClaw Need?
OpenClaw has dozens of environment variables, but only a few are required. Here is a categorized reference:
Required:
# At least one model provider API key
ANTHROPIC_API_KEY=sk-ant-...
# OR
OPENAI_API_KEY=sk-...
# OR
GOOGLE_AI_API_KEY=...
Recommended:
GATEWAY_TOKEN=random-secure-string # API authentication
TELEGRAM_BOT_TOKEN=... # If using Telegram
MODEL_PRIMARY=claude-sonnet-4-20250514 # Default model
Gateway configuration:
GATEWAY_BIND=0.0.0.0:18789 # Listen address (default)
GATEWAY_MODE=standard # standard, api_only, or reverse_proxy
Security:
TELEGRAM_ALLOWED_USERS=123456789 # Comma-separated user IDs
AUTH_ENABLED=false # Web UI authentication
AUTH_PROVIDER=google # OAuth provider
Sandbox:
SANDBOX_BACKEND=docker # docker, ssh, or none
SANDBOX_DOCKER_IMAGE=openclaw/sandbox:latest
Browser:
BROWSER_ENABLED=true # Enable browser automation
BROWSER_HEADLESS=true # Run headless (default)
Always put sensitive values in a .env file, not directly in docker-compose.yml. The .env file should be in the same directory as docker-compose.yml and should be added to .gitignore if you version control your deployment configuration.
How Do Volumes Work?
The /data volume is critical. It stores everything that needs to persist between container restarts:
/data/config.json— Configuration file (if not using env vars exclusively)/data/sessions/— Conversation sessions and history/data/memory/— Agent memory (vector store and file-based)/data/skills/— Installed skills (SKILL.md files)/data/logs/— Application logs (if file logging is enabled)
Without a volume, all of this data is lost every time the container restarts. This is the single most common mistake new operators make — they deploy without a volume, everything works great, the container restarts, and all conversation history and configuration is gone.
You have two options for volumes:
Named volume (recommended for most users):
volumes:
- openclaw_data:/data
Docker manages the storage location. Data survives container updates and recreations. Easy to back up with docker volume inspect openclaw_data to find the path.
Bind mount (for advanced users):
volumes:
- ./openclaw-data:/data
Maps to a specific directory on the host. Easier to access files directly, manage backups, and troubleshoot. But you are responsible for permissions and directory creation.
What Ports Does OpenClaw Use?
OpenClaw uses a single port by default: 18789. This handles all HTTP traffic — web UI, REST API, and webhook callbacks.
ports:
- "18789:18789" # host_port:container_port
You can change the host port without changing OpenClaw's internal configuration:
ports:
- "8080:18789" # Access on port 8080, OpenClaw still listens on 18789 internally
If you are running behind a reverse proxy and do not need direct external access, you can remove the ports mapping entirely and use Docker's internal networking:
# No ports exposed — only accessible via Docker network
# Other services (like Nginx) can reach openclaw:18789 via the Docker network
If you are using the sandbox Docker backend, OpenClaw also needs access to the Docker socket:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
This lets OpenClaw create sandbox containers. The security implications of mounting the Docker socket are significant — it gives OpenClaw the ability to create, start, stop, and delete containers. Only do this if you understand the risks.
How Do You Run OpenClaw with Other Services?
A production deployment often includes companion services. Here is a complete multi-service docker-compose.yml:
version: "3.8"
services:
openclaw:
image: openclaw/openclaw:latest
container_name: openclaw
restart: unless-stopped
volumes:
- openclaw_data:/data
- /var/run/docker.sock:/var/run/docker.sock
env_file:
- .env
depends_on:
- ollama
networks:
- openclaw_net
caddy:
image: caddy:2-alpine
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
networks:
- openclaw_net
ollama:
image: ollama/ollama:latest
container_name: ollama
restart: unless-stopped
volumes:
- ollama_data:/root/.ollama
networks:
- openclaw_net
volumes:
openclaw_data:
caddy_data:
ollama_data:
networks:
openclaw_net:
This setup runs OpenClaw behind Caddy (a reverse proxy with automatic HTTPS), with Ollama available for local model inference. Caddy handles TLS certificates automatically, and all services communicate over a shared Docker network.
The corresponding Caddyfile:
your-domain.com {
reverse_proxy openclaw:18789
}
How Do You Update OpenClaw?
Updating OpenClaw with Docker Compose is straightforward:
# Pull the latest image
docker compose pull
# Restart with the new image
docker compose up -d
Your data persists in the volume — only the application code changes. The container is recreated with the new image, but the /data volume remains attached.
Before updating, always check the release notes for breaking changes. Major updates (like the 3.22 release) can rename environment variables, change config formats, or remove deprecated features.
To pin a specific version instead of using latest:
image: openclaw/openclaw:3.23.1
This prevents unexpected updates and gives you control over when you upgrade. Many operators pin to a specific version in production and test new versions in a staging environment first.
What Are the Most Common Docker Issues?
"Port 18789 is already in use" — Another process is using the port. Change the host port in docker-compose.yml (e.g., "8080:18789") or stop the conflicting process.
"Permission denied" on volume mount — The host directory has wrong ownership. Run sudo chown -R 1000:1000 ./openclaw-data (1000 is the default UID inside the container).
Container restarts in a loop — Check logs with docker compose logs openclaw. Common causes: invalid config, expired API key, or missing required environment variables.
"No space left on device" — Docker images, containers, and volumes consume disk space. Run docker system prune to clean up unused resources. Also check if conversation logs are filling the data volume.
Environment variables not updating — Docker Compose can cache the old environment. Run docker compose up -d --force-recreate instead of just docker compose restart to ensure the new .env values are loaded.
"Cannot connect to Docker daemon" — The Docker daemon is not running, or your user does not have permission. Run sudo systemctl start docker and add your user to the docker group with sudo usermod -aG docker $USER.
