Home Hosting & Deployment Containerization OpenClaw Docker Compose
Containerization Docker Hosting & Deployment

OpenClaw Docker Compose: Spin Up Your Full Stack in One Command

Most Docker setups for OpenClaw fail before the first agent runs. The missing piece isn't the Dockerfile — it's the orchestration layer that wires the gateway, workers, and backing services into a coherent, restartable stack.

JD
J. Donovan
Infrastructure & Containerization
Feb 1, 2025 15 min read 7,200 views
Updated Feb 2025
Key Takeaways
A single docker compose up -d command starts the entire OpenClaw stack — gateway, agent workers, Redis, and optional Postgres — with correct startup ordering.
Use depends_on with healthchecks to prevent agents from starting before Redis is accepting connections — this eliminates 80% of cold-start failures.
Store all secrets in a .env file and reference them as ${VAR} in the YAML — never hardcode API keys in docker-compose.yml.
Named volumes persist agent memory and conversation history across container restarts and image updates.
Scale workers horizontally with --scale agent=N without touching your compose file or restarting the gateway.

A single docker compose up -d can launch a fully operational OpenClaw environment in under 90 seconds. That includes the gateway, multiple agent workers, Redis for task queuing, and persistent volume storage. Here's what breaks that for most people: they containerize OpenClaw but skip the service orchestration, and then wonder why agents fail to connect on startup or lose state on restart.

What You Need Before You Start

Docker Compose v2 ships bundled with Docker Desktop and current Docker Engine installs. Run docker compose version to confirm you have v2.x — the command uses a space, not a hyphen. If you get a "command not found" error with the spaced syntax, you're on the legacy v1 CLI and should upgrade before proceeding.

You'll also need your OpenClaw API key and at least one LLM provider key. These go into a .env file, not into the compose YAML itself. Create that file before writing a single line of YAML — it's easier to reference variables you've already defined than to circle back and extract hardcoded values later.

  • Docker Engine 24+ or Docker Desktop 4.20+
  • Docker Compose v2.17+ (included with the above)
  • OpenClaw API key
  • At least 2GB RAM available for the full stack
  • A .env file in your project root with all secrets
Docker Desktop vs. Docker Engine
Docker Desktop includes a resource limit GUI that defaults to 2GB RAM. If you run the full OpenClaw stack including Postgres, increase this to at least 4GB in Docker Desktop → Settings → Resources. Engine on Linux has no such cap by default.

Understanding the OpenClaw Stack Architecture

Before writing the compose file, understand what you're orchestrating. The OpenClaw gateway is the single external entry point — it receives requests, authenticates them, and routes tasks to worker containers. Workers pull jobs from a Redis queue, execute them against your configured LLM provider, and write results back. Postgres (optional but recommended for production) stores persistent agent memory and conversation history.

This means your compose file needs four services in the correct dependency order: Redis starts first, Postgres starts in parallel with Redis, the gateway starts after both are healthy, and workers start after the gateway is healthy. Get that ordering wrong and you'll see connection errors in the first 30 seconds of every cold start.

The startup sequence that works:

  1. Redis and Postgres launch simultaneously
  2. Both expose healthchecks that Compose polls
  3. Gateway starts only when both pass their healthchecks
  4. Agent workers start only when the gateway healthcheck passes

We'll get to the exact healthcheck configuration in a moment — but first, understand why skipping it breaks everything.

Without healthchecks, Docker Compose uses "started" as the dependency condition. A container reports started the moment the process launches — not when the service inside it is actually ready to accept connections. Redis takes about 200ms to initialize. Postgres takes 2–4 seconds. If the gateway starts the instant Redis reports "started," it will fail to connect and crash before Redis has finished booting.

The Docker Compose Configuration

Here's a production-ready docker-compose.yml for OpenClaw. Every field is intentional — I'll explain the non-obvious ones after the block.

version: "3.9"

services:
  redis:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5
      start_period: 10s

  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: openclaw
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - pg-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d openclaw"]
      interval: 5s
      timeout: 5s
      retries: 10
      start_period: 20s

  gateway:
    image: openclaw/gateway:latest
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      OPENCLAW_API_KEY: ${OPENCLAW_API_KEY}
      REDIS_URL: redis://redis:6379
      DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/openclaw
      LOG_FORMAT: json
      LOG_LEVEL: info
    depends_on:
      redis:
        condition: service_healthy
      postgres:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 15s

  agent:
    image: openclaw/agent:latest
    restart: unless-stopped
    environment:
      GATEWAY_URL: http://gateway:8080
      OPENCLAW_API_KEY: ${OPENCLAW_API_KEY}
      OPENAI_API_KEY: ${OPENAI_API_KEY}
      AGENT_CONCURRENCY: 2
    volumes:
      - agent-data:/app/data
    depends_on:
      gateway:
        condition: service_healthy
    deploy:
      replicas: 1

volumes:
  redis-data:
  pg-data:
  agent-data:

A few things worth noting: restart: unless-stopped means containers restart automatically after host reboots or crashes, but not when you manually stop them with docker compose stop. This is the right behavior for production — you don't want accidental restarts during maintenance windows. The AGENT_CONCURRENCY: 2 variable controls how many tasks a single worker processes simultaneously. Start at 2, increase to 4 only after confirming your LLM provider rate limits can handle it.

Your .env file should look like this:

OPENCLAW_API_KEY=your-openclaw-key-here
POSTGRES_USER=openclaw
POSTGRES_PASSWORD=change-this-to-something-strong
OPENAI_API_KEY=sk-your-openai-key-here
Never Commit Your .env File
Add .env to your .gitignore before your first commit. If you accidentally push API keys to a public repo, rotate them immediately — GitHub's secret scanning bots and malicious scrapers will find them within minutes of the push going public.

Running and Testing the Stack

With your compose file and .env in place, bring the stack up:

# Start all services in detached mode
docker compose up -d

# Follow logs from all services
docker compose logs -f

# Follow logs from a specific service
docker compose logs -f gateway

# Check service health status
docker compose ps

The docker compose ps output is your first diagnostic tool. You want to see "healthy" next to every service. If any service shows "starting" for more than 60 seconds or "unhealthy," check its logs immediately with docker compose logs [service-name].

Once everything is healthy, verify the gateway responds:

curl http://localhost:8080/health
# Expected: {"status":"ok","version":"x.x.x"}

Sound familiar? This is the same endpoint the gateway healthcheck uses. If curl returns a response, your full stack is operational.

Scaling and Optimization

Docker Compose handles horizontal scaling of the agent service without any configuration changes:

# Scale to 3 agent workers
docker compose up -d --scale agent=3

# Scale back down to 1
docker compose up -d --scale agent=1

Here's where most people stop. The real optimization is resource constraints — without them, a misbehaving agent can starve the gateway of memory and bring down the entire stack.

ServiceRecommended CPU LimitRecommended Memory LimitNotes
redis0.5 cores256MBIncrease for high message volume
postgres1.0 cores512MBIncrease for large conversation history
gateway1.0 cores512MBHandles all request routing
agent (per worker)1.0 cores768MBScale count, not per-worker resources

Add these limits under a deploy.resources block in each service definition. As of early 2025, resource limits in Compose are applied without requiring Swarm mode when using Docker Engine 24+.

💡
Use Compose Profiles for Optional Services
Add profiles: ["monitoring"] to Prometheus or Grafana service definitions. They only start when you run docker compose --profile monitoring up -d, keeping your standard stack lean for development.

Common Mistakes

Skipping healthchecks on depends_on. Using depends_on: [redis] without a condition only waits for the container to start, not for Redis to be ready. Always use condition: service_healthy.

Using host networking for inter-service communication. Services in the same Compose network reach each other by service name. Use redis://redis:6379, not redis://localhost:6379. Localhost inside a container refers to that container, not the host.

Not persisting Redis data. Without a volume on Redis, every restart wipes the task queue. If agents are mid-task when the container restarts, those tasks are lost. The named volume in the config above prevents this.

Setting AGENT_CONCURRENCY too high. Each concurrent task makes API calls to your LLM provider. Five workers at concurrency 4 means 20 simultaneous API calls. Most OpenAI tier-1 accounts rate limit at 60 RPM, which sounds like enough until a task triggers multiple tool calls in rapid succession.

Forgetting to pull updated images. docker compose up -d only pulls images if they're not already present locally. Run docker compose pull before up -d when deploying updates, or pin image tags and only update them intentionally.

Frequently Asked Questions

What services does the OpenClaw Docker Compose stack include?

The default stack includes the OpenClaw gateway, one or more agent worker containers, a Redis instance for task queuing, and an optional Postgres container for persistent memory. You can strip it down to just gateway plus workers for lightweight or development deployments where persistence isn't required.

How do I start OpenClaw with Docker Compose?

Run docker compose up -d from the directory containing your docker-compose.yml. The -d flag runs it detached. Check all service statuses with docker compose ps and follow logs with docker compose logs -f. The gateway is ready when its healthcheck shows "healthy."

Can I scale OpenClaw agent workers with Docker Compose?

Run docker compose up -d --scale agent=3 to spin up three agent worker containers behind the gateway. Compose handles the load distribution automatically through the gateway's routing logic. For production scaling beyond five workers, Kubernetes or Docker Swarm gives you more precise control and automatic rescheduling on failure.

How do I pass API keys safely into a Docker Compose stack?

Create a .env file in the same directory as your docker-compose.yml and reference variables with ${VAR_NAME} syntax in the YAML. Never hardcode secrets directly in the compose file. Add .env to .gitignore immediately — exposed API keys in repos are the most common OpenClaw security incident by far.

Why does my OpenClaw gateway keep restarting in Docker Compose?

Usually a missing environment variable or a failed Redis connection at startup. Run docker compose logs gateway to see the crash reason. The most common fix is ensuring REDIS_URL is set correctly and that Redis has a healthcheck configured so the gateway's depends_on waits for Redis to be genuinely ready, not just started.

How do I update OpenClaw in a Docker Compose setup?

Pull updated images first with docker compose pull, then run docker compose up -d to recreate containers on the new image. Named volumes persist all your data across the update. Test in a staging environment — or at minimum with a test compose file — before updating production to catch breaking changes early.

What is the difference between docker-compose and docker compose?

docker-compose is the legacy Python-based CLI (v1). docker compose is the newer Go plugin built directly into the Docker CLI (v2). As of early 2025, use docker compose — it ships with Docker Desktop and current Engine installs, runs faster, and receives active maintenance while v1 is in long-term support mode only.

JD
J. Donovan
Infrastructure & Containerization

J. Donovan has built and maintained containerized agent infrastructure for production deployments across cloud and bare-metal environments. Specializes in Docker Compose and Kubernetes orchestration patterns for AI workloads, with hands-on experience migrating OpenClaw stacks from single-VM setups to fully orchestrated multi-worker deployments.

You now have a complete, production-ready Docker Compose setup for OpenClaw — with correct startup ordering, secret management, scaling capability, and persistent data volumes. The gateway is running, agents are queuing tasks through Redis, and everything restarts cleanly after a reboot. Your next step is to verify agent connectivity by sending a test task through the gateway API. It takes under five minutes and confirms the entire stack is wired correctly before you put real workloads on it.

Get the Latest OpenClaw Guides

New deployment tutorials, configuration tips, and agent infrastructure guides — straight to your inbox.