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:
- Run
docker compose ps— all services should beUp - Run
curl http://127.0.0.1:3000from the server — should return a response - 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:latestis 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_zonedirective 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.