Prerequisites

  • Docker Engine 24+ installed (docker --version)
  • docker-compose v2+ (docker compose version)
  • At least one LLM provider API key (OpenAI, Anthropic, or Ollama locally)
  • 2GB free RAM minimum (4GB recommended for production)

Quick Start — Single Container

Run OpenClaw with a single docker run command for testing or lightweight use:

docker run -d   --name openclaw   -e OPENAI_API_KEY=sk-your-key   -p 8080:8080   -v openclaw-data:/app/data   ghcr.io/openclaw-ai/openclaw:latest
# Test it works
curl http://localhost:8080/health
# {"status": "ok", "version": "1.5.2"}

# Run a task via API
curl -X POST http://localhost:8080/tasks   -H "Content-Type: application/json"   -d '{"prompt": "List 3 benefits of containerization"}'

Custom Dockerfile

For production, build your own image that includes your custom agents and plugins:

FROM python:3.12-slim

# Security: run as non-root user
RUN addgroup --system openclaw && adduser --system --ingroup openclaw openclaw

WORKDIR /app

# Install dependencies first (better layer caching)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application
COPY --chown=openclaw:openclaw . .

USER openclaw

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3   CMD curl -f http://localhost:8080/health || exit 1

EXPOSE 8080

CMD ["openclaw", "serve", "--host", "0.0.0.0", "--port", "8080"]
requirements.txt:
openclaw==1.5.2
openclaw[redis]==1.5.2   # Include Redis backend
gunicorn==21.2.0          # Production WSGI server

Production docker-compose.yml

For a complete stack with Redis caching and PostgreSQL persistence:

version: "3.9"

services:
  openclaw:
    image: ghcr.io/openclaw-ai/openclaw:1.5.2
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      - OPENAI_API_KEY=${OPENAI_API_KEY}
      - OPENCLAW_ENV=production
      - REDIS_URL=redis://redis:6379/0
      - DATABASE_URL=postgresql://openclaw:${DB_PASS}@db:5432/openclaw
    depends_on:
      redis:
        condition: service_healthy
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
    deploy:
      resources:
        limits:
          cpus: "2"
          memory: 1G

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

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

volumes:
  redis-data:
  db-data:
# Create .env file (never commit this!)
echo "OPENAI_API_KEY=sk-your-key" > .env
echo "DB_PASS=$(openssl rand -base64 32)" >> .env

# Start the stack
docker compose up -d

# Check all services are healthy
docker compose ps

Security Hardening

Docker containers provide some isolation by default, but production deployments should apply additional hardening:

  • Non-root user — already in the Dockerfile above; never run as root
  • Read-only filesystem — add read_only: true to the service and mount specific writable paths as volumes
  • No new privileges — add security_opt: ["no-new-privileges:true"]
  • Drop Linux capabilities — add cap_drop: [ALL] and only add back what's needed
  • Secrets via Docker secrets — don't put API keys in environment variables in .env files in production; use Docker secrets or a vault
# Hardened service configuration
services:
  openclaw:
    read_only: true
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    tmpfs:
      - /tmp
    volumes:
      - openclaw-data:/app/data  # Writable volume for data

Logs and Monitoring

# Stream logs from all services
docker compose logs -f

# Only OpenClaw logs
docker compose logs -f openclaw

# Filter for errors only
docker compose logs openclaw | grep '"level":"error"'

Configure log rotation to prevent disk exhaustion:

services:
  openclaw:
    logging:
      driver: "json-file"
      options:
        max-size: "50m"
        max-file: "5"

For structured log shipping to Datadog, Loki, or Elasticsearch, see Structured Logging.

Production Docker Configuration

A production-ready Docker configuration for OpenClaw addresses security, resource limits, logging, and health checking. The minimal production docker-compose.yml includes: a resource limits block to prevent the container from consuming unbounded memory (mem_limit: 512m for most agents), a health check that verifies the agent process is responsive, a restart policy of unless-stopped for automatic recovery from crashes, and read-only filesystem with a specific writeable volume for logs and agent memory. These four elements together make the container self-healing and resource-bounded.

Multi-stage Docker builds keep production images small and secure. Use a build stage to assemble the application with all build tools installed, then copy only the necessary artifacts to a minimal runtime image. A Python OpenClaw deployment might use a python:3.11-slim build stage and a python:3.11-alpine runtime stage, reducing the final image size by 60-70% and eliminating build tools (pip, gcc, make) from the production image. Smaller images have a smaller attack surface and deploy faster due to reduced pull time.

Secrets Handling in Docker

Never bake secrets into Docker images — once a secret is in an image layer, it's accessible to anyone who can pull the image, even if you add a later layer that removes the file. Pass secrets at runtime using Docker secrets (in Swarm mode) or environment variables injected by your deployment system. For Docker Compose on a single host, use a .env file that is excluded from version control via .gitignore. Verify your .gitignore contains .env before committing — accidentally committing credentials is one of the most common security incidents in containerized deployments.

Container Registry and Image Scanning

Maintain your OpenClaw images in a private container registry (Docker Hub private, ECR, GCR, or Azure Container Registry). Enable vulnerability scanning on your registry — most cloud registries offer this built-in. Configure your CI pipeline to fail the build if the image scan finds high-severity CVEs in base OS packages or Python dependencies. Regularly update your base image to pick up security patches, and track the OpenClaw release notes for dependency updates. A well-maintained image as of deployment date that is never updated will accumulate vulnerabilities — treat image updates as ongoing operational work, not a one-time task.