Skip to Content

OpenClaw Docker VPS Deploy: A Developer's Step-by-Step Guide

Get OpenClaw running on your own VPS with Docker Compose, secure domain access, and messaging channels configured in under 30 minutes.

Running OpenClaw on your own VPS gives you full control over your AI agent gateway. No dependencies on third-party hosted services, no usage limits you did not choose, and complete data sovereignty. This guide covers a clean Docker-based deployment on a fresh Ubuntu VPS — from first SSH login to a working gateway with Telegram or Discord integration.

If you want the fastest possible path to a running gateway, see our 30-minute quick-start. For a deeper walkthrough with security hardening, check the step-by-step deployment guide. This post sits in the middle: complete enough to follow without guessing, concise enough to finish in one sitting.

What You Need Before Starting

Gather these before you open a terminal:

  • A VPS with at least 2 vCPUs, 4 GB RAM, and 20 GB SSD (Ubuntu 22.04 or 24.04 LTS)
  • A domain or subdomain with DNS A record pointing to your VPS IP
  • Docker Engine 24.x+ and Docker Compose v2 installed
  • A valid TLS certificate (Let's Encrypt via certbot works)
  • At least one AI provider API key (OpenAI, Anthropic, or a local Ollama instance)
  • Optional: Telegram bot token or Discord bot token for messaging channels

OpenClaw builds from source during setup if you do not use a pre-built image. The build process can consume significant RAM, so the 4 GB minimum is not negotiable.

Server Preparation and Docker Setup

Start with a clean server. Update packages, install Docker, and add your user to the docker group:

sudo apt update && sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg

# Add Docker's official GPG key and repository
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# Add current user to docker group
sudo usermod -aG docker $USER
newgrp docker

Verify Docker is working before proceeding:

docker --version
docker compose version
docker run --rm hello-world

Cloning and Building OpenClaw

Create a directory for OpenClaw and clone the repository:

sudo mkdir -p /opt/openclaw
sudo chown $USER:$USER /opt/openclaw
cd /opt/openclaw

git clone https://github.com/openclaw/openclaw.git .
git checkout main

Run the Docker setup script. It builds the gateway image, runs onboarding, and starts the container:

./scripts/docker/setup.sh

If you prefer a pre-built image instead of building locally:

export OPENCLAW_IMAGE="ghcr.io/openclaw/openclaw:latest"
./scripts/docker/setup.sh

The setup script prompts for your AI provider API key, generates a gateway token, and writes configuration to .env. Keep that token secure — it is your admin access to the Control UI.

Domain Configuration and Reverse Proxy

The gateway listens on port 18789 by default. For production, put it behind a reverse proxy with HTTPS. Here is a minimal NGINX configuration:

server {
    listen 80;
    server_name openclaw.example.com;
    return 301 https://\$server_name\$request_uri;
}

server {
    listen 443 ssl http2;
    server_name openclaw.example.com;

    ssl_certificate /etc/letsencrypt/live/openclaw.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/openclaw.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:18789;
        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;

        proxy_buffering off;
        proxy_read_timeout 300s;
    }

    location /ws {
        proxy_pass http://127.0.0.1:18789;
        proxy_http_version 1.1;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Obtain certificates and reload NGINX:

sudo certbot --nginx -d openclaw.example.com
sudo systemctl reload nginx

Now open https://openclaw.example.com in your browser and paste the gateway token from .env into the Settings panel.

Configuring Messaging Channels

OpenClaw supports WhatsApp, Telegram, and Discord out of the box. Use the CLI container to add channels without touching config files directly.

Telegram

docker compose run --rm openclaw-cli channels add \
  --channel telegram \
  --token "YOUR_BOT_TOKEN"

Discord

docker compose run --rm openclaw-cli channels add \
  --channel discord \
  --token "YOUR_BOT_TOKEN"

After adding a channel, send a test message to verify the bot responds. Check logs if messages are not reaching the gateway:

docker compose logs --tail 50 openclaw-gateway

Health Checks and Monitoring

OpenClaw exposes unauthenticated health endpoints for container orchestration:

curl -fsS http://127.0.0.1:18789/healthz   # liveness
curl -fsS http://127.0.0.1:18789/readyz    # readiness

The Docker image includes a built-in HEALTHCHECK that pings /healthz. If the gateway becomes unresponsive, Docker marks the container unhealthy and can trigger automatic restarts.

For deeper diagnostics, run the authenticated health snapshot:

docker compose exec openclaw-gateway \
  node dist/index.js health \
  --token "$OPENCLAW_GATEWAY_TOKEN"

Tips and Troubleshooting

Build fails with exit 137

This is an out-of-memory kill. The local build needs at least 2 GB free RAM during pnpm install and the TypeScript compilation step. Upgrade your VPS or use a pre-built image:

export OPENCLAW_IMAGE="ghcr.io/openclaw/openclaw:latest"
./scripts/docker/setup.sh

Cannot reach the Control UI from outside the server

Verify the gateway bind mode. The setup script defaults to lan, which publishes port 18789 on all interfaces. If you changed it to loopback, only processes inside the container can reach it directly. Check .env for OPENCLAW_GATEWAY_BIND.

Local AI providers are unreachable

Inside the Docker container, 127.0.0.1 refers to the container itself, not the host. Use host.docker.internal for Ollama or LM Studio running on the host:

# For Ollama on the host
OLLAMA_HOST=0.0.0.0:11434 ollama serve

# In OpenClaw config, use
# http://host.docker.internal:11434

Channel messages are not received

Confirm your bot token is valid and the bot has permissions to read messages in the target channel. For Telegram, start a conversation with the bot first — it cannot message users who have not interacted with it.

Config changes do not persist after restart

Ensure the OPENCLAW_CONFIG_DIR and OPENCLAW_HOME_VOLUME mounts are active. Without a named volume or bind mount, container restarts wipe all state. The setup script configures these by default, but custom Compose files may omit them.

Logs are growing without bound

Configure Docker log rotation to prevent disk exhaustion:

# /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Next Steps

You now have a self-hosted OpenClaw gateway running on your VPS with Docker, accessible over HTTPS, and connected to messaging channels. From here you can add custom agents, integrate additional AI providers, and build automated workflows that run entirely on your infrastructure.

For more detailed guidance, explore our related posts:

Need help with production hardening, multi-agent orchestration, or integrating OpenClaw with your existing infrastructure? Contact our team for enterprise OpenClaw consulting and managed deployment services.

Vaultwarden Bitwarden Self-Host: Production Deployment with Docker Compose, NGINX, and PostgreSQL
Build a hardened, production-ready password manager using Vaultwarden with an external PostgreSQL database and NGINX reverse proxy on Ubuntu.