# OpenClaw VPS Configuration Guide
This is a step-by-step configuration guide for [[OpenClaw]] on a VPS ([[Ubuntu]]-based), using [[Tailscale]] for more secure access.
```
# Create your VPS
# Get the IP & root account password
# Login over SSH as root
ssh root@<ip>
# Change root password
# Add your SSH pubkey to ~/ssh/authorized_keys
# Update
sudo apt update && sudo apt upgrade
sudo apt dist-upgrade
# Enabled automatic security updates
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure -plow unattended-upgrades
## Verify it's enabled:
cat /etc/apt/apt.conf.d/20auto-upgrades
# Change hostname
sudo hostnamectl set-hostname <foo>
# Create YOUR user account (sudoer)
adduser <yourusername>
# Add it to sudoers
usermod -aG sudo <yourusername>
# Switch user
su <yourusername>
# Add your SSH pubkey
mkdir /home/<yourusername>/.ssh
sudo chown -R <yourusername> /home/<yourusername>/.ssh
sudo chgrp -R <yourusername> /home/<yourusername>/.ssh
sudo chmod 0700 /home/<yourusername>/.ssh
sudo chmod 0600 /home/<yourusername>/.ssh/authorized_keys
# Validate that you can connect using your SSH key
# Configure the SSH daemon
sudo su # Switch back to root
nano /etc/sshd/sshd_config
PermitRootLogin no
PasswordAuthentication no
PermitEmptyPasswords no
# Restart SSH daemon
sudo sshd -t && sudo systemctl reload ssh
# Brute-force protection → Auto-ban IPs after failed login attempts.
sudo apt install fail2ban -y
sudo systemctl enable --now fail2ban
# Enable NTP Time Synchronization
sudo apt install chrony -y
sudo systemctl enable --now chrony
## Verify it's working
chronyc tracking
# Create 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
## Verify it's ok
free -h
# Install Tailscale
# More secure connections to the VPS
sudo curl -fsSL https://tailscale.com/install.sh | sh
# Start Tailscale
sudo tailscale up
# Connect the VPS to Tailscale
# Optional: Disable key expiry for it: https://login.tailscale.com/admin/machines
# Verify Tailscale is running
tailscale status
# Get Tailscale IPv4 on your own computer (aka client host)
tailscale ip -4 # Take note of it
# Run the same command on your VPS to get its Tailscale IP
# BLOCK Tailscale incoming traffic on your own computer
# If your VPS is p0wned, you DO NOT want it to be able to reach your machine
sudo tailscale set --shields-up=true
# Change SSH configuration on your own client to use the Tailscale IP as HostName
## Go to ~/.ssh
## Edit the 'config' file
## Add an entry to use your SSH key and use the VPS' Tailscale IP
## Validate it works
# Enable UFW
sudo apt install ufw -y
sudo ufw enable
# Restrict traffic
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw status verbose
# SSH only via Tailscale: No more public SSH exposure
# Allow inbound Tailscale traffic
sudo ufw allow in on tailscale0
sudo ufw status verbose
# Reload UFW
sudo ufw reload
sudo service ssh restart
# Enable 443 and 80 ports from your client host (i.e., your machine)
sudo ufw allow from <your client host's Tailscale IP>/24 to any port 443 proto tcp
sudo ufw allow from <your client host's Tailscale IP>/24 to any port 80 proto tcp
sudo ufw status verbose
sudo ufw reload
# Create a user account for the AI Agent
sudo adduser foo
sudo usermod -aG sudo foo
su - foo
# Install OpenClaw
curl -fsSL https://openclaw.ai/install.sh | bash
exec bash
# Reload bash profile
source .profile
# Configure the OpenClaw gateway to use Tailscale
openclaw configure
# Where will the Gateway run? Local (this machine)
# Select sections to configure: Gateway
# Gateway port: 18789
# Gateway bind mode: Tailnet (Tailscale IP)
# Tailscale exposure: Serve (Private HTTPS for your tailnet (devices on Tailscale))
# Reset Tailscale serve/funnel on exit? No
## During the config, connect your WhatsApp or Telegram etc
# Expose the Gateway via Tailscale
sudo tailscale serve --bg 18789
sudo tailscale serve status
# To disable it:
sudo tailscale serve --https=443 off
# Run audits and tighten security
openclaw doctor
openclaw security audit
openclaw security audit --deep
openclaw security audit --fix
# Added trusteproxies (127.0.0.1) to ~/.openclaw/openclaw.json
# Inside "gateway" object:
# "trustedProxies": ["127.0.0.1"]
# Start the gateway
openclaw gateway --force
# In another terminal
## List devices
openclaw devices list
## Approve client Tailscale device
openclaw devices approve <Request>
# Connect with browser to Tailscale service URL
# Install jq
sudo apt install jq
# Install nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
nvm install x.y.z
nvm use x.y.z
# Install Bun: https://bun.com/docs/installation
sudo apt install unzip
curl -fsSL https://bun.com/install | bash
source /home/foo/.bashrc
## Install pnpm: https://pnpm.io/installation
curl -fsSL https://get.pnpm.io/install.sh | sh -
## Install Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
echo >> /home/foo/.bashrc
echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv bash)"' >> /home/foo/.bashrc
# Install gh CLI
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update && sudo apt install gh -y
# Configure Web client
openclaw configure --section web
## Get a Brave API key and enable web fetch: https://api-dashboard.search.brave.com/app/keys
# Configure systemctl service
sudo cp ~/.openclaw/openclaw-gateway.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now openclaw-gateway
sudo systemctl status openclaw-gateway
# Setup the systemd daemon
# Reference: https://docs.openclaw.ai/platforms/linux#system-control-systemd-user-unit
Create ~/.config/systemd/user/openclaw-gateway.service
Add this to it:
---
[Unit]
Description=OpenClaw Gateway
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/home/foo/.npm-global/bin/openclaw gateway --port 18789
Restart=always
RestartSec=5
Environment=HOME=/home/foo
Environment=PATH=/usr/local/bin:/usr/bin:/bin:/home/foo/.npm-global/bin
Environment=NODE_ENV=production
[Install]
WantedBy=default.target
---
# Enable the systemd service
systemctl --user enable --now openclaw-gateway.service
# Verify it is running correctly
systemctl --user status openclaw
journalctl --user -u openclaw -f
# Once started, you should be able to connect to the Web UI
# TIP: You can find your Tailscale DNS name here: https://login.tailscale.com/admin/dns
# Run a deep check and fix any raised issues:
openclaw security audit --deep
openclaw security audit --fix
# Install browser agent + Chromium: https://github.com/vercel-labs/agent-browser
npm install -g agent-browser
agent-browser install --with-deps
# Install a real Web browser
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo dpkg -i google-chrome-stable_current_amd64.deb
sudo apt --fix-broken install -y # if there are dependency errors
## Configure the browser to run as a service
touch ~/.config/systemd/user/openclaw-browser.service && nano ~/.config/systemd/user/openclaw-browser.service
---
[Unit]
Description=OpenClaw Browser (Chrome CDP)
After=network.target
[Service]
ExecStart=/usr/bin/google-chrome --headless --no-sandbox --disable-gpu --remote-debugging-port=18800 --user-data-dir=%h/.openclaw/browser/openclaw/user-data about:blank
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
---
## Then enable the browser service
systemctl --user enable --now openclaw-browser.service
## Test it
curl -s http://127.0.0.1:18791/ | jq '{running, pid, chosenBrowser}'
curl -s -X POST http://127.0.0.1:18791/start
curl -s http://127.0.0.1:18791/tabs
## Configure OpenClaw to use it
nano ~/.openclaw/openclaw.json
---
"browser": {
"enabled": true,
"executablePath": "/usr/bin/google-chrome-stable",
"headless": true,
"noSandbox": true
},
---
```
# Back everything up
```
tar czf - ~/.openclaw > openclaw-backup-$(date +%Y%m%d).tar.gz
```
After this your VPS should be secure-enough and good to go!
## More "protections"
Although this won't save you from everything, these skills can help:
```
npx clawhub install skillguard
npx clawhub install prompt-guard
```
Also, make 100% sure you BLOCK the incoming traffic to machines on your [[Tailscale]] network by default using: ``
## Heartbeat
Play with your agent for a while before enabling the heartbeat (i.e., what makes the agent come alive every X).
Once you're more confident, check out: https://docs.openclaw.ai/gateway/heartbeat
When you configure that, make sure to adapt HEARTBEAT.md in the workspace. That's where you can configure the instructions/prompt: https://docs.openclaw.ai/gateway/heartbeat#what-the-heartbeat-prompt-is-for
## Staying up to date
See here: https://docs.openclaw.ai/install/updating
## Bonuses
### Git for the OpenClaw workspace
You may also want to create a repository for [[OpenClaw]]'s workspace (~/.openclaw/workspace). This is a good thing to do because that way you have a backup and can restore if/when needed. If you do that, also make sure to give a hard rule to your agent about always doing a git commit/push when it changes its workspace.
### Disable mDNS Broadcasting
You should also probably disable mDNS broadcasting. Your whole network doesn't need to know you're running OpenClaw:
```
echo 'export OPENCLAW_DISABLE_BONJOUR=1' >> ~/.bashrc
source ~/.bashrc
sudo systemctl restart openclaw
```
### Install and Configure Skills
- Run `openclaw configure`
- Go to the skills configuration
- Select those you want using space, then hit enter
- Recommended
- summarize
- video-frames
- ...
### Create a Discord Bot
- Go to https://discord.com/developers/applications
- Click "New Application" → name it
- Go to *Bot* section → "Add Bot"
- Copy the *Bot Token* (keep it secret!)
- Enable required intents
- In Bot settings, enable:
- ✅ Message Content Intent
- ✅ Server Members Intent (optional)
- Invite the bot to your server
- Go to *OAuth2 → URL Generator*
- Select scopes: bot
- Select permissions: Send Messages, Read Message History, Add Reactions, ... (or Administrator, depending on what you want/need your agent to do)
- Open the generated URL to add the bot to your server
- Give the bot token to your assistant and let it handle the configuration on its side
- Once configured, send a Discord DM to your bot. It will reply with a pairing code
- Go to your server and run `openclaw pairing list discord`
- Copy the code
- Run `openclaw pairing approve discord <code>`
- You're good to go
DO NOT open this up. Lock down access to your server id only, enforce approvals, etc:
- Set `groupPolicy` to `allowlist`
- Add your server id to `guilds`
### Give Control Over Chrome running on your Computer
Although this MUST be considered HIGHLY risky, it's possible to expose a Chrome browser launched in debug mode on your computer to the OpenClaw agent running on your VPS.
This can be useful when the agent can't work around [[Cloudflare]] and the like, or you need to be able to see the browser to intervene.
**WARNING**: As I said, this is REALLY dangerous. If you do want that nevertheless, then you SHOULD REALLY use a temporary/dedicated chrome profile and NOT your own. Also, ONLY expose your computer for the minimum amount of time. Don't allow incoming connections all the time. And EVEN if you do that, you'll be at risk, because the [[Lethal Trifecta for AI Agents|Lethal Trifecta]] may p0wn your AI...
The idea is to start Chrome on your computer with the [[Chrome Debug Mode]] enabled, and to connect to its [[Chrome DevTools]] via the [[Chrome DevTools Protocol (CDP)]].
First, get your computer's IPv4 [[Tailscale]]: `tailscale ip -4`.
One the OpenClaw server, edit the `openclaw.json` configuration. You need to add a profile for your browser. Give it a useful name, and make it point to port `9223` on your computer's Tailscale IP:
```
...
"browser": {
"enabled": true,
...
"profiles": {
"your-browser": {
"cdpUrl": "http://<your computer tailscale ip:9223"
...
},
...
}
}
...
```
Second, install the prerequisites on your computer:
- [[socat]], a powerful tool created by [[Gerhard Rieger]]. This will expose the traffic from the chrome instance (normally limited to your local host) to [[OpenClaw]]
- And of course Chrome ;-)
Then, you can use the following [[Bash]] function on your computer to:
- Temporarily disable the [[Tailscale]] shield (i.e., let your machine accept incoming traffic through Tailscale)
- Start Chrome in debug mode with a temporary profile (use the path to your actual Chrome profile instead if you're nuts)
- Start [[socat]]
- (OpenClaw can connect after this)
- Finally, it re-enables the [[Tailscale]] shield once done
Once that's started, you can ask your [[OpenClaw]] server to connect and use your browser, and you'll get to see all the fun things it does for you.
```
chrome-openclaw() {
local TS_IP=$(tailscale ip -4)
echo "🔓 Lowering Tailscale shields..."
sudo tailscale set --shields-up=false
echo "🚀 Starting Chrome + socat on $TS_IP:9223..."
google-chrome-stable --remote-debugging-port=9222 \
--user-data-dir=/tmp/openclaw-chrome &
local CHROME_PID=$!
sleep 2
socat TCP-LISTEN:9223,bind=$TS_IP,reuseaddr,fork TCP:127.0.0.1:9222 &
local SOCAT_PID=$!
echo "✅ Ready! OpenClaw can connect. Press Ctrl+C to stop."
cleanup() {
echo "🧹 Cleaning up..."
kill $CHROME_PID $SOCAT_PID 2>/dev/null
echo "🛡️ Raising Tailscale shields..."
sudo tailscale set --shields-up=true
echo "✅ Done"
}
trap cleanup INT TERM EXIT
wait $CHROME_PID 2>/dev/null
}
```
**TIP**: Just for additional safety, run `killall socat` when you're done.
Oh and explain your agent that it should let you know when it needs access to your Web browser.
## Additional recommendations
This stuff is fun AND powerful, but VERY dangerous. A few pieces of advice:
- DO NOT install this on your own computer
- Apply the least privilege principle
- Don't give it all the keys to your kingdom
- Don't make it read whatever on the Web (prompt injection risks are REAL); only let it consume trusted sources
- Use short-lived API keys
- You can install skills using `openclaw skills install <foo>`, but be VERY careful. That's a perfect vector for prompt injection. Only install stuff from people you really trust
- Same with everything else
- Don't let your bot partipate in Moltbook. Probably not a great idea from a security pov
- Use the "CRITICAL" keyword in SOUL.MD
- ...
## References
- https://docs.openclaw.ai
- https://docs.openclaw.ai/gateway/heartbeat
## Related
- [[OpenClaw]]
- [[Tailscale]]
- [[Secure Shell (SSH)]]