OpenClaw Docker Installation Tutorial

Master OpenClaw Docker installation with production-grade steps, Docker Compose configs, security hardening, and troubleshooting for self-hosted AI agents.

OpenClaw Team

Introduction

OpenClaw is a powerful, self-hostable AI agent orchestration framework that connects large language models to your local tools, APIs, and data pipelines. While running OpenClaw directly on your host machine works for experimentation, production deployments demand isolation, reproducibility, and clean dependency management. That is precisely where Docker enters the picture.

Containerizing OpenClaw solves three persistent pain points: dependency hell (Python version conflicts, native library mismatches), state pollution (agent memory and tool caches leaking across projects), and non-reproducible deployments ("it works on my machine" syndrome). By the end of this tutorial, you will have a hardened, production-ready OpenClaw Docker deployment with persistent volumes, health checks, automatic restarts, and a clean migration path between environments.

This guide assumes you are comfortable with the terminal and have basic Docker knowledge. If you are entirely new to OpenClaw, I recommend first reading our How to Run OpenClaw Locally: Quickstart & Local Development Guide to understand the core concepts before containerizing.

Architecture / Core Concepts

Before writing a single Dockerfile, you must understand how OpenClaw is structured at runtime. This knowledge directly informs your container design decisions.

OpenClaw Runtime Components

OpenClaw consists of three primary runtime layers:

  1. The Core Engine: A Python-based orchestrator that manages agent state, tool registration, and LLM API communication. It exposes a REST API and WebSocket interface for client connections.

  2. The Tool Registry: A dynamic collection of plugins (filesystem access, web scraping, database connectors, etc.) loaded at startup. Each tool may have its own native dependencies, which is the primary source of Docker image bloat.

  3. The State Store: Persistent agent memory, conversation history, and configuration files. In a containerized environment, this MUST live on a mounted volume—never inside the container's writable layer—or you will lose all agent state on every container recreation.

Container Design Decisions

Your Docker architecture must account for three critical factors:

Ephemeral vs. Persistent State: The container itself must be treated as disposable. All state—~/.openclaw/ configuration, agent memory databases, tool caches—must reside on Docker volumes. This enables zero-downtime upgrades and trivial rollbacks.

Network Topology: OpenClaw makes outbound HTTPS calls to LLM providers (OpenAI, Anthropic, local Ollama instances). If your LLM runs locally (e.g., Ollama on the same host), you need a shared Docker network or host.docker.internal access. If you use cloud LLM APIs, standard bridge networking suffices.

Resource Isolation: LLM agent workloads are memory-hungry. A single agent session can consume 500MB–2GB of RAM depending on context window size and tool complexity. Set hard memory limits in Docker to prevent a runaway agent from OOM-killing your host.

Image Strategy: Single vs. Multi-Container

For most deployments, a single container running the OpenClaw core engine is correct. The tools are Python libraries loaded in-process, not separate services. However, if you run a local LLM (Ollama, vLLM), that should be a separate container on the same Docker network. This separation lets you scale the LLM independently and swap inference backends without rebuilding OpenClaw.

Prerequisites & Environment Setup

Required Software

Component Minimum Version Notes
Docker Engine 24.0+ Includes Compose v2 plugin
Docker Compose 2.20+ docker compose (not docker-compose)
Git 2.30+ For cloning config templates
OpenClaw CLI Latest Only needed for config generation

Verify your Docker installation:

docker --version
docker compose version

Both commands should return version information without errors. If Docker is not installed, follow the official Docker Engine installation guide for your distribution before proceeding.

System Resource Recommendations

  • CPU: 2+ cores (4+ recommended for production)
  • RAM: 4GB minimum, 8GB recommended (LLM context processing is memory-intensive)
  • Disk: 10GB free (image + volumes for agent state)

For a dedicated self-hosting environment, I strongly recommend a VPS rather than your local workstation. Containerized agents that make outbound API calls and run scheduled tasks belong on an always-on server. If you need a reliable host, Start with Vultr Cloud VPS (Get $35 Credit) → offers excellent performance for Docker workloads. For a detailed comparison of hosting options, see our Best VPS for OpenClaw Self-Hosting in 2026 (Tested & Compared).

Directory Structure

Create a clean project directory to house your OpenClaw Docker deployment:

mkdir -p ~/openclaw-docker/{config,data,logs}
cd ~/openclaw-docker
  • config/: Mounted OpenClaw configuration files
  • data/: Persistent agent state and memory databases
  • logs/: Container output logs for debugging

Step-by-Step Implementation

Step 1: Generate Your OpenClaw Configuration

Before containerizing, you need a valid OpenClaw configuration file. The fastest way to generate one is using the official OpenClaw Config Generator, which produces a YAML file tailored to your LLM provider and tool selections. This visual tool eliminates syntax errors and ensures all required fields are present.

Alternatively, generate a baseline config via the CLI:

# Install OpenClaw CLI if not already present
curl -fsSL https://openclaw.ai/install.sh | bash

# Generate a default config
openclaw config init --output ./config/openclaw.yaml

Edit the generated config to set your LLM API keys and provider endpoints. A minimal config for OpenAI looks like:

# config/openclaw.yaml
engine:
  provider: openai
  model: gpt-4o
  api_key: ${OPENAI_API_KEY}  # Injected via environment variable

server:
  host: 0.0.0.0
  port: 8080

state:
  storage_path: /data/openclaw-state
  memory_backend: sqlite

tools:
  enabled:
    - filesystem
    - web_search
    - code_interpreter

Critical: Note the server.host: 0.0.0.0 setting. Inside a container, OpenClaw must bind to all interfaces so Docker's port forwarding can reach it. Binding to 127.0.0.1 will make the container unreachable from the host.

Step 2: Write the Dockerfile

Create a Dockerfile in your project directory. This multi-stage build keeps the final image lean by separating build dependencies from runtime dependencies:

# syntax=docker/dockerfile:1.4

# Stage 1: Build dependencies
FROM python:3.11-slim AS builder

WORKDIR /build

# Install build tools and native libraries required by OpenClaw's Python deps
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    libffi-dev \
    libssl-dev \
    git \
    && rm -rf /var/lib/apt/lists/*

# Install OpenClaw into a virtual environment to isolate dependencies
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Stage 2: Runtime image
FROM python:3.11-slim AS runtime

# Create non-root user for security
RUN groupadd -r openclaw && useradd -r -g openclaw -d /home/openclaw openclaw

# Copy the virtual environment from builder
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

# Create data directories with proper ownership
RUN mkdir -p /data /config /logs && \
    chown -R openclaw:openclaw /data /config /logs

# Switch to non-root user
USER openclaw

# Declare volumes for persistent state
VOLUME ["/data", "/config", "/logs"]

# Expose the OpenClaw API port
EXPOSE 8080

# Health check to verify the engine is responsive
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
    CMD curl -f http://localhost:8080/health || exit 1

# Default command
CMD ["openclaw", "serve", "--config", "/config/openclaw.yaml"]

Create the requirements.txt file:

openclaw>=1.0.0

Step 3: Create Docker Compose Configuration

Docker Compose simplifies orchestration, volume management, and environment variable injection. Create docker-compose.yml:

version: "3.8"

services:
  openclaw:
    build:
      context: .
      dockerfile: Dockerfile
    image: openclaw:latest
    container_name: openclaw-agent
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      - OPENAI_API_KEY=${OPENAI_API_KEY}
      - OPENCLAW_LOG_LEVEL=info
      - TZ=UTC
    volumes:
      - ./config:/config:ro
      - ./data:/data
      - ./logs:/logs
    networks:
      - openclaw-net
    deploy:
      resources:
        limits:
          memory: 4G
          cpus: "2.0"
        reservations:
          memory: 1G
          cpus: "0.5"
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

networks:
  openclaw-net:
    driver: bridge

Key configuration decisions explained:

  • restart: unless-stopped: Ensures the container restarts after host reboots or crashes, unless you explicitly stop it.
  • ./config:/config:ro: The config directory is mounted read-only. Configuration changes require a container restart, preventing runtime config drift.
  • deploy.resources.limits: Hard caps on memory and CPU prevent a misbehaving agent from exhausting host resources.
  • logging options: Rotate logs to prevent disk exhaustion from verbose agent output.

Step 4: Environment Variables

Create a .env file in the project root to store secrets. Never commit this file to version control.

# .env
OPENAI_API_KEY=sk-your-key-here

Add .env to your .gitignore:

echo ".env" >> .gitignore

Step 5: Build and Launch

Build the image and start the container:

docker compose build
docker compose up -d

Verify the container is running and healthy:

docker compose ps
docker compose logs -f openclaw

You should see log output indicating the OpenClaw engine started successfully and is listening on port 8080.

Step 6: Verify Functionality

Test the API endpoint from your host:

curl http://localhost:8080/health

Expected response: {"status": "ok"}

Send a test agent request:

curl -X POST http://localhost:8080/api/agents \
  -H "Content-Type: application/json" \
  -d '{"task": "Summarize the benefits of containerization in one sentence."}'

If you receive a valid response, your OpenClaw Docker installation is fully operational.

Production Best Practices & Security Hardening

1. Run as Non-Root User

The Dockerfile already creates and switches to the openclaw user. This is non-negotiable for production. A container running as root gives any compromised agent process full root access to the container, and potentially the host via volume mounts.

2. Read-Only Root Filesystem

For maximum security, run the container with a read-only root filesystem:

# In docker-compose.yml, under the openclaw service:
read_only: true
tmpfs:
  - /tmp

This prevents any process from writing to the container's filesystem layer. Only the mounted volumes (/data, /config, /logs) remain writable. Some OpenClaw tools may need /tmp for scratch space, hence the tmpfs mount.

3. Secret Management

Never hardcode API keys in your config file or Dockerfile. The current setup injects OPENAI_API_KEY via environment variables. For production, consider Docker Secrets:

secrets:
  openai_key:
    file: ./secrets/openai_key.txt

services:
  openclaw:
    secrets:
      - openai_key
    environment:
      - OPENAI_API_KEY_FILE=/run/secrets/openai_key

Then modify your OpenClaw config to read the key from the file path.

4. Network Isolation

If OpenClaw only needs outbound HTTPS access to LLM APIs, do not publish the port to the host network. Instead, use an internal network and access OpenClaw via a reverse proxy (nginx, Traefik) that handles TLS termination:

ports:
  - "127.0.0.1:8080:8080"  # Bind to localhost only

Then configure nginx on the host to proxy https://your-domain.com to 127.0.0.1:8080.

5. Regular Image Updates

OpenClaw releases frequently. Establish a weekly update cadence:

docker compose pull
docker compose up -d

For zero-downtime updates, use rolling deployments with multiple replicas behind a load balancer.

6. Backup Strategy

Your /data volume contains irreplaceable agent state. Implement automated backups:

# Cron job: nightly backup
0 2 * * * tar -czf /backups/openclaw-data-$(date +\%Y\%m\%d).tar.gz -C ~/openclaw-docker data

Store backups off-host (S3, another VPS) to protect against disk failure.

Troubleshooting & Common Pitfalls

Case 1: Container Exits Immediately with "Address already in use"

Error Output:

Error: [Errno 98] error while attempting to bind on address ('0.0.0.0', 8080): address already in use

Root Cause: Another process on the host (or another container) is already bound to port 8080.

Diagnosis:

# Check what is using port 8080
sudo lsof -i :8080
# Or with ss
ss -tulpn | grep 8080

Fix: Either stop the conflicting process or change the host-side port mapping:

ports:
  - "9090:8080"  # Host port 9090 maps to container port 8080

Case 2: Container Running but Health Check Fails

Error Output:

Health check failed: curl: (7) Failed to connect to localhost port 8080: Connection refused

Root Cause: The OpenClaw engine is still starting up, or it crashed after the container started. The start_period: 60s in the health check should cover slow startups, but if the engine crashes, the health check will never pass.

Diagnosis:

docker compose logs openclaw | tail -50

Look for Python tracebacks or configuration errors.

Common Fix: The config file has an invalid YAML syntax or references an unavailable model. Validate your config:

docker compose exec openclaw openclaw config validate --config /config/openclaw.yaml

Case 3: Agent Cannot Reach External APIs (DNS/Network Issues)

Error Output:

openai.error.APIConnectionError: Error communicating with OpenAI: HTTPSConnectionPool(host='api.openai.com', port=443): Max retries exceeded

Root Cause: The container cannot resolve external DNS names or the host firewall blocks outbound connections.

Diagnosis:

# Test DNS resolution inside the container
docker compose exec openclaw python -c "import socket; print(socket.gethostbyname('api.openai.com'))"

# Test outbound connectivity
docker compose exec openclaw curl -v https://api.openai.com

Fix: If DNS fails, check your host's /etc/docker/daemon.json for DNS settings:

{
  "dns": ["8.8.8.8", "1.1.1.1"]
}

Restart Docker after modifying this file. If you are behind a corporate proxy, you must configure HTTP_PROXY environment variables in the container.

Case 4: Permission Denied Writing to Data Volume

Error Output:

PermissionError: [Errno 13] Permission denied: '/data/openclaw-state'

Root Cause: The openclaw user inside the container (UID 999, typically) does not have write permissions on the host-mounted ./data directory.

Fix: Align the host directory ownership with the container user:

# Find the UID of the openclaw user in the container
docker compose exec openclaw id openclaw
# Output: uid=999(openclaw) gid=999(openclaw)

# Change host directory ownership
sudo chown -R 999:999 ~/openclaw-docker/data

For a more robust solution, use a named Docker volume instead of a bind mount:

volumes:
  openclaw-data:
    driver: local

services:
  openclaw:
    volumes:
      - openclaw-data:/data

Docker manages permissions on named volumes automatically.

Frequently Asked Questions

How do I update OpenClaw to the latest version in Docker?

To update, pull the latest base image and rebuild: run docker compose build --pull followed by docker compose up -d. This rebuilds the image with the newest OpenClaw package. Your persistent data in the ./data volume remains untouched. Always back up your data directory before major version upgrades.

Can I run multiple OpenClaw agents in separate containers?

Yes. Create separate Compose projects or use distinct service names with different host port mappings and separate data volumes. Each agent gets isolated state and resource limits. Use a shared Docker network if agents need to communicate with each other.

How do I connect OpenClaw Docker to a local Ollama instance?

If Ollama runs on the host, use host.docker.internal as the hostname in your OpenClaw config. Add extra_hosts: - "host.docker.internal:host-gateway" to your Compose service. Alternatively, run Ollama as a sibling container on the same Docker network and reference it by service name.

What is the recommended backup strategy for OpenClaw Docker data?

Back up the entire ./data directory daily using a cron job. Use tar to create compressed archives and store them off-host. For critical deployments, stop the container before backup to ensure a consistent state: docker compose stop && tar -czf backup.tar.gz data && docker compose start.

Does OpenClaw Docker support GPU acceleration for local models?

Yes, but only if you use the NVIDIA Container Toolkit. Install nvidia-container-toolkit, then add deploy.resources.reservations.devices with driver: nvidia to your Compose service. The base image must include CUDA libraries, so you will need a custom Dockerfile based on a CUDA-enabled Python image.

Related Guides & Resources

For visual configuration generation, use the OpenClaw Config Generator to create production-ready YAML files without syntax errors. When you need reliable cloud infrastructure for your Docker deployment, Start with Vultr Cloud VPS (Get $35 Credit) → and have your OpenClaw agent running in minutes.

OpenClaw Security & Deployment Brief

Get the weekly OpenClaw Security & Deployment Brief — malicious skill alerts, CVE breakdowns, cost optimization tips.

Related Articles