Skip to main content
Deploy better-openclaw stacks to any VPS provider (DigitalOcean, Linode, Vultr, Hetzner, AWS EC2, etc.) with Docker or bare-metal.

Prerequisites

  • VPS with 2GB+ RAM (varies by preset)
  • Ubuntu 22.04+ or Debian 11+ (recommended)
  • Root or sudo access
  • Public IP address
  • SSH key authentication (recommended)

Server sizing guide

Choose a VPS size based on your preset:
PresetRAMCPUDiskCost/month
Minimal1 GB1 vCPU25 GB$5-10
Creator2 GB2 vCPU50 GB$10-20
Researcher4 GB2 vCPU80 GB$20-40
DevOps4 GB2 vCPU80 GB$20-40
AI Playground8 GB4 vCPU160 GB$40-80
Full Stack8 GB4 vCPU160 GB$40-80

Initial server setup

1

Create VPS

Create a VPS with your preferred provider:DigitalOcean:
doctl compute droplet create openclaw \
  --region nyc3 \
  --size s-2vcpu-4gb \
  --image ubuntu-22-04-x64 \
  --ssh-keys YOUR_KEY_ID
Hetzner:
hcloud server create \
  --name openclaw \
  --type cx21 \
  --image ubuntu-22.04 \
  --ssh-key YOUR_KEY_NAME
2

SSH into server

Connect to your VPS:
ssh root@YOUR_SERVER_IP
3

Update system

Update packages and install essentials:
apt update && apt upgrade -y
apt install -y curl git ufw
4

Configure firewall

Set up UFW firewall:
# Allow SSH
ufw allow 22/tcp

# Allow HTTP/HTTPS (if using reverse proxy)
ufw allow 80/tcp
ufw allow 443/tcp

# Enable firewall
ufw --force enable

Docker deployment

Install Docker

1

Install Docker Engine

curl -fsSL https://get.docker.com | sh
2

Enable Docker service

systemctl enable docker
systemctl start docker
3

Verify installation

docker --version
docker compose version

Deploy stack

1

Generate stack locally

On your local machine:
npx create-better-openclaw@latest \
  --preset researcher \
  --proxy caddy \
  --domain example.com \
  --yes
2

Transfer to VPS

Upload the generated stack:
rsync -avz ./my-openclaw-stack root@YOUR_SERVER_IP:/opt/openclaw
3

Configure environment

SSH into the server and edit .env:
ssh root@YOUR_SERVER_IP
cd /opt/openclaw
nano .env
Update:
  • Domain names
  • API keys
  • Database passwords
  • Email settings (for Let’s Encrypt)
4

Start services

Launch the stack:
docker compose up -d
Monitor logs:
docker compose logs -f

Bare-metal deployment

Install dependencies

1

Install Docker

curl -fsSL https://get.docker.com | sh
systemctl enable docker
systemctl start docker
2

Generate stack with bare-metal mode

On your local machine:
npx create-better-openclaw@latest \
  --preset researcher \
  --deployment-mode bare-metal \
  --yes
3

Transfer to VPS

Upload the stack:
rsync -avz ./my-openclaw-stack root@YOUR_SERVER_IP:/opt/openclaw
4

Run installer

SSH into the server and run the installer:
ssh root@YOUR_SERVER_IP
cd /opt/openclaw
chmod +x install.sh
./install.sh
This will:
  • Install native services (Redis, etc.)
  • Configure systemd units
  • Start native services
  • Launch Docker containers for remaining services

DNS configuration

Point your domain to the VPS:
1

Create A record

In your DNS provider, create an A record:
TypeNameValueTTL
A@YOUR_SERVER_IP300
2

Create CNAME for subdomains (optional)

For service-specific subdomains:
TypeNameValueTTL
CNAMEgrafanaexample.com300
CNAMEn8nexample.com300
3

Verify DNS propagation

Check DNS resolution:
dig example.com +short
dig grafana.example.com +short

SSL/TLS configuration

Caddy (automatic)

Caddy automatically provisions Let’s Encrypt certificates. No additional configuration needed. Verify:
curl -I https://example.com

Traefik (automatic)

Traefik provisions certificates when traefik.http.routers.<service>.tls.certresolver=letsencrypt is set. Verify in Traefik dashboard:
open http://YOUR_SERVER_IP:8080

Manual (Certbot)

For custom SSL setup:
# Install Certbot
apt install -y certbot

# Generate certificate
certbot certonly --standalone -d example.com

# Certificates saved to:
# /etc/letsencrypt/live/example.com/fullchain.pem
# /etc/letsencrypt/live/example.com/privkey.pem
Update docker-compose.yml to mount certificates:
services:
  caddy:
    volumes:
      - /etc/letsencrypt:/etc/letsencrypt:ro

Security hardening

Disable root SSH

1

Create non-root user

adduser openclaw
usermod -aG sudo openclaw
usermod -aG docker openclaw
2

Copy SSH key

mkdir -p /home/openclaw/.ssh
cp ~/.ssh/authorized_keys /home/openclaw/.ssh/
chown -R openclaw:openclaw /home/openclaw/.ssh
chmod 700 /home/openclaw/.ssh
chmod 600 /home/openclaw/.ssh/authorized_keys
3

Disable root login

Edit SSH config:
nano /etc/ssh/sshd_config
Set:
PermitRootLogin no
PasswordAuthentication no
Restart SSH:
systemctl restart sshd

Enable automatic updates

# Install unattended-upgrades
apt install -y unattended-upgrades

# Enable automatic security updates
dpkg-reconfigure -plow unattended-upgrades

Install fail2ban

Protect against brute-force attacks:
apt install -y fail2ban
systemctl enable fail2ban
systemctl start fail2ban

Monitoring and maintenance

System monitoring

If you included Grafana and Prometheus in your stack:
  1. Access Grafana at https://grafana.example.com
  2. Login with credentials from .env
  3. View pre-configured dashboards for system metrics

Log management

View service logs:
# Docker services
docker compose logs -f

# Native services
journalctl -u redis -f
Rotate logs to prevent disk overflow:
# Configure Docker log rotation
nano /etc/docker/daemon.json
Add:
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
Restart Docker:
systemctl restart docker

Backup strategy

1

Identify data volumes

List Docker volumes:
docker volume ls
2

Create backup script

nano /opt/openclaw/backup.sh
Add:
#!/bin/bash
BACKUP_DIR="/backup/openclaw-$(date +%F)"
mkdir -p $BACKUP_DIR

# Backup Docker volumes
docker run --rm -v postgres-data:/data -v $BACKUP_DIR:/backup \
  alpine tar czf /backup/postgres.tar.gz -C /data .

docker run --rm -v redis-data:/data -v $BACKUP_DIR:/backup \
  alpine tar czf /backup/redis.tar.gz -C /data .

# Backup .env
cp /opt/openclaw/.env $BACKUP_DIR/

echo "Backup complete: $BACKUP_DIR"
Make executable:
chmod +x /opt/openclaw/backup.sh
3

Schedule daily backups

Add to crontab:
crontab -e
Add:
0 2 * * * /opt/openclaw/backup.sh

Update stack

Update services to latest versions:
cd /opt/openclaw

# Pull latest images
docker compose pull

# Recreate containers
docker compose up -d --force-recreate

# Clean up old images
docker image prune -a -f

Scaling considerations

Vertical scaling

Increase VPS resources:
  1. Resize VPS via provider dashboard
  2. Restart VPS
  3. Verify new resources:
    free -h
    lscpu
    

Horizontal scaling

For high availability, use:
  • Load balancer: Distribute traffic across multiple VPS instances
  • Shared database: External PostgreSQL (e.g., AWS RDS, DigitalOcean Managed DB)
  • Shared cache: External Redis (e.g., Redis Cloud, AWS ElastiCache)
  • Object storage: External MinIO or S3-compatible storage
Or migrate to Dokploy or Coolify for built-in orchestration.

Troubleshooting

Services won’t start

Check logs:
docker compose logs <service-name>
Common issues:
  • Port conflicts: lsof -i :<port>
  • Insufficient memory: free -h
  • Missing environment variables: cat .env

SSL certificate errors

Error: Certificate provisioning failed Solution:
  1. Verify DNS points to server IP: dig example.com +short
  2. Ensure ports 80 and 443 are open: ufw status
  3. Check Caddy/Traefik logs: docker compose logs caddy

Disk space issues

Check disk usage:
df -h
Clean up Docker:
docker system prune -a --volumes
Resize disk via provider dashboard if needed.

Connection refused

Error: Cannot connect to services Solution:
  1. Verify services are running: docker compose ps
  2. Check firewall rules: ufw status
  3. Test locally first: curl http://localhost:3000
  4. Verify DNS: dig example.com

Provider-specific guides

DigitalOcean

Hetzner

Vultr

Linode

Next steps

Build docs developers (and LLMs) love