Back to Blog
Deployment25 min readIntermediate

Docker Deployment Guide

Deploy OpenClaw with Docker and Compose, then harden the stack for production with environment isolation, logs, and scaling patterns.

Published March 19, 2026Updated March 23, 2026
OpenClaw DockerDocker deployment guideself-hosted docker

Complete OpenClaw Docker Deployment Guide

Target keywords: OpenClaw Docker, OpenClaw container, Docker deployment, self-hosted docker


Introduction

Docker is the simplest way to deploy OpenClaw. This guide covers the full Docker deployment workflow from development to production.

What you will learn:

  • Basic Docker configuration
  • docker-compose deployment
  • Production optimization
  • Multi-stage builds
  • Monitoring and logging

Estimated time: 25 minutes
Difficulty: Intermediate


Quick Start

One-Command Deployment

# Create the directory
mkdir openclaw-docker && cd openclaw-docker

# Download the configuration file
curl -O https://raw.githubusercontent.com/openclaw/openclaw/main/docker-compose.yml

# Start
sudo docker-compose up -d

# View logs
sudo docker-compose logs -f

Done! OpenClaw is running at http://localhost:8080


Basic Configuration

1.1 Minimal docker-compose.yml

version: '3.8'

services:
  openclaw:
    image: openclaw/openclaw:latest
    container_name: openclaw
    ports:
      - "8080:8080"
    environment:
      - OPENAI_API_KEY=${OPENAI_API_KEY}
    volumes:
      - ./config:/root/.openclaw
      - ./logs:/var/log/openclaw
    restart: unless-stopped

1.2 Environment Variable File

Create .env:

# API Keys
OPENAI_API_KEY=sk-your-key-here
ANTHROPIC_API_KEY=sk-ant-your-key

# Discord (optional)
DISCORD_BOT_TOKEN=your-discord-token

# Telegram (optional)
TELEGRAM_BOT_TOKEN=your-telegram-token

# WhatsApp (optional)
WHATSAPP_TOKEN=your-whatsapp-token

# Log level
LOG_LEVEL=info

Important: Add .env to .gitignore.

1.3 Start the Stack

# Load environment variables and start
docker-compose up -d

# Check status
docker-compose ps

# View logs
docker-compose logs -f openclaw

Advanced Configuration

2.1 Production-Grade docker-compose.yml

version: '3.8'

services:
  openclaw:
    image: openclaw/openclaw:latest
    container_name: openclaw
    
    # Resource limits
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2G
        reservations:
          cpus: '1'
          memory: 1G
    
    ports:
      - "127.0.0.1:8080:8080"  # Local access only (through Nginx)
    
    environment:
      - OPENAI_API_KEY=${OPENAI_API_KEY}
      - LOG_LEVEL=info
      - TZ=Asia/Shanghai
    
    volumes:
      - openclaw-config:/root/.openclaw
      - openclaw-logs:/var/log/openclaw
    
    networks:
      - openclaw-network
    
    restart: unless-stopped
    
    # Health check
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  # Nginx reverse proxy
  nginx:
    image: nginx:alpine
    container_name: openclaw-nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - openclaw
    networks:
      - openclaw-network
    restart: unless-stopped

  # Optional: Redis cache
  redis:
    image: redis:7-alpine
    container_name: openclaw-redis
    volumes:
      - redis-data:/data
    networks:
      - openclaw-network
    restart: unless-stopped

volumes:
  openclaw-config:
  openclaw-logs:
  redis-data:

networks:
  openclaw-network:
    driver: bridge

2.2 Nginx Configuration

# nginx.conf
events {
    worker_connections 1024;
}

http {
    upstream openclaw {
        server openclaw:8080;
    }

    server {
        listen 80;
        server_name yourdomain.com;
        
        # Redirect to HTTPS
        return 301 https://$server_name$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name yourdomain.com;

        # SSL certificate
        ssl_certificate /etc/nginx/ssl/cert.pem;
        ssl_certificate_key /etc/nginx/ssl/key.pem;
        
        # SSL configuration
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;

        # Security headers
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;

        # Proxy to OpenClaw
        location / {
            proxy_pass http://openclaw;
            proxy_http_version 1.1;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            
            # WebSocket support
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    }
}

Multi-Stage Build

3.1 Custom Dockerfile

# Dockerfile
FROM openclaw/openclaw:latest AS base

# Install additional dependencies
RUN apt-get update && apt-get install -y \
    curl \
    ca-certificates \
    && rm -rf /var/lib/apt/lists/*

# Create a non-root user
RUN useradd -m -u 1000 openclaw

# Set the working directory
WORKDIR /app

# Copy the configuration
COPY --chown=openclaw:openclaw config/ /app/.openclaw/

# Switch user
USER openclaw

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

EXPOSE 8080

CMD ["openclaw", "start"]

3.2 Build and Run

# Build the image
docker build -t my-openclaw:latest .

# Run
docker run -d \
  --name openclaw \
  -p 8080:8080 \
  -e OPENAI_API_KEY=$OPENAI_API_KEY \
  -v $(pwd)/config:/app/.openclaw \
  my-openclaw:latest

Production Optimization

4.1 Performance Tuning

services:
  openclaw:
    image: openclaw/openclaw:latest
    
    # CPU and memory
    deploy:
      resources:
        limits:
          cpus: '4'
          memory: 4G
    
    # Environment optimization
    environment:
      - GOMAXPROCS=4
      - GOMEMLIMIT=3GiB
      - LOG_LEVEL=warn  # Reduce logging in production
    
    # Log limits
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
        max-file: "3"

4.2 Automatic Updates

#!/bin/bash
# update.sh - automatic update script

# Pull the latest image
docker-compose pull

# Restart gracefully
docker-compose up -d

# Clean up old images
docker image prune -f

# Send a notification (optional)
curl -X POST https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage \
  -d "chat_id=$ADMIN_CHAT_ID" \
  -d "text=OpenClaw updated successfully"

Add to crontab:

# Update every Monday at 3:00 AM
0 3 * * 1 /path/to/update.sh

4.3 Backup Strategy

#!/bin/bash
# backup.sh

BACKUP_DIR="/backups/openclaw"
DATE=$(date +%Y%m%d_%H%M%S)

# Create the backup
mkdir -p $BACKUP_DIR

# Back up the configuration
docker run --rm \
  -v openclaw-docker_openclaw-config:/data \
  -v $BACKUP_DIR:/backup \
  alpine tar czf /backup/config_$DATE.tar.gz -C /data .

# Back up logs (optional)
docker run --rm \
  -v openclaw-docker_openclaw-logs:/data \
  -v $BACKUP_DIR:/backup \
  alpine tar czf /backup/logs_$DATE.tar.gz -C /data .

# Keep the 7 most recent backups
ls -t $BACKUP_DIR/config_*.tar.gz | tail -n +8 | xargs rm -f

echo "Backup completed: $BACKUP_DIR/config_$DATE.tar.gz"

Monitoring and Logs

5.1 Log Collection

services:
  openclaw:
    logging:
      driver: "fluentd"
      options:
        fluentd-address: localhost:24224
        tag: docker.openclaw

5.2 Prometheus Monitoring

services:
  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana

5.3 View Live Logs

# View logs for all services
docker-compose logs -f

# View OpenClaw only
docker-compose logs -f openclaw

# Last 100 lines
docker-compose logs --tail=100 openclaw

# With timestamps
docker-compose logs -f -t openclaw

Troubleshooting

Issue 1: Container will not start

# View error logs
docker-compose logs openclaw

# Check the configuration
docker-compose config

# Verify environment variables
cat .env

# Recreate the containers
docker-compose down
docker-compose up -d

Issue 2: Port conflict

# Check port usage
sudo lsof -i :8080

# Modify `docker-compose.yml` to use a different port
ports:
  - "8081:8080"  # Host:container

Issue 3: Permission errors

# Fix volume permissions
sudo chown -R 1000:1000 ./config
sudo chown -R 1000:1000 ./logs

# Or specify the user in `docker-compose`
services:
  openclaw:
    user: "1000:1000"

Issue 4: Out of memory

# View container memory usage
docker stats

# Increase the memory limit
docker-compose down
# Edit `docker-compose.yml` to add a memory limit
docker-compose up -d

Deployment by Environment

Development Environment

# docker-compose.dev.yml
version: '3.8'

services:
  openclaw:
    image: openclaw/openclaw:latest
    ports:
      - "8080:8080"
    environment:
      - LOG_LEVEL=debug
      - DEV_MODE=true
    volumes:
      - ./config:/root/.openclaw
      - ./src:/app/src  # Hot reload source code
    command: ["openclaw", "start", "--dev"]

Test Environment

# docker-compose.test.yml
services:
  openclaw:
    image: openclaw/openclaw:latest
    environment:
      - LOG_LEVEL=info
      - TEST_MODE=true
    depends_on:
      - redis-test
      
  redis-test:
    image: redis:7-alpine

Production Cluster (Swarm)

# docker-compose.prod.yml
version: '3.8'

services:
  openclaw:
    image: openclaw/openclaw:latest
    deploy:
      replicas: 3
      placement:
        constraints:
          - node.role == worker
      resources:
        limits:
          cpus: '2'
          memory: 2G
    networks:
      - overlay

Deploy:

docker stack deploy -c docker-compose.prod.yml openclaw

Next Steps


Get more tutorials for free:

[Email subscription form]


Last updated: March 2026