⚠️ Critical Warning: Docker Is Not Enough

Containerization is a layer, not a solution.

Running OpenClaw in Docker without additional isolation leaves you vulnerable to:

  • Container escape via privileged mode or kernel exploits
  • Host network exposure if the gateway binds to 0.0.0.0
  • Volume mount risks when sharing host filesystems
  • Secret leakage through environment variables or mounted files

You need defense in depth. This guide gives you the Docker layer. Pair it with:

  • Off-network VPS deployment (see YOLO Safely)
  • Network segmentation and egress filtering
  • Read-only filesystems and non-root execution
  • Monitoring and audit logging

Coming soon: Dedicated VPS hardening guide with cloud-init scripts, firewall rules, and automated lockdown procedures (~Week 2-3 on content calendar).


Quick Start (If You Accept the Risks)

1
2
3
4
5
6
7
8
9
# Clone the compose configuration
curl -fsSL https://raw.githubusercontent.com/openclaw/openclaw/main/docker-compose.yml -o docker-compose.yml

# Create environment file
cp .env.example .env
# Edit .env with your API keys and settings

# Start with security flags
docker-compose up -d

Security-Hardened Docker Compose

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
version: '3.8'

services:
  openclaw:
    image: openclaw/openclaw:latest
    container_name: openclaw-agent
    restart: unless-stopped
    
    # Security: Run as non-root
    user: "1000:1000"
    
    # Security: Read-only root filesystem
    read_only: true
    
    # Security: Limit capabilities
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE  # Only if binding to privileged port
    
    # Security: No new privileges
    security_opt:
      - no-new-privileges:true
    
    # Security: Limited resources
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 2G
        reservations:
          cpus: '0.5'
          memory: 512M
    
    # Network: Custom isolated network
    networks:
      - openclaw-net
    
    # Ports: Only expose what you need
    # WARNING: Binding to 0.0.0.0 exposes to the internet
    # Use 127.0.0.1:port:port for localhost-only
    ports:
      - "127.0.0.1:3000:3000"  # Web UI - localhost only
      - "127.0.0.1:8080:8080"  # Gateway API - localhost only
    
    # Environment: Pass through, not hardcoded
    env_file:
      - .env
    
    # Volumes: Minimal, temporary where possible
    volumes:
      # Persistent data (encrypted at rest ideally)
      - openclaw-data:/app/data
      
      # Temporary files (noexec, nosuid, nodev)
      - type: tmpfs
        target: /tmp
        tmpfs:
          size: 100M
          mode: 1777
      
      # Read-only config
      - ./config:/app/config:ro
    
    # Health checks
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    
    # Logging
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
        labels: "openclaw,agent"

  # Optional: Monitoring sidecar
  agent-monitor:
    image: prom/node-exporter:latest
    container_name: openclaw-monitor
    restart: unless-stopped
    networks:
      - openclaw-net
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.rootfs=/rootfs'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'

networks:
  openclaw-net:
    driver: bridge
    internal: false  # Set to true for no external access (use with proxy)
    ipam:
      config:
        - subnet: 172.20.0.0/16

volumes:
  openclaw-data:
    driver: local

Environment Configuration

Create .env:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Required: API keys (use burner keys, not production)
ANTHROPIC_API_KEY=sk-ant-your-burner-key-here
OPENAI_API_KEY=sk-your-burner-key-here

# Optional: Model selection
DEFAULT_MODEL=claude-sonnet-4-5
FALLBACK_MODEL=kimi-k2-5

# Security: Disable dangerous features by default
ENABLE_SHELL_EXECUTION=false
ENABLE_FILE_WRITE=false
ENABLE_NETWORK_FETCH=false

# Only enable after reviewing skill code:
# ENABLE_SHELL_EXECUTION=true
# ENABLE_FILE_WRITE=true
# ENABLE_NETWORK_FETCH=true

# Logging
LOG_LEVEL=info
LOG_FORMAT=json

# Gateway binding (127.0.0.1 = localhost only)
GATEWAY_BIND=127.0.0.1
GATEWAY_PORT=8080

Network Security Checklist

Before Starting the Container

  • Firewall configured: Only outbound 443, no inbound except SSH
  • Gateway binds to localhost: 127.0.0.1:port, not 0.0.0.0:port
  • No host network mode: Never use --network host
  • Secrets in env file: Not in compose, not in images
  • VPS off home network: Hetzner/Vultr, not your laptop

After Starting the Container

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Verify network exposure
ss -tlnp | grep -E '(3000|8080)'
# Should show 127.0.0.1, NOT 0.0.0.0 or :::

# Check for unexpected ports
docker exec openclaw-agent ss -tlnp

# Verify read-only filesystem
docker exec openclaw-agent touch /tmp/test-write  # Should work
docker exec openclaw-agent touch /app/test-write  # Should fail

# Check running user
docker exec openclaw-agent id  # Should show uid=1000, not root

Common Mistakes

Mistake 1: --privileged Mode

Don’t:

1
docker run --privileged openclaw/openclaw  # Gives full host access

Do: Use capability dropping (see compose file above).

Mistake 2: Volume Mounting Host Docker Socket

Don’t:

1
2
volumes:
  - /var/run/docker.sock:/var/run/docker.sock  # Container escape

Do: Run separate monitoring containers, not Docker-in-Docker.

Mistake 3: Binding to 0.0.0.0

Don’t:

1
2
ports:
  - "3000:3000"  # Binds to all interfaces

Do:

1
2
ports:
  - "127.0.0.1:3000:3000"  # Localhost only

Mistake 4: Running on Your Laptop

Don’t: Run OpenClaw Docker on your development machine with access to:

  • Your SSH keys (~/.ssh)
  • Your Git config (~/.gitconfig)
  • Your work Slack/Discord
  • Your cloud provider credentials

Do: Deploy to a disposable VPS. See YOLO Safely.


Monitoring Container Activity

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Real-time container stats
docker stats openclaw-agent

# View logs
docker logs -f openclaw-agent

# Inspect network connections
docker exec openclaw-agent netstat -tuln

# Check filesystem changes (run from host)
docker diff openclaw-agent

What’s Missing (Coming Soon)

This Docker configuration is one layer of a complete security strategy.

VPS Hardening Guide (~Week 2-3):

  • Cloud-init scripts for automated lockdown
  • UFW/iptables rules for egress filtering
  • SSH hardening (key-only, port change, fail2ban)
  • Host-level audit logging with auditd
  • Automated snapshot/backup before experiments
  • WireGuard mesh for distributed agent topologies

Subscribe to updates or check /posts/openclaw-security-reality-2026/ for release timeline.



Last updated: February 3, 2026

Security verification: Docker configurations tested on Ubuntu 22.04 with Docker 24.0+. Always verify network binding before exposing to any network.