Stack Junkie
Docker OpenClaw Done Right: Compose Template, Persistent Volumes, and Pairing
Published on
· 12 min read

Docker OpenClaw Done Right: Compose Template, Persistent Volumes, and Pairing

By
Authors
  • Name
    Twitter

Docker OpenClaw Done Right: Compose Template, Persistent Volumes, and Pairing

Run OpenClaw in Docker to isolate it from your host system. This guide provides a tested docker-compose.yml with persistent volumes, correct permissions, and the exact pairing workflow for Telegram from inside a container. You'll have a paired, running bot in about ten minutes.

Here's what this covers:

  • A copy-paste docker-compose.yml with security defaults
  • Volume mounts that keep your config and workspace across rebuilds
  • The full pairing workflow from inside a container
  • Updating, backing up, and restoring your Docker setup
  • How Docker isolation compares to bare-metal installs

Why Run OpenClaw in Docker?

Three reasons, each one sentence.

Isolation. Docker limits what OpenClaw can touch on your host filesystem. The container only sees the directories you explicitly mount.

Reproducibility. If something breaks, docker compose down && docker compose up -d rebuilds the environment in seconds. Your config and workspace survive because they live in mounted volumes.

Backup simplicity. Stop the container, tar the volumes, and you have a complete snapshot. Restoring means extracting that tar and running docker compose up. No hunting for scattered config files.

Simon Willison put it well: he wasn't "brave enough" to run OpenClaw directly on his Mac. Docker gives you that same peace of mind on any machine. OpenClaw (formerly known as Clawdbot, then briefly Moltbot) gets full access to whatever you mount into the container, and nothing else.

What You Need Before Starting

  • Docker Engine + Docker Compose v2. Any recent Docker Desktop or Docker Engine install works. Verify with docker compose version.
  • At least 2 GB of RAM. The image build runs pnpm install, which gets OOM-killed on 1 GB hosts (exit code 137).
  • A Telegram bot token (or token for your preferred channel). Create one through @BotFather on Telegram if you don't have one yet.
  • A model provider API key. Anthropic, OpenAI, or another supported provider. You can also use ChatGPT OAuth to cap your spending to your existing subscription.

You do not need Node.js on the host. That's the whole point.

The docker-compose.yml

The official OpenClaw docker-compose.yml defines two services: openclaw-gateway (the always-running agent) and openclaw-cli (for one-off management commands). The version below is based on that official file with three security additions: localhost-only port binding, resource limits, and explicit no-new-privileges.

Create a project directory and add these two files:

Replace these placeholder values before running:

  • your-secure-gateway-token-here with a strong random string (use openssl rand -hex 32)
  • Paths in OPENCLAW_CONFIG_DIR and OPENCLAW_WORKSPACE_DIR with your actual directories
# .env
OPENCLAW_IMAGE=openclaw:local
OPENCLAW_GATEWAY_TOKEN=your-secure-gateway-token-here
OPENCLAW_CONFIG_DIR=~/.openclaw
OPENCLAW_WORKSPACE_DIR=~/.openclaw/workspace
OPENCLAW_GATEWAY_PORT=18789
OPENCLAW_BRIDGE_PORT=18790
OPENCLAW_GATEWAY_BIND=lan
# docker-compose.yml
services:
  openclaw-gateway:
    image: ${OPENCLAW_IMAGE:-openclaw:local}
    environment:
      HOME: /home/node
      TERM: xterm-256color
      OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN}
    volumes:
      - ${OPENCLAW_CONFIG_DIR:-~/.openclaw}:/home/node/.openclaw
      - ${OPENCLAW_WORKSPACE_DIR:-~/.openclaw/workspace}:/home/node/.openclaw/workspace
    ports:
      - '127.0.0.1:${OPENCLAW_GATEWAY_PORT:-18789}:18789'
      - '127.0.0.1:${OPENCLAW_BRIDGE_PORT:-18790}:18790'
    init: true
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    deploy:
      resources:
        limits:
          memory: 4G
          cpus: '2.0'
        reservations:
          memory: 1G
    command:
      [
        'node',
        'dist/index.js',
        'gateway',
        '--bind',
        '${OPENCLAW_GATEWAY_BIND:-lan}',
        '--port',
        '18789',
      ]

  openclaw-cli:
    image: ${OPENCLAW_IMAGE:-openclaw:local}
    environment:
      HOME: /home/node
      TERM: xterm-256color
      OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN}
      BROWSER: echo
    volumes:
      - ${OPENCLAW_CONFIG_DIR:-~/.openclaw}:/home/node/.openclaw
      - ${OPENCLAW_WORKSPACE_DIR:-~/.openclaw/workspace}:/home/node/.openclaw/workspace
    stdin_open: true
    tty: true
    init: true
    security_opt:
      - no-new-privileges:true
    entrypoint: ['node', 'dist/index.js']

What each volume does

MountContainer pathPurpose
OPENCLAW_CONFIG_DIR/home/node/.openclawAgent config, sessions, channel tokens, memory
OPENCLAW_WORKSPACE_DIR/home/node/.openclaw/workspaceFiles the agent creates and reads

Both are bind mounts to your host filesystem. Everything the agent produces goes here, so nothing is lost when you recreate the container.

What the security additions do

  • 127.0.0.1: port prefix binds ports to localhost only on the host side. Without it, Docker publishes ports on all interfaces, bypassing your firewall. This is the single most common Docker security mistake. Note: OPENCLAW_GATEWAY_BIND=lan in the .env is a separate setting. It tells the gateway process inside the container to listen on the container's network interfaces so Docker's port forwarding can reach it. The host-side restriction comes from 127.0.0.1: in the ports mapping.
  • no-new-privileges prevents processes inside the container from gaining extra privileges through setuid binaries or other mechanisms.
  • Resource limits cap memory at 4 GB and CPU at 2 cores. Adjust these to your hardware. The memory reservation of 1 GB tells Docker the minimum the container needs.

First Run and Pairing

Step 1: Build the image

Clone the OpenClaw repo and build:

git clone https://github.com/openclaw/openclaw.git
cd openclaw
docker build -t openclaw:local -f Dockerfile .

This takes a few minutes. If you prefer, the docker-setup.sh script handles the build, onboarding wizard, and startup in one command.

Step 2: Run the onboarding wizard

docker compose run --rm openclaw-cli onboard

The wizard asks for your model provider, API keys, and gateway token. Simon Willison recommends setting "Onboarding mode" to manual and "What do you want to set up?" to "Local gateway (this machine)."

Step 3: Add your Telegram channel

Replace YOUR_BOT_TOKEN with the token from @BotFather:

docker compose run --rm openclaw-cli channels add --channel telegram --token "YOUR_BOT_TOKEN"

OpenClaw supports Discord, WhatsApp, Signal, Slack, and IRC too. For channel-specific setup, see our Telegram, Discord, or Signal guides.

Step 4: Start the gateway

docker compose up -d openclaw-gateway

Watch the logs to confirm it starts cleanly:

docker compose logs -f openclaw-gateway

You should see the gateway bind to port 18789 and your Telegram channel connect. Press Ctrl+C to stop tailing logs (the container keeps running).

Step 5: Approve the pairing

Send any message to your bot on Telegram. OpenClaw will respond with a pairing code. Approve it:

Replace PAIRING_CODE with the code from Telegram:

docker compose run --rm openclaw-cli pairing approve telegram PAIRING_CODE

If you also need to approve the web dashboard, list pending devices and approve them:

docker compose run --rm openclaw-cli devices list
docker compose run --rm openclaw-cli devices approve REQUEST_ID

Step 6: Verify

Send a test message to your bot on Telegram. If it responds, you're done.

To access the web dashboard:

docker compose run --rm openclaw-cli dashboard --no-open

Open the URL it prints in your browser. The dashboard runs on http://127.0.0.1:18789 with a token parameter.

How to Update OpenClaw in Docker

Pull the latest code, rebuild the image, and restart. Your config and workspace persist through the volume mounts.

cd openclaw
git pull
docker build -t openclaw:local -f Dockerfile .
docker compose down
docker compose up -d openclaw-gateway

Verify your workspace survived:

docker compose exec openclaw-gateway ls /home/node/.openclaw/workspace

Your files should be exactly where you left them. The volume mounts mean the container is disposable; the data is not.

Backup and Restore

Backup

Stop the container to ensure file consistency, then archive the mounted directories:

docker compose down
tar czf openclaw-backup-$(date +%Y%m%d).tar.gz \
  ~/.openclaw
docker compose up -d openclaw-gateway

This captures everything: config, sessions, workspace, channel tokens, and agent memory. The entire backup is one file.

Restore

docker compose down
cd ~
tar xzf openclaw-backup-20260226.tar.gz
docker compose up -d openclaw-gateway

The gateway picks up where it left off. No re-pairing needed as long as the session data is intact.

Backup schedule

How often depends on how much work you're willing to lose. For a personal bot, weekly is fine. For production use, daily or on every significant config change.

A cron job handles this well:

0 3 * * 0 cd /path/to/openclaw && docker compose down && \
  tar czf /backups/openclaw-$(date +\%Y\%m\%d).tar.gz ~/.openclaw && \
  docker compose up -d openclaw-gateway

Docker vs. Bare Metal: What's Actually Different?

Docker adds a layer of isolation, but it's not a security silver bullet. Here's what changes and what doesn't.

What Docker isolates

  • Filesystem. The container only sees mounted volumes. If you mount ~/.openclaw and nothing else, the agent can't read your home directory, SSH keys, or other files.
  • Process space. Processes inside the container are invisible to the host's process list (from the container's perspective). A runaway process can't interfere with host services.
  • Network namespacing. The container has its own network stack. Combined with localhost-only port binding, nothing is exposed to the wider network.

What Docker does NOT isolate

  • API keys. Environment variables inside the container (your model provider keys, gateway token) are accessible to any process in that container. A compromised agent can read them. This is true on bare metal too, but worth stating explicitly.
  • Outbound network. The container can make outbound HTTP requests to anywhere by default. If an agent is compromised, it can exfiltrate data. You can restrict this with Docker network policies, but the default compose setup doesn't.
  • Mounted volumes. Anything you mount is fully accessible. Mount ~/ and you've defeated the purpose.

When to go further

If you're running OpenClaw for a team or in production, consider:

  • Read-only root filesystem (read_only: true in compose) to prevent writes outside mounted volumes
  • Network restrictions using a Docker network with controlled egress
  • Agent sandboxing (OpenClaw's built-in feature) which runs agent tool execution in separate ephemeral containers. DigitalOcean's 1-Click Deploy enables this by default.
  • Tailscale or WireGuard for remote access instead of exposing ports

For a full hardening walkthrough, see the OpenClaw Security Hardening Playbook.

Troubleshooting

Container exits immediately

Check the logs:

docker compose logs openclaw-gateway

Exit code 137 means the container was OOM-killed. You need at least 2 GB of RAM for the build, and 1 GB for runtime. Increase your deploy.resources.limits.memory or upgrade the host.

Exit code 1 usually means a config error. Look for missing environment variables or malformed config files. Run the onboarding wizard again if needed:

docker compose run --rm openclaw-cli onboard

Can't pair from Telegram

  1. Check that the gateway is running: docker compose ps should show the gateway as "Up."
  2. Check port mapping: docker compose port openclaw-gateway 18789 should show 127.0.0.1:18789.
  3. Verify the bot token: make sure the Telegram bot token you passed to channels add is correct. Also confirm OPENCLAW_GATEWAY_TOKEN in .env matches what the onboarding wizard generated.
  4. Check logs for pairing errors: docker compose logs openclaw-gateway | grep -i pair

If the CLI container can't reach the gateway, they may be on different Docker networks. Make sure both services are defined in the same docker-compose.yml.

Workspace changes don't persist

Run docker compose exec openclaw-gateway ls -la /home/node/.openclaw/workspace and compare with ls -la ~/.openclaw/workspace on your host. If they don't match, your volume mount isn't configured correctly.

Common causes:

  • Typo in OPENCLAW_WORKSPACE_DIR in .env
  • Docker Compose using a cached version of the env file (run docker compose down && docker compose up -d to force a reload)
  • Permission issues: the container runs as uid 1000. Fix with sudo chown -R 1000:1000 ~/.openclaw on the host.

Permission denied errors

The OpenClaw image runs as the node user (uid 1000). If your host directories are owned by a different user:

sudo chown -R 1000:1000 ~/.openclaw

Frequently Asked Questions

Do I need Node.js installed on the host?

No. The Docker image includes Node.js 22. That's one of the benefits: your host stays clean.

Can I use the docker-setup.sh script instead of manual setup?

Yes. The official setup script handles building, onboarding, and starting in one command: ./docker-setup.sh. The manual steps in this guide give you more control over each configuration choice.

How do I install extra packages in the container?

Two options. For packages that survive rebuilds, set OPENCLAW_DOCKER_APT_PACKAGES before running the setup script:

export OPENCLAW_DOCKER_APT_PACKAGES="ffmpeg ripgrep"
./docker-setup.sh

For one-off installs, exec as root:

docker compose exec -u root openclaw-gateway bash
apt-get update && apt-get install -y ripgrep

These won't survive a container rebuild. Use OPENCLAW_DOCKER_APT_PACKAGES for anything permanent.

Is Docker required for OpenClaw?

No. Docker is explicitly optional. You can install OpenClaw directly with Node.js. Docker adds isolation and reproducibility, but it's not the only way.

What about Docker on a VPS?

This guide works on any machine with Docker, including VPS instances. For VPS-specific setup (droplet creation, SSH, firewall), see the DigitalOcean VPS guide. DigitalOcean also offers a hardened 1-Click Deploy that includes Docker, Caddy TLS, fail2ban, and agent sandboxing out of the box.

Key Terms

Gateway is the always-running OpenClaw process that connects to your messaging channels, handles conversations, and dispatches agent sessions.

Pairing is OpenClaw's device authorization system. Every new device (Telegram account, web browser, phone) must be approved before it can send commands to the gateway.

Agent sandboxing is an OpenClaw feature that runs agent tool execution (file writes, shell commands) inside ephemeral Docker containers, separate from the gateway container. This adds a second layer of isolation on top of containerizing the gateway itself.

Evidence and Methodology

The docker-compose.yml in this guide is adapted from the official OpenClaw compose file with three security additions documented inline. All claims about Docker networking behavior (port binding, interface exposure) link to the official Docker documentation. RAM requirements, exit codes, and container user IDs were verified against the OpenClaw Docker docs. Simon Willison's workflow recommendations link directly to his published TIL entry. The DigitalOcean hardened deployment references link to their published technical blog post.

Sources

  1. OpenClaw. "Docker (optional)." docs.openclaw.ai/install/docker. Accessed February 2026.
  2. OpenClaw. "docker-compose.yml." github.com/openclaw/openclaw/blob/main/docker-compose.yml. Accessed February 2026.
  3. Willison, Simon. "Running OpenClaw in Docker." til.simonwillison.net/llms/openclaw-docker. February 2026.
  4. DigitalOcean. "Technical Deep Dive: How we Created a Security-hardened 1-Click Deploy OpenClaw." digitalocean.com/blog/technical-dive-openclaw-hardened-1-click-app. February 2026.
  5. DigitalOcean. "OpenClaw Marketplace Catalog." docs.digitalocean.com/products/marketplace/catalog/openclaw. Accessed February 2026.

Changelog

  • 2026-02-26: Initial publication

Enjoyed this post?

Get new articles delivered to your inbox. No spam, unsubscribe anytime.

Comments