OpenClaw Docker Installation Tutorial
Master OpenClaw Docker installation with production-grade steps, Docker Compose configs, security hardening, and troubleshooting for self-hosted AI agents.
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:
-
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.
-
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.
-
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 filesdata/: Persistent agent state and memory databaseslogs/: 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.loggingoptions: 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
- How to Run OpenClaw Locally: Quickstart & Local Development Guide — Master the fundamentals before containerizing.
- OpenClaw Installation Errors and Fixes: Complete Troubleshooting Guide — Deep dive into common installation failures beyond Docker.
- Best OpenClaw Tools for Beginners — Curated list of tools to extend your containerized agent.
- Best VPS for OpenClaw Self-Hosting in 2026 (Tested & Compared) — Find the right infrastructure for your deployment.
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.