What You'll End Up With
- OpenClaw running on a $5 VPS with 512MB RAM headroom
- SSH key-only authentication (no password logins)
- UFW firewall allowing only ports 22, 80, 443
- fail2ban blocking brute-force attempts
- Automatic security updates
- systemd service that auto-restarts on crash
- Log rotation so disks don't fill up
- Resource limits so OpenClaw can't eat all RAM
Prerequisites
- A VPS running Ubuntu 24.04 LTS (tested on Hetzner CX22)
- Your local SSH public key
- A domain pointing to your VPS IP (optional, for HTTPS)
Never run commands you don't understand. Every command below is explained. If something breaks, check the troubleshooting section.
Step 1: Initial SSH Hardening
SSH into your new VPS as root:
ssh root@YOUR_VPS_IP
1a. Create a non-root user
adduser --gecos "" openclaw
usermod -aG sudo openclaw
1b. Copy your SSH key
From your local machine:
ssh-copy-id openclaw@YOUR_VPS_IP
1c. Disable password authentication
sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^#*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
systemctl restart sshd
Verify: Open a new terminal and SSH in as
openclaw. If it works and ssh root@YOUR_VPS_IP is refused, you're good.Step 2: Firewall
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw --force enable
Verify:
sudo ufw status should show only 22, 80, 443 allowed.Step 3: fail2ban
sudo apt update && sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban
Default config bans after 5 failed SSH attempts for 10 minutes.
Step 4: Automatic Security Updates
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
# Select "Yes" when prompted
Step 5: Install Node.js
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
node --version # Should show v22.x.x
Step 6: Install OpenClaw
sudo npm install -g openclaw
6a. Create the config directory
sudo mkdir -p /etc/openclaw
sudo chown openclaw:openclaw /etc/openclaw
6b. Create the workspace directory
sudo mkdir -p /opt/openclaw/workspace
sudo chown openclaw:openclaw /opt/openclaw/workspace
Step 7: Resource Limits
Create a systemd override to cap memory at 3.5GB (leaves 500MB for the OS):
sudo mkdir -p /etc/systemd/system/openclaw.service.d
sudo tee /etc/systemd/system/openclaw.service.d/limits.conf <<'EOF'
[Service]
MemoryHigh=3G
MemoryMax=3500M
CPUQuota=150%
EOF
Step 8: systemd Service
sudo tee /etc/systemd/system/openclaw.service <<'EOF'
[Unit]
Description=OpenClaw AI Agent
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=openclaw
Group=openclaw
WorkingDirectory=/opt/openclaw/workspace
Environment=NODE_ENV=production
Environment=HOME=/home/openclaw
ExecStart=/usr/bin/node /usr/lib/node_modules/openclaw/dist/index.js
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=openclaw
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/etc/openclaw /opt/openclaw/workspace /home/openclaw
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable openclaw
sudo systemctl start openclaw
Verify:
sudo systemctl status openclaw should show "active (running)".Step 9: Log Rotation
sudo tee /etc/logrotate.d/openclaw <<'EOF'
/var/log/openclaw/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 openclaw openclaw
}
EOF
Step 10: HTTPS with Caddy
sudo apt install -y caddy
Edit /etc/caddy/Caddyfile:
yourdomain.com {
reverse_proxy localhost:3000
}
sudo systemctl restart caddy
Caddy automatically provisions Let's Encrypt certificates. No certbot needed.
Verification Checklist
| Check | Command | Expected |
|---|---|---|
| Service running | systemctl is-active openclaw | active |
| Password SSH disabled | ssh -o PasswordAuthentication=yes root@IP | Permission denied |
| Root login disabled | ssh root@IP | Permission denied |
| Firewall active | sudo ufw status | Only 22/80/443 |
| fail2ban running | sudo systemctl is-active fail2ban | active |
| Memory limit set | systemctl show openclaw | grep MemoryMax | 3500M |
Troubleshooting
"Cannot find module" errors
which openclaw
ls /usr/lib/node_modules/openclaw/dist/
Service crashes on start
sudo journalctl -u openclaw -n 50 --no-pager
Out of memory (OOM kills)
free -h
If total is under 2GB, upgrade to a 4GB VPS.
Caddy won't get certificates
- Make sure DNS points to your VPS IP
- Make sure port 80 is open:
sudo ufw allow 80/tcp - Check logs:
sudo journalctl -u caddy -n 20
Hardening Extras (Optional)
Swap file (2GB safety net)
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
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Rate-limit SSH further
Add to /etc/ssh/sshd_config:
MaxAuthTries 3
LoginGraceTime 30
Then sudo systemctl restart sshd.