Skip to Content

How to Deploy OpenClaw on a VPS with Docker (Step-by-Step Guide)

Set up a fully self-hosted OpenClaw instance on any VPS using Docker and Docker Compose in under 30 minutes.

How to Deploy OpenClaw on a VPS with Docker (Step-by-Step Guide)

Set up a fully self-hosted OpenClaw instance on any VPS using Docker and Docker Compose in under 30 minutes.

OpenClaw is one of the fastest-growing open AI agent platforms right now. If you've been following the space, you know the ecosystem is heating up fast — even Microsoft is building OpenClaw-like agents of its own. But there's a strong case for self-hosting: full control over your data, no vendor lock-in, and the freedom to customize everything.

This guide walks you through a complete OpenClaw Docker VPS deploy — from a fresh server to a running, secured instance. No hand-waving. Real commands. Let's get into it.


Prerequisites

Before you touch the server, make sure you have these in place.

What You Need

  • A VPS running Ubuntu 22.04 LTS or Debian 12 (these instructions apply to both)
  • Minimum specs: 2 vCPU, 4 GB RAM, 40 GB SSD. 8 GB RAM recommended for production.
  • A non-root sudo user on the server
  • A domain name pointed at your VPS IP (for TLS)
  • SSH access to the server
  • Basic familiarity with the Linux terminal

VPS Providers That Work Well

Any major VPS provider works: DigitalOcean, Hetzner, Vultr, Linode, or AWS Lightsail. Hetzner offers great price-to-performance if you're cost-sensitive.


Step 1 — Prepare Your VPS

Log in and do a clean system update first. Never skip this on a fresh server.

ssh your-user@your-server-ip
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl git ufw

Configure the Firewall

Lock down the server before opening any ports. Allow only SSH, HTTP, and HTTPS.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw enable
sudo ufw status

Create a Dedicated User (Optional but Recommended)

Running OpenClaw under a dedicated system user limits blast radius if something goes wrong.

sudo useradd -m -s /bin/bash openclaw
sudo usermod -aG sudo openclaw
sudo su - openclaw

Step 2 — Install Docker and Docker Compose

Don't install Docker from the default Ubuntu apt repo — it's usually outdated. Use Docker's official install script instead.

Install Docker Engine

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
newgrp docker

Verify Docker Is Running

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

If hello-world completes without errors, Docker is installed correctly and you're ready to move on.


Step 3 — Configure and Deploy OpenClaw with Docker Compose

This is the core of the OpenClaw Docker VPS deploy. We'll use Docker Compose to define the full stack: the OpenClaw gateway, a PostgreSQL database, and a Redis cache.

Create the Project Directory

mkdir -p ~/openclaw && cd ~/openclaw

Write the docker-compose.yml

Create your Compose file with the following configuration. Replace the placeholder values with your own secrets.

cat > docker-compose.yml <<'EOF'
version: '3.9'

services:
  openclaw:
    image: openclaw/openclaw:latest
    container_name: openclaw_gateway
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://openclaw:${DB_PASSWORD}@db:5432/openclaw
      - REDIS_URL=redis://redis:6379
      - OPENCLAW_SECRET=${OPENCLAW_SECRET}
      - OPENCLAW_HOST=https://${DOMAIN}
    depends_on:
      - db
      - redis
    volumes:
      - openclaw_data:/app/data

  db:
    image: postgres:16-alpine
    container_name: openclaw_db
    restart: unless-stopped
    environment:
      - POSTGRES_USER=openclaw
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB=openclaw
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    container_name: openclaw_redis
    restart: unless-stopped
    volumes:
      - redis_data:/data

volumes:
  openclaw_data:
  postgres_data:
  redis_data:
EOF

Create the .env File

Never hardcode secrets in your Compose file. Use a .env file and add it to .gitignore immediately.

cat > .env <<'EOF'
DB_PASSWORD=change_this_to_a_strong_password
OPENCLAW_SECRET=change_this_to_a_random_64char_string
DOMAIN=openclaw.yourdomain.com
EOF

# Lock down permissions
chmod 600 .env

Generate a strong secret with: openssl rand -hex 32

Start the Stack

docker compose up -d
docker compose ps
docker compose logs -f openclaw

All three containers should show Up status. The gateway binds to 127.0.0.1:3000 — intentionally not exposed to the public internet yet. Nginx handles that next.


Step 4 — Set Up Nginx as a Reverse Proxy with TLS

You should never expose OpenClaw directly on port 3000. Nginx sits in front, terminates TLS, and proxies requests to the container.

Install Nginx and Certbot

sudo apt install -y nginx certbot python3-certbot-nginx
sudo systemctl enable nginx
sudo systemctl start nginx

Create the Nginx Site Config

Replace openclaw.yourdomain.com with your actual domain.

sudo tee /etc/nginx/sites-available/openclaw <<'EOF'
server {
    listen 80;
    server_name openclaw.yourdomain.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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_cache_bypass $http_upgrade;
        proxy_read_timeout 86400s;
    }
}
EOF

sudo ln -s /etc/nginx/sites-available/openclaw /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Issue a TLS Certificate

sudo certbot --nginx -d openclaw.yourdomain.com --non-interactive --agree-tos -m [email protected]
sudo systemctl reload nginx

Certbot automatically edits your Nginx config to add HTTPS and sets up auto-renewal. Verify with: sudo certbot renew --dry-run


Step 5 — Post-Install Configuration

The server is up. Now make it production-ready.

Run Database Migrations

OpenClaw ships with a migration command. Run it once after the first boot:

docker compose exec openclaw openclaw db migrate

Create Your Admin Account

docker compose exec openclaw openclaw admin create \
  --email [email protected] \
  --password your_secure_password

Configure API Keys

Add your LLM provider API keys through the OpenClaw gateway config or directly in .env:

# Add to your .env file, then restart the stack
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxx
OPENAI_API_KEY=sk-xxxxxxxxxxxx

# Restart to pick up new env vars
docker compose down && docker compose up -d

The AI agent ecosystem moves fast. It's worth noting that recent platform decisions — like Anthropic's OpenClaw suspension drama — highlight exactly why self-hosting matters: when you control the infrastructure, third-party policy changes don't take your deployment offline.

Enable Automatic Container Restarts

The restart: unless-stopped policy in the Compose file already handles container-level restarts. To survive full server reboots, enable Docker's systemd service:

sudo systemctl enable docker
sudo systemctl status docker

Step 6 — Keeping OpenClaw Updated

Docker makes updates clean. Pull the latest image, recreate the container, run any new migrations.

cd ~/openclaw
docker compose pull
docker compose up -d --remove-orphans
docker compose exec openclaw openclaw db migrate
docker image prune -f

That's it. No package manager conflicts, no dependency hell. This is one of the biggest practical advantages of containerized deployments.

Automate Updates with a Cron Job (Optional)

If you want nightly pulls, add a cron entry. But for production, manual updates give you more control:

# Add to crontab with: crontab -e
# Pull and restart every Sunday at 2am
0 2 * * 0 cd ~/openclaw && docker compose pull && docker compose up -d --remove-orphans >> ~/openclaw/update.log 2>&1

Step 7 — Backups

Backups aren't optional. At minimum, back up the Postgres volume daily.

Database Backup Script

#!/bin/bash
# Save as ~/openclaw/backup.sh and chmod +x it

BACKUP_DIR=~/openclaw/backups
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR

docker compose -f ~/openclaw/docker-compose.yml exec -T db \
  pg_dump -U openclaw openclaw | gzip > "$BACKUP_DIR/openclaw_$TIMESTAMP.sql.gz"

# Keep only the last 7 days
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete

echo "Backup complete: openclaw_$TIMESTAMP.sql.gz"
chmod +x ~/openclaw/backup.sh

# Schedule daily at 3am
(crontab -l 2>/dev/null; echo "0 3 * * * ~/openclaw/backup.sh") | crontab -

Tips and Troubleshooting

Here are the most common issues people hit during an OpenClaw Docker VPS deploy and how to fix them fast.

Container Won't Start — Check Logs First

# View all container logs
docker compose logs

# Tail a specific service
docker compose logs -f openclaw
docker compose logs -f db

Port 3000 Already in Use

Something else is bound to port 3000. Find it and kill it, or change the host port in your Compose file:

sudo lsof -i :3000
# Change the port mapping in docker-compose.yml if needed:
# "127.0.0.1:3001:3000"

Database Connection Refused

Make sure the db service is fully healthy before OpenClaw tries to connect. Add a healthcheck to the Compose file if startup ordering is causing issues:

# Check if postgres is accepting connections
docker compose exec db pg_isready -U openclaw

Nginx 502 Bad Gateway

This almost always means the OpenClaw container isn't running or isn't listening on port 3000 inside the container. Check:

  1. Run docker compose ps — all services should be Up
  2. Run curl http://127.0.0.1:3000 from the server — should return a response
  3. Check Nginx config: sudo nginx -t

TLS Certificate Issues

Make sure your domain's DNS A record actually points to your server IP before running Certbot. Let's Encrypt validates by hitting port 80 on your domain.

# Check DNS resolution
dig +short openclaw.yourdomain.com

# Test renewal
sudo certbot renew --dry-run

Out of Memory

If containers are getting OOM-killed, check with docker stats. If you're on a 2 GB VPS, consider adding a swap file:

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Pro Tips

  • Pin image versions in production. openclaw/openclaw:latest is fine for getting started, but pin to a specific version tag (e.g., :1.4.2) once you're stable.
  • Use a managed database for high-availability setups. Self-hosting Postgres is fine for small deployments, but for serious production use, consider a managed Postgres service.
  • Monitor with Uptime Kuma. It's lightweight, Docker-native, and takes 5 minutes to set up on the same VPS.
  • Rate-limit the Nginx proxy if you're exposing OpenClaw to the public internet. A simple limit_req_zone directive goes a long way.

As AI agent platforms mature, enterprise deployments are getting more sophisticated — even Microsoft is testing OpenClaw-style agents for enterprise security controls. A solid self-hosted foundation like this one puts you in a position to scale confidently.


What You've Built

Here's a quick recap of what's running:

  • ✅ OpenClaw gateway running in a Docker container
  • ✅ PostgreSQL database with persistent storage
  • ✅ Redis cache for session and queue handling
  • ✅ Nginx reverse proxy with auto-renewing TLS
  • ✅ UFW firewall with minimal attack surface
  • ✅ Automated daily database backups
  • ✅ Container auto-restart on reboot

You now have a self-hosted OpenClaw deployment that you control entirely. No cloud platform surprises, no data leaving your infrastructure, and full freedom to extend and customize.


Need Help Scaling This for Your Team?

This guide covers a solid single-node production deployment. If you're looking at multi-node setups, enterprise SSO integration, custom agent pipelines, or managed OpenClaw hosting for your organization — the Sysbrix team can help.

Talk to us about enterprise OpenClaw deployments →

Windmill Self-Host Setup: Git Sync, Worker Groups, App Builder, and Enterprise Workflow Patterns
A practical developer guide to unlocking Windmill's advanced self-hosted features — version-controlled scripts, isolated worker pools, low-code apps, and the workflow patterns that scale to production teams.