"Just use a VPS. It's like a one-click install." This is the advice you'll hear from every forum, every Discord server, and every tutorial. And it's technically true — in the same way that cooking dinner is just "applying heat to food." The OpenClaw installation itself is straightforward. Everything that comes before it is where people get destroyed.
I've set this up multiple times, helped others do the same, and watched enough people brick their servers or get compromised within hours to know that the "just spin up a VPS" advice is dangerously incomplete. This guide covers every step from a fresh server to a running OpenClaw instance, with security treated as a first-class concern — not an afterthought.
Before you begin
This guide assumes Ubuntu 22.04+ on a cloud VPS (DigitalOcean, Hetzner, Linode, Vultr — any provider works). You'll need: 1 vCPU, 4 GB RAM, 100 GB storage, and a terminal with SSH access. Total cost: roughly $6–24/month depending on provider.
Why security comes first
The moment your VPS gets a public IP address, it's under attack. This is not hyperbole. Within seconds of provisioning, automated scanners will find your server and begin attempting to brute-force SSH access. I've watched login attempts start within 12 seconds of a new server coming online.
OpenClaw is an AI agent with access to your personal data, your messaging platforms, potentially your email, and whatever else you connect to it. If someone compromises your server, they don't just get a Linux box — they get your AI assistant and everything it has access to. This is why we secure the server before installing anything.
1 Update the system
SSH into your fresh server as root and immediately bring everything up to date. Your VPS image is almost certainly running packages with known vulnerabilities.
apt update && apt upgrade -y
This may take a few minutes. Don't skip the upgrade — your job is to keep your system patched while attackers are actively scanning for unpatched servers.
2 Install essential security and networking tools
A fresh Ubuntu install is deliberately minimal. Linux was designed to be composable and lightweight — not to come pre-loaded with everything you might need. Install the essentials:
apt install -y curl wget ufw fail2ban ca-certificates gnupg git
- ufw — Uncomplicated Firewall, our primary defense layer
- fail2ban — Automatically bans IPs that fail authentication
- ca-certificates & gnupg — For verifying package signatures and HTTPS
- curl & wget — For downloading packages and scripts
- git — For cloning the OpenClaw repository
3 Create a non-root user
Running everything as root is how servers get fully compromised from a single exploit. Create a dedicated user with sudo privileges:
adduser openclaw
usermod -aG sudo openclaw
Use a strong, unique password. Not the password you use everywhere. Not a variation of it. A genuinely random password. You won't need to type it often because we're about to eliminate password-based access entirely.
4 Set up SSH key authentication
Passwords are guessable. SSH keys are not. On your local machine (not the server), generate a key pair if you don't already have one:
# On your local machine
ssh-keygen -t ed25519 -C "openclaw-vps"
Copy the public key to your server:
# On your local machine
ssh-copy-id -i ~/.ssh/id_ed25519.pub openclaw@your-server-ip
Save your SSH key
If you lose your private key and we disable password authentication (which we're about to do), you are permanently locked out. Back up your key pair now. Store it somewhere safe. Do not proceed until you've verified you can log in with the key.
Test the key-based login before proceeding:
# On your local machine
ssh openclaw@your-server-ip
If you get in without being prompted for a password, you're good. If not, stop and fix it before continuing.
5 Harden SSH
Now we lock down the SSH daemon. Edit the SSH configuration:
sudo nano /etc/ssh/sshd_config
Find and set these values (some may need to be uncommented or added):
Port 2222
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
We're changing the SSH port from the default 22 to 2222. This isn't security — it's noise reduction. Every automated scanner hits port 22 first. Moving to a non-standard port eliminates 99% of the low-effort automated attacks and keeps your logs readable.
Verify the SSH config before restarting. If you misconfigure this and restart, you're locked out. Run:
sudo sshd -t
If the test passes with no output, restart SSH:
sudo systemctl restart sshd
Do not close your current session. Open a new terminal and test the connection with the new port:
# On your local machine — in a NEW terminal
ssh -p 2222 openclaw@your-server-ip
Only close the original session after confirming the new one works.
6 Configure the firewall
This is an elimination diet for network traffic. We block everything, then selectively allow only what we need.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 2222/tcp comment 'SSH'
That's it for now. One door open — our custom SSH port. Everything else is blocked. Enable the firewall:
sudo ufw enable
Verify the rules:
sudo ufw status verbose
7 Set up Fail2ban
"I thought we disabled passwords?" You did — today. But security isn't a one-time event. Fail2ban adds defense-in-depth by automatically banning IPs that repeatedly fail authentication, protecting against brute-force attacks on your SSH key auth and any future services you expose.
Create a local configuration file (never edit the main config — it gets overwritten on updates):
sudo nano /etc/fail2ban/jail.local
Add this configuration:
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
Start and enable fail2ban:
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Verify it's running:
sudo fail2ban-client status sshd
8 Enable automatic security updates
Your server needs to patch itself without waiting for you to remember to SSH in and run apt upgrade. Configure unattended upgrades:
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Verify the security origin is enabled in /etc/apt/apt.conf.d/50unattended-upgrades. The line containing ${distro_id}:${distro_codename}-security should be uncommented.
Optionally, configure automatic reboots for kernel updates:
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
Find and set:
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";
Your server can now reboot itself at 3 AM when kernel patches require it. You'll sleep better.
9 Basic OS sanity
Before installing anything else, set your timezone and make sure the system clock is synchronized. Time drift causes subtle, maddening bugs in distributed systems and logging:
sudo timedatectl set-timezone UTC
sudo timedatectl set-ntp on
Verify:
timedatectl status
10 Install Tailscale VPN
This is where the setup gets genuinely interesting. Tailscale creates a private mesh VPN between your devices — your laptop, your phone, your server — using WireGuard under the hood. Once Tailscale is running, we can remove all public access to the server and only allow connections through the encrypted VPN mesh.
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
You'll get an authentication URL. Open it in your browser, log in to your Tailscale account, and authorize the device. Once connected, get your server's Tailscale IP:
tailscale ip -4
This gives you something like 100.x.x.x — a private IP that's only reachable through your Tailscale network. Test the connection from your local machine (which should also have Tailscale installed):
# On your local machine (with Tailscale running)
ssh -p 2222 openclaw@100.x.x.x
11 Lock down to Tailscale only
Now we do something that feels reckless but is actually the most secure configuration possible: we remove public SSH access entirely.
# Remove public SSH rule
sudo ufw delete allow 2222/tcp
# Allow SSH only through Tailscale
sudo ufw allow in on tailscale0 to any port 2222 proto tcp comment 'SSH via Tailscale'
Public SSH is now gone. All public inbound traffic is gone. The server is only reachable through your private Tailscale mesh. For extra hardening, disable IPv6 in UFW and apply kernel-level settings:
# Disable IPv6 in UFW
sudo sed -i 's/IPV6=yes/IPV6=no/' /etc/default/ufw
# Apply kernel hardening
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1
sudo sysctl -w net.ipv6.conf.default.disable_ipv6=1
Reload the firewall:
sudo ufw reload
sudo ufw status verbose
Verify you can still connect via Tailscale. If you can — congratulations, your server is now invisible to the public internet.
12 Install Node.js
OpenClaw requires Node.js. Never use the Node version that ships with your distro's package manager — it's always outdated. Install from the official NodeSource repository:
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs
Verify the installation:
node --version
npm --version
13 Install OpenClaw
Create a dedicated directory for the application — don't dump production apps into the home directory:
sudo mkdir -p /opt/openclaw
sudo chown openclaw:openclaw /opt/openclaw
cd /opt/openclaw
Clone the repository:
git clone https://github.com/openclaw/openclaw.git .
npm install
Fix directory permissions (they're broken by default — as is tradition):
sudo chown -R openclaw:openclaw /opt/openclaw
Create a credentials directory:
mkdir -p /opt/openclaw/credentials
chmod 700 /opt/openclaw/credentials
Copy the example environment file and configure it with your API keys and settings:
cp .env.example .env
nano .env
Run the built-in doctor command to verify everything is configured correctly:
npm run doctor
14 Create a systemd service
Systemd ensures OpenClaw starts on boot, restarts on crash, and logs properly. Create the service file:
sudo nano /etc/systemd/system/openclaw.service
Add this unit configuration:
[Unit]
Description=OpenClaw AI Agent
After=network.target
[Service]
Type=simple
User=openclaw
WorkingDirectory=/opt/openclaw
ExecStart=/usr/bin/node /opt/openclaw/index.js
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=openclaw
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
Enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable openclaw
sudo systemctl start openclaw
Check that it's running:
sudo systemctl status openclaw
View the logs to observe runtime behavior:
sudo journalctl -u openclaw -f
15 Backups and monitoring
Your OpenClaw instance is now running and accumulating data — memories, conversations, configurations. Protect it.
Set up a basic backup script:
sudo nano /opt/openclaw/backup.sh
#!/bin/bash
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/opt/openclaw/backups"
mkdir -p $BACKUP_DIR
tar -czf $BACKUP_DIR/openclaw_$TIMESTAMP.tar.gz \
--exclude='node_modules' \
--exclude='backups' \
/opt/openclaw/
# Keep only last 7 backups
ls -t $BACKUP_DIR/openclaw_*.tar.gz | tail -n +8 | xargs -r rm
echo "Backup completed: openclaw_$TIMESTAMP.tar.gz"
chmod +x /opt/openclaw/backup.sh
Automate it with a cron job (daily at 2 AM):
crontab -e
# Add this line:
0 2 * * * /opt/openclaw/backup.sh >> /var/log/openclaw-backup.log 2>&1
If OpenClaw ships with a built-in security audit, run it:
npm audit
The final architecture
Let's review what you've built. Your server now has:
- No public SSH — only accessible via Tailscale VPN
- No public web ports — nothing exposed to the internet
- Key-based authentication only — no passwords to brute-force
- Automatic security updates — patches applied without intervention
- Fail2ban monitoring — abusive IPs automatically blocked
- systemd management — automatic restart on crash, proper logging
- Daily backups — your data is protected against failure
The server is reachable only through your private Tailscale network. Every connection is encrypted end-to-end with WireGuard. This is significantly more secure than the default setup most tutorials leave you with.
Security isn't something you do once. It needs to live rent-free in your mind at all times.
The alternative: just use a Mac Mini
After all of this — after the SSH hardening, the firewall rules, the VPN mesh, the systemd services — I should tell you something. You could also just run OpenClaw on an isolated Mac Mini on your local network. No public IP. No attack surface. No VPS bill. Plug it in, install Node.js, clone the repo, run it.
The VPS approach makes sense when you need remote access from anywhere, 24/7 uptime, or you're running multiple services. But if you just want a personal AI assistant that works when you're home and you have a spare machine — the simplest, most secure option is a device on your local network that has no exposure to the public internet whatsoever.
There's an irony in spending two hours hardening a public server when the most secure configuration is a computer in your closet that the internet can't see at all. Choose the approach that fits your actual requirements, not the one that feels most impressive.
The best server architecture is the one that matches your threat model, not the one with the most steps.
If you want help setting up OpenClaw for your specific use case — whether on a VPS, a local machine, or a more complex multi-service architecture — I consult on exactly this kind of AI infrastructure.
Related: 6 OpenClaw Use Cases: Build a Second Brain, Content Factory, and More