If your VPS came with ZeroClaw pre-installed, you already have a native binary running and Docker isn't required. But there are solid reasons to run ZeroClaw in a container anyway: isolation from the host system, reproducible deployments, easier rollbacks when updates go sideways. There's also the Docker sandboxed runtime that isolates tool execution inside containers so your AI agent can't accidentally rm -rf something important.
This tutorial covers both: running ZeroClaw itself in Docker, and configuring the Docker runtime sandbox for tool execution on an existing native install. Fair warning up front, the Docker documentation in the official repo has been acknowledged as incomplete, so consider this guide a supplement rather than a replacement for the upstream docs.
Prerequisites
You need Docker and Docker Compose installed on your server. If you're using a Docker VPS, these are already set up. Otherwise, install Docker with the official convenience script:
curl -fsSL https://get.docker.com | sh
systemctl enable docker
systemctl start docker
Verify the installation:
docker --version
docker compose version
Docker Compose setup
Create a directory for your ZeroClaw deployment and add a docker-compose.yml file:
mkdir -p /opt/zeroclaw && cd /opt/zeroclaw
# docker-compose.yml
version: "3.8"
services:
zeroclaw:
image: ghcr.io/zeroclaw-labs/zeroclaw:latest
container_name: zeroclaw
restart: unless-stopped
volumes:
- ./data:/root/.zeroclaw
ports:
- "127.0.0.1:42617:42617"
environment:
- ZEROCLAW_CONFIG_PATH=/root/.zeroclaw/config.toml
command: ["zeroclaw", "daemon"]
healthcheck:
test: ["CMD", "zeroclaw", "status", "--format=exit-code"]
interval: 30s
timeout: 10s
retries: 3
A few things to note in this compose file. The volume mount at ./data:/root/.zeroclaw is critical because it persists your config, memory database and channel bindings outside the container. Without it, every container restart wipes your assistant's memory and configuration. The port binding is scoped to 127.0.0.1 so the gateway isn't exposed to the public internet. And the healthcheck uses ZeroClaw's built-in status command with the exit-code format that was added in v0.5.0 specifically for container healthchecks.
Initial configuration
Before starting the container, create a minimal config file in the data directory:
mkdir -p /opt/zeroclaw/data
cat > /opt/zeroclaw/data/config.toml << 'EOF'
default_provider = "anthropic"
api_key = "sk-ant-your-key-here"
EOF
chmod 600 /opt/zeroclaw/data/config.toml
Start the container:
docker compose up -d
Check the logs to make sure it started cleanly:
docker compose logs -f zeroclaw
You should see the gateway starting on port 42617 and the daemon initializing. If there are config errors, they'll appear in these logs. Once the container is running, you can interact with ZeroClaw through docker exec:
docker exec -it zeroclaw zeroclaw agent -m "Hello from Docker"
docker exec -it zeroclaw zeroclaw channel list
docker exec -it zeroclaw zeroclaw doctor
Adding channels through Docker
Binding channels works the same as a native install, you just run the commands inside the container:
docker exec -it zeroclaw zeroclaw channel bind-telegram YOUR_BOT_TOKEN
The channel configuration is stored in the mounted volume, so it persists across container restarts. If you've been following our Telegram setup guide, all the same BotFather steps apply. The only difference is prefixing commands with docker exec -it zeroclaw.
Docker runtime sandbox for tool execution
This is separate from running ZeroClaw itself in Docker. ZeroClaw has a runtime.kind setting that controls how tools like shell commands, file operations and scripts get executed. By default it runs them natively on the host, which is fast but means your AI agent has the same filesystem access as the user running ZeroClaw.
Setting the runtime to Docker sandboxes all tool execution inside disposable containers:
[runtime]
kind = "docker"
With this enabled, when ZeroClaw's agent decides to run a shell command (say, to check disk usage or install a package), that command executes inside a temporary Docker container rather than directly on your host. The container gets destroyed after execution. This is a meaningful security improvement, especially if you're giving your AI agent broad tool access or running it in a shared environment.
The tradeoff is speed. Spawning a Docker container for each tool invocation adds a few hundred milliseconds of overhead compared to native execution. For interactive chat this is barely noticeable. For automated workflows with dozens of sequential tool calls, it adds up. If you're interested in security practices beyond the Docker sandbox, the security best practices guide covers additional hardening measures that apply to both OpenClaw and ZeroClaw deployments.
Updating ZeroClaw in Docker
Pull the latest image and recreate the container:
docker compose pull
docker compose up -d
Because your data lives in the mounted volume, the new container picks up your existing config and memory. Run the doctor command after updating to check for config compatibility:
docker exec -it zeroclaw zeroclaw doctor
If you want to pin a specific version instead of tracking latest, change the image tag in your compose file to a release version like ghcr.io/zeroclaw-labs/zeroclaw:v0.5.1. That gives you control over when updates happen, which is worth doing if you're running a production setup where surprise breakages aren't acceptable.
Persistent storage and backups
The ./data directory contains everything ZeroClaw needs to reconstruct its state: config.toml (your provider keys, channel bindings, tool settings), memory.db (the SQLite database with all conversation history and vector embeddings) and any skills or logs the agent has generated.
For backups, the simplest approach is a cron job that copies the data directory:
0 3 * * * tar czf /root/backups/zeroclaw-$(date +\%Y\%m\%d).tar.gz /opt/zeroclaw/data/
If you want to get more sophisticated with backup strategies, the production hardening guide covers automated backup pipelines and retention policies.

