Setting Up a Persistent AI Agent on a VPS with OpenClaw
How to run OpenClaw on a DigitalOcean VPS, lock it down with Tailscale, and sync everything to Obsidian with Syncthing.
This is Part 4 of my AI coding workflow series. Part 1 covers terminal agents. Part 2 covers editor-level AI. Part 3 covers PR-level agents. This post goes deeper: running a persistent AI agent on a remote server using OpenClaw.
Why run an AI agent on a VPS?
Running AI agents locally works, but has limitations:
- My laptop sleeps, travels, runs out of battery
- Long-running tasks get interrupted
- Can't easily hand off to mobile or other devices
The fix: run OpenClaw on a cheap VPS that's always on, accessible from anywhere via Tailscale VPN, with automatic backups to my Obsidian vault via Syncthing.
I recommend DigitalOcean for this setup because the lowest-tier droplets are enough to run OpenClaw, Tailscale, and Syncthing reliably.
Here's the stack:
┌─────────────────┐ ┌─────────────────┐
│ Your Mac │────▶│ Tailscale VPN │
│ (Obsidian) │◀────│ (encrypted) │
└─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ DigitalOcean │
│ VPS ($12/mo) │
│ ───────────── │
│ OpenClaw │
│ Syncthing │
│ Tailscale │
└─────────────────┘
Not technical? Use an AI assistant
If you're not comfortable with command-line setup, you can use Claude Code or Codex directly on your server to do it for you.
Once you have SSH access to your VPS:
# Install Node.js first (required for terminal AI tools)
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
# Then install your preferred AI coding assistant:
# Option A: Claude Code
sudo npm install -g @anthropic-ai/claude-code
# Option B: Codex CLI
sudo npm install -g @openai/codex
Then run claude or codex and authenticate. Once connected, ask it to:
"I have already installed Node.js. Now, follow this guide to set up OpenClaw with Tailscale and Syncthing. My username is
<your_user>."
The AI can run the commands, troubleshoot errors, and adapt to your setup. Once OpenClaw is running, it becomes that assistant permanently.
1. DigitalOcean VPS setup
Create the droplet
- Sign up / log in at DigitalOcean
- Click Create → Droplets
- Choose your configuration:
- Region: Pick something geographically close (London or Singapore from Thailand both work)
- Image: Ubuntu 24.04 LTS
- Size: Regular (shared CPU), 2GB / 1 vCPU ($12/mo) is plenty. The AI runs in the cloud; the VPS just needs to run the CLI and Syncthing
- Authentication: SSH Key (we'll set this up next)
- Give it a hostname like
openclawand create it - Note the public IP address once it's provisioned
Initial server hardening
Once you can SSH in, do the basics:
# Update everything
apt update && apt upgrade -y
# Create a non-root user (replace <your_user> with your username)
adduser <your_user>
usermod -aG sudo <your_user>
# Copy your SSH key to the new user
mkdir -p /home/<your_user>/.ssh
cp ~/.ssh/authorized_keys /home/<your_user>/.ssh/authorized_keys
chown -R <your_user>:<your_user> /home/<your_user>/.ssh
chmod 700 /home/<your_user>/.ssh
chmod 600 /home/<your_user>/.ssh/authorized_keys
# Disable root login and password auth
sed -i 's/^#*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart sshd
Install Node.js
OpenClaw requires Node.js:
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
node --version # confirm v22+
Install OpenClaw
npm install -g openclaw
Run through the setup wizard:
openclaw onboard
Check the OpenClaw documentation for configuration options.
2. Tailscale VPN setup
Tailscale gives you a private, encrypted mesh network between your devices. No need to expose SSH to the public internet.
Install on the VPS
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
This prints an auth URL. Open it, log in to your Tailscale account (or create one), and authorise the device.
Install on your Mac
# Via Homebrew
brew install --cask tailscale
# Or download from https://tailscale.com/download/mac
Open the Tailscale app, sign in with the same account, and connect.
Verify the connection
# On your Mac, check both devices are visible
tailscale status
# You should see both your Mac and the VPS listed with their Tailscale IPs (100.x.x.x)
Disable key expiry (recommended for servers)
In the Tailscale admin console:
- Find your VPS machine
- Click the
...menu → Disable key expiry
This prevents the VPS from dropping off the network when the auth key expires.
3. SSH key setup on Mac
Generate a key
# Ed25519 is modern and preferred
ssh-keygen -t ed25519 -C "your-email@example.com"
# Accept the default path (~/.ssh/id_ed25519)
# Set a passphrase (recommended)
Add the public key to DigitalOcean
Either:
- During droplet creation: Paste the contents of
~/.ssh/id_ed25519.pubinto the SSH key field - After creation: Copy it to the server manually:
ssh-copy-id -i ~/.ssh/id_ed25519.pub root@<DROPLET_PUBLIC_IP>
Set up your SSH config
Edit ~/.ssh/config:
Host openclaw
HostName 100.x.x.x # Tailscale IP of your VPS
User <your_user>
IdentityFile ~/.ssh/id_ed25519
Now you can just run ssh openclaw from anywhere on your Tailscale network.
4. Accessing via Tailscale only
Once both your Mac and the VPS are on Tailscale, stop using the public IP for SSH and use the Tailscale IP instead.
Lock down the firewall
On the VPS, restrict SSH to only Tailscale:
# Allow SSH only on the Tailscale interface
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow in on tailscale0 to any port 22
sudo ufw enable
SSH is now only accessible through your Tailscale VPN, not from the public internet.
MagicDNS (optional)
Tailscale's MagicDNS lets you use hostnames instead of IPs:
ssh <your_user>@openclaw # if your machine is named "openclaw" in Tailscale
Enable it in the Tailscale admin console under DNS → MagicDNS.
5. Obsidian setup
Obsidian is a markdown-based knowledge management tool. We'll use it to store conversation logs and project files from the agent.
Install on Mac
Download from obsidian.md or:
brew install --cask obsidian
Create your vault
- Open Obsidian
- Create new vault → name it something like
openclaw-vault - Choose a location, e.g.
~/Documents/openclaw-vault - This is where all your synced files will live
Recommended vault structure
openclaw-vault/
├── clawd/ # ← synced from the server
│ ├── projects/
│ ├── conversations/
│ └── memory/
├── notes/ # Your own notes
├── templates/ # Obsidian templates
└── README.md
6. Syncthing: bidirectional vault sync
Syncthing provides continuous, encrypted, peer-to-peer file sync. No cloud middleman.
Install on the VPS
# Add the Syncthing repo
sudo curl -o /usr/share/keyrings/syncthing-archive-keyring.gpg \
https://syncthing.net/release-key.gpg
echo "deb [signed-by=/usr/share/keyrings/syncthing-archive-keyring.gpg] \
https://apt.syncthing.net/ syncthing stable" | \
sudo tee /etc/apt/sources.list.d/syncthing.list
sudo apt update
sudo apt install -y syncthing
Run as a systemd service
# Enable and start for your user
sudo systemctl enable syncthing@<your_user>
sudo systemctl start syncthing@<your_user>
# Check it's running
systemctl status syncthing@<your_user>
Install on Mac
brew install syncthing
brew services start syncthing
Access the Syncthing web UI
On your Mac, Syncthing's UI runs at http://127.0.0.1:8384.
For the VPS, access it via SSH tunnel:
ssh -L 8385:localhost:8384 openclaw
Then open http://127.0.0.1:8385 in your browser.
Connect the devices
- On the Mac's Syncthing UI: go to Actions → Show ID and copy the device ID
- On the VPS's Syncthing UI: click Add Remote Device and paste the Mac's device ID
- Accept the pairing on both sides
Share the Obsidian vault folder
- On the Mac's Syncthing UI: click Add Folder
- Folder Path:
~/Documents/openclaw-vault - Folder ID:
openclaw-vault(must match on both sides) - Share with: your VPS device
- Folder Path:
- On the VPS, accept the incoming folder share
- Set the folder path to
/home/<your_user>/openclaw-vault
- Set the folder path to
Verify sync
Create a test file on your Mac:
echo "sync test" > ~/Documents/openclaw-vault/test.md
After a few seconds, check on the VPS:
cat ~/openclaw-vault/test.md
# Should show "sync test"
Syncthing ignore patterns
Create a .stignore file in the vault root to skip files you don't need synced:
// .stignore
.obsidian/workspace.json
.obsidian/workspace-mobile.json
.DS_Store
*.tmp
7. Link OpenClaw to your vault
Configure OpenClaw to write directly into the synced vault.
Option A: Direct path (recommended)
Set your clawd working directory to be inside the vault:
# OpenClaw writes directly to the vault
mkdir -p /home/<your_user>/openclaw-vault/clawd
# Set this path as workspace in your openclaw config
# agents.defaults.workspace in ~/.openclaw/openclaw.json
Option B: Symlink
If you prefer keeping clawd in its own location:
mkdir -p /home/<your_user>/clawd
ln -s /home/<your_user>/clawd /home/<your_user>/openclaw-vault/clawd
Note: If using symlinks, enable "Follow Symlinks" in Syncthing's folder settings under Advanced.
What this gives you
Once wired up:
- OpenClaw writes files, logs, and project data to the vault
- Syncthing picks up changes and syncs them to your Mac
- Obsidian on your Mac sees everything with full markdown rendering
- Changes flow both ways: add notes in Obsidian and they sync back to the server
8. Secure web access with Tailscale Serve
OpenClaw has a web interface. Instead of exposing it to the public internet, use Tailscale Serve to make it accessible only within your Tailscale network.
Why Tailscale Serve?
- Services only accessible from devices on your Tailscale network
- Automatic HTTPS with valid certificates for your
*.ts.netdomain - Works through NATs and firewalls without port forwarding
Set up Tailscale Serve
On the VPS, expose the OpenClaw gateway (default port 18789):
# Serve the gateway over HTTPS on your Tailscale network
sudo tailscale serve --bg https / http://localhost:18789
This makes the service available at https://<your-vps-hostname>.<tailnet-name>.ts.net/.
Exposing multiple services
# OpenClaw gateway on /
sudo tailscale serve --bg https / http://localhost:18789
# Syncthing UI on a separate port
sudo tailscale serve --bg --https=8384 http://localhost:8384
Check running services
tailscale serve status
Access from any device
Once configured, access your services from any device on your Tailscale network:
- Mac/PC: Open
https://openclaw.<your-tailnet>.ts.net/in browser - Mobile: Install Tailscale app, connect, then access the same URL
Security notes
- Only devices authenticated to your Tailscale network can access these URLs
- You can further restrict access using Tailscale ACLs
- No need to open any ports on your firewall
9. Gateway web UI and device pairing
When you first visit the OpenClaw web UI, you might see "disconnected (1008): pairing required". The gateway needs to approve your browser as a trusted device.
Approve your browser
On the VPS, check for pending device requests:
openclaw devices list
You'll see something like:
Pending (1)
┌──────────────────────────────────────┬────────────────────────────────────┬──────────┐
│ Request │ Device │ Role │
├──────────────────────────────────────┼────────────────────────────────────┼──────────┤
│ 44e05baf-ae0b-4a5f-b640-04195b8acca9 │ 2286fb5a55e891dcb8f6c8c76645c387...│ operator │
└──────────────────────────────────────┴────────────────────────────────────┴──────────┘
Approve it:
openclaw devices approve <request-id>
Refresh the browser and you should be connected.
Getting your gateway token
If the UI prompts for a token, find it in your config:
grep '"token"' ~/.openclaw/openclaw.json
Or check ~/.openclaw/openclaw.json under gateway.auth.token.
Managing devices
# List all devices (pending and paired)
openclaw devices list
# Revoke a device
openclaw devices revoke <device-id>
# Rotate a token
openclaw devices rotate <role>
Quick reference
| Component | Mac | VPS |
|---|---|---|
| Tailscale | App or brew install --cask tailscale | curl -fsSL https://tailscale.com/install.sh | sh |
| SSH | ssh openclaw (via ~/.ssh/config) | Locked to Tailscale interface only |
| Syncthing | brew install syncthing → localhost:8384 | apt install syncthing → systemd service |
| Obsidian | brew install --cask obsidian | Not needed on server |
| OpenClaw | Optional (for local use) | npm install -g openclaw |
Ports and access
| Service | Port | Access |
|---|---|---|
| SSH | 22 | Tailscale only (tailscale0 interface) |
| Syncthing Web UI | 8384 | Localhost or Tailscale Serve |
| Syncthing Sync | 22000 | Tailscale only |
| OpenClaw Gateway | 18789 | Tailscale Serve (https://<hostname>.<tailnet>.ts.net/) |
Troubleshooting
Syncthing not syncing?
Check systemctl status syncthing@<your_user> on the VPS. Make sure both devices show as "Connected" in the web UI.
Can't SSH via Tailscale?
Run tailscale status on both devices. If the VPS shows as offline, run sudo tailscale up again.
Symlink not syncing? Enable "Follow Symlinks" in Syncthing's folder settings, or switch to the direct path approach.
Obsidian not seeing new files? Obsidian watches the filesystem, but large syncs can take a moment. Try closing and reopening the vault.
OpenClaw auth issues?
Run openclaw doctor on the VPS to check auth status. See OpenClaw authentication docs for setup.
Gateway shows "pairing required"?
Run openclaw devices list and approve the pending request with openclaw devices approve <request-id>.
What's next
With this setup running:
- Persistent AI agent that's always on
- Secure access from anywhere via Tailscale
- Automatic backup of agent output to Obsidian
- Bidirectional sync between server and local
From here you could:
- Add more Syncthing folders (code repos, notes)
- Configure OpenClaw with custom skills and cron jobs
- Connect chat channels (Telegram, Slack, Discord)
- Build dashboards to monitor agent activity
The VPS becomes your AI command center: cheap, always available, and you control all of it.