Back to Runbook
🖥️ Chapter 5

VPS Deployment

Full Hetzner setup with Tailscale SSH, firewall hardening, backup scripts, systemd service management, and a production security checklist. You don't need a large machine.

📖 14 min read🔧 12 sections

Running on a VPS

If you want to run OpenClaw on a VPS, you don't need a large machine. A Hetzner CX23 is plenty.

I'd strongly recommend Tailscale on both your local machine and the VPS. Install it on the VPS with the --ssh=true flag and you can log in over Tailscale directly. Then block port 22 entirely in the Hetzner firewall.

I block all inbound traffic and access everything over Tailscale. Simple setup, and one less thing to worry about.

Hardware requirements

Minimum VPS Specs — Hetzner CX23 or equivalent
vCPUs2
RAM4 GB
Disk40 GB
Monthly cost~$5/mo

Network security with Tailscale

🚨

CRITICAL: Follow this order exactly to avoid lockout.

Step 1: Install Tailscale on local machine

Local Machine
# On your local machine (Mac/Linux/Windows)
# Visit: https://tailscale.com/download
# Install and authenticate

Step 2: Install Tailscale on VPS

VPS
# SSH into VPS normally first
ssh user@your-vps-ip

# Install Tailscale
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --ssh=true

The --ssh=true flag enables SSH over Tailscale.

Step 3: Get VPS Tailscale IP

VPS
# On VPS, get your Tailscale IP
tailscale ip -4
# Example output: 100.64.1.2

Step 4: TEST SSH via Tailscale

⚠️

CRITICAL: Do NOT skip this step. If Tailscale SSH fails, DO NOT proceed. Debug Tailscale first.

Local Machine
# Use the Tailscale IP, NOT your public IP
ssh user@100.64.1.2

Step 5: Block public access (only after verification)

Hetzner Firewall (Web UI)
# 1. Create new firewall rule
# 2. Block: All inbound traffic on port 22
# 3. Leave Tailscale traffic unrestricted (100.64.0.0/10)

Step 6: Verify lockout prevention

Verification
# This should work (Tailscale)
ssh user@100.64.1.2

# This should fail/timeout (public IP blocked)
ssh user@your-public-vps-ip
🛟

Safety net: Most VPS providers (Hetzner, DigitalOcean, Linode) offer web-based console access as a last resort if you lock yourself out. Find this BEFORE making firewall changes.

OpenClaw installation

After installing OpenClaw, run these commands before doing anything else:

bash
# Validate config and auto-fix common issues
openclaw doctor --fix

# Run a deep security scan
openclaw security audit --deep

The security audit should return zero critical issues. A couple of warnings is normal:

  • gateway.trusted_proxies_missing — ok if localhost-only
  • fs.credentials_dir.perms_readable — fix with chmod

File permissions

Lock down the config directory:

bash
chmod 700 ~/.openclaw
chmod 600 ~/.openclaw/openclaw.json
chmod 700 ~/.openclaw/credentials

This prevents other users on the system from reading your config or API keys.

Gateway binding

Verify the gateway is binding to localhost and not exposed to the public internet:

bash
netstat -an | grep 18789 | grep LISTEN
# You want to see: 127.0.0.1:18789
# You do NOT want: 0.0.0.0:18789
✅ Correct
127.0.0.1:18789

Only localhost can reach the gateway

❌ Dangerous
0.0.0.0:18789

Anyone who can reach port 18789 can talk to your agent

Fix it in config:

openclaw.json
"gateway": {
  "bind": "loopback"
}

Hardening configuration

Logging with redaction

openclaw.json
"logging": {
  "redactSensitive": "tools"
}
"off"No redaction (dangerous)
"tools"Redact tool output (recommended)
"all"Aggressive redaction (harder debugging)

Tool policies

Restrict which tools agents can use:

openclaw.json
"tools": {
  "profile": "minimal",
  "deny": ["exec"],
  "allow": ["web_search", "web_fetch", "read"]
}
Tool Profiles
minimalOnly session_status (most restrictive)
codingFile system, runtime, sessions, memory
messagingMessaging tools only
fullNo restrictions (default)

Sandbox mode (optional)

If you want containerized execution (requires Docker):

openclaw.json
"agents": {
  "defaults": {
    "sandbox": {
      "enabled": true,
      "image": "openclaw-sandbox"
    }
  }
}

Useful if running on a shared VPS and want agent work isolated.

Git-track your config

Git-track the OpenClaw config directory for rollback capability:

bash — Initial setup
cd ~/.openclaw && git init
printf 'agents/*/sessions/\nagents/*/agent/*.jsonl\n*.log\n' > .gitignore
git add .gitignore openclaw.json
git commit -m "config: baseline"
bash — Before/after changes
# Before making changes
git commit -am "config: before model update"

# Make your changes
vim openclaw.json

# Test and commit
openclaw doctor --fix
git commit -am "config: switched to Gemini 3 Flash"

When something breaks at midnight, git diff and git checkout are faster than trying to remember what you changed.

Validation workflow

After any config change:

1

Validate

openclaw doctor --fix
2

Security audit

openclaw security audit --deep
3

Test

openclaw status + send a test message
4

Commit

git commit -am "config: description of change"

System monitoring

bash
# Check OpenClaw status
openclaw status

# Check for errors in logs
tail -100 ~/.openclaw/gateway.log | grep -i error

# Check system resources
htop

Consider adding a cron job or heartbeat check for failed jobs and error logs — see the Heartbeat & Task Tracking chapter.

Backup strategy

✅ What to backup
  • ~/.openclaw/openclaw.json
  • ~/.openclaw/credentials/
  • ~/.openclaw/workspace/
⏭️ Skip these
  • • Session logs (recreated)
  • • Agent state (regenerated)
  • • Log files (ephemeral)

Backup script

Create ~/bin/backup-openclaw.sh:

bash — backup-openclaw.sh
#!/bin/bash
# OpenClaw backup script
BACKUP_DIR=~/backups
DATE=$(date +%Y-%m-%d)

# Create backup directory if it doesn't exist
mkdir -p $BACKUP_DIR

# Create backup
tar czf $BACKUP_DIR/openclaw-$DATE.tar.gz \
  ~/.openclaw/openclaw.json \
  ~/.openclaw/credentials \
  ~/.openclaw/workspace

# Keep only last 7 days of backups
find $BACKUP_DIR -name "openclaw-*.tar.gz" -mtime +7 -delete

# Log completion
echo "$(date): Backup completed - openclaw-$DATE.tar.gz" >> $BACKUP_DIR/backup.log
bash — Cron schedules
chmod +x ~/bin/backup-openclaw.sh
crontab -e

# Daily at 3 AM
0 3 * * * ~/bin/backup-openclaw.sh

# Every 6 hours
0 */6 * * * ~/bin/backup-openclaw.sh

# Weekly on Sunday at 2 AM
0 2 * * 0 ~/bin/backup-openclaw.sh

Service management

The OpenClaw wizard automatically sets up a systemd user service on Linux (or launchd on macOS) during installation. No manual configuration needed.

bash
# Check service status
openclaw status
# or
systemctl --user status openclaw

# Manage the service
openclaw gateway start
openclaw gateway stop
openclaw gateway restart

Get things stable before going 24/7

Don't run OpenClaw 24/7 until you've ironed out the basics. Get your config right, get your agents stable, get your costs predictable. Then let it run.

I've seen people jump to 24/7 operation on day one and end up with a bot that burns $50 in API calls overnight because a retry loop went sideways.

Troubleshooting

Tailscale SSH not working

sudo tailscale status
sudo tailscale status | grep ssh
sudo tailscale up --ssh=true

Can't find Tailscale IP

tailscale ip -4    # IPv4
tailscale ip -6    # IPv6
hostname           # Machine name on Tailscale network

Locked out after firewall change

  1. 1. Use provider's web console (Hetzner Console, DigitalOcean Droplet Console)
  2. 2. Log in through web interface
  3. 3. Fix firewall rules or re-enable Tailscale
  4. 4. Test Tailscale SSH before closing console

Gateway won't start

openclaw doctor --fix
openclaw gateway stop
openclaw gateway start

Port already in use

lsof -i :18789
# Kill the process or change the port in config

Pre-production security checklist

Before running OpenClaw in production
File permissions locked down (700/600)
Gateway binds to localhost only
openclaw security audit --deep returns zero critical issues
Tailscale configured, SSH blocked at firewall
Logging redaction enabled
Tool policies configured
Config git-tracked
Backup strategy in place

Cost optimization

Running on a VPS doesn't mean expensive:

  • Hetzner CX23: ~$5/month
  • Cheap model for heartbeat (GPT-5 nano)
  • Cross-provider fallbacks to avoid quota burnout
  • Concurrency limits to prevent runaway costs

See the Agent Prompts chapter for model configuration strategies.