19 February 2026 · 15 min read

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.

Setting Up a Persistent AI Agent on a VPS with OpenClaw
Disclosure: This post contains affiliate links. We earn commissions when you shop through the links below.

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. Part 5 (coming soon) covers the skills system. This post is about running a persistent AI agent on a remote server using OpenClaw.

Updated April 2026 after two months of daily use. This post focuses on the setup.

A note on timing: the AI tooling space moves fast. The tools, versions, and prices here are a snapshot of what I use right now, not a fixed recipe, and some details will date quickly. I keep these posts updated as my workflow shifts.

At a glance

Think of this setup as giving yourself a second computer that never sleeps, only lets you in through a private door, and quietly keeps a copy of its notes on your Mac.

  • The VPS is a cheap always-on Linux box that hosts the agent (OpenClaw).
  • Tailscale is the private door — a VPN that only your own devices can use.
  • Syncthing keeps a folder of notes and agent output in sync between the server and your Mac.
  • Obsidian reads that folder on your Mac like a normal vault.

You don't need to understand networking, VPNs, or file sync in depth to run this. You need an SSH client and the patience to copy-paste a few commands. Everything below is organised so you can skip to the parts that apply to you.

If you already know why you want this, the cheat sheet near the end has the commands grouped together. The sections in between explain the why.

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 (~£10/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

  1. Sign up / log in at DigitalOcean
  2. Click Create → Droplets
  3. Choose your configuration:
    • Region: Pick something geographically close to you (e.g. London or Singapore)
    • Image: Ubuntu 24.04 LTS
    • Size: Regular (shared CPU), 2GB / 1 vCPU (~£10/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)
  4. Give it a hostname like openclaw and create it
  5. 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

OPENCLAW INSTALL · 30 SECONDS

Two commands, one *agent*.

$npm install -g openclaw
added 142 packages in 18s
✓ openclaw 0.4.2 installed to /usr/local/bin/openclaw
$openclaw onboard
Welcome to OpenClaw. Configuring agent...
? Project name: my-vps-agent
? Default model: claude-sonnet-4
✓ Config written to ~/.openclaw/openclaw.json

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)

In the Tailscale admin console:

  1. Find your VPS machine
  2. 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.pub into 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

  1. Open Obsidian
  2. Create new vault → name it something like openclaw-vault
  3. Choose a location, e.g. ~/Documents/openclaw-vault
  4. This is where all your synced files will live
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

  1. On the Mac's Syncthing UI: go to Actions → Show ID and copy the device ID
  2. On the VPS's Syncthing UI: click Add Remote Device and paste the Mac's device ID
  3. Accept the pairing on both sides

Share the Obsidian vault folder

  1. 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
  2. On the VPS, accept the incoming folder share
    • Set the folder path to /home/<your_user>/openclaw-vault

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

Multiple shared folders

Once Syncthing is working for the vault, it's trivial to add more folders. I run two: obsidian-vault for knowledge/notes and media-output for agent-generated media (video/audio/images) so I can review them on my Mac without SSH'ing in.

The same Add Folder dialog handles this. Give each folder a unique ID and keep the scope tight — syncing an entire $HOME is asking for lock conflicts and 20 GB of node_modules churning through Syncthing's hashing pipeline.


Configure OpenClaw to write directly into the synced vault.

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

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?

I've written a deeper dive on using Tailscale Serve for zero-trust service exposure. The short version:

  • Services only accessible from devices on your Tailscale network
  • Automatic HTTPS with valid certificates for your *.ts.net domain
  • 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

In practice, the VPS ends up hosting more than just OpenClaw. Mine currently serves the gateway, a workstream dashboard (Agent Control Center), Syncthing, an AI pipeline UI, and a lead-gen dashboard — all reachable only from my tailnet.

# 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

# Agent Control Center (workstream dashboard)
sudo tailscale serve --bg --https=1337 http://localhost:1337
sudo tailscale serve --bg --https=1338 http://localhost:1338  # API

# AI pipeline dashboard + API
sudo tailscale serve --bg --https=5173 http://localhost:5173
sudo tailscale serve --bg --https=3001 http://localhost:3001

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>

A couple of practical extras

Two small quality-of-life things that aren't required but you'll want eventually.

Keep long-running services alive with tmux. Once you start running support services (dashboards, scrapers) alongside OpenClaw, use tmux so they don't die when you close your SSH session:

tmux new -s myservice  # start a named session
# ... run your service ...
# ctrl-b then d to detach
tmux attach -t myservice  # come back later

For anything you depend on, graduate to a systemd service. tmux is for development.

Let the agent use git without passphrase prompts. Install keychain so an SSH key gets loaded once per login and stays available to every shell — including the ones OpenClaw spawns:

sudo apt install keychain
ssh-keygen -t ed25519 -f ~/.ssh/dev_server_key

# Add to ~/.bashrc or ~/.zshrc:
eval "$(keychain --eval --quiet ~/.ssh/dev_server_key)"

Now git pull and git push work without you being there.


Quick reference

ComponentMacVPS
TailscaleApp or brew install --cask tailscalecurl -fsSL https://tailscale.com/install.sh | sh
SSHssh openclaw (via ~/.ssh/config)Locked to Tailscale interface only
Syncthingbrew install syncthinglocalhost:8384apt install syncthing → systemd service
Obsidianbrew install --cask obsidianNot needed on server
OpenClawOptional (for local use)npm install -g openclaw
tmuxNot neededapt install tmux — keeps services running
keychainNot neededapt install keychain — SSH without passphrase prompts

Ports and access

ServicePortAccess
SSH22Tailscale only (tailscale0 interface)
OpenClaw Gateway18789Tailscale Serve (https://<hostname>.<tailnet>.ts.net/)
Syncthing Web UI8384Localhost or Tailscale Serve
Syncthing Sync22000Tailscale only
Agent Control Center1337Tailscale Serve (optional — workstream dashboard)
Agent Control Center API1338Tailscale Serve (optional)
AI Pipeline Dashboard5173Tailscale Serve (optional)
AI Pipeline API3001Tailscale Serve (optional)

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>.


10. What this grew into

Two months on, the single OpenClaw instance has become a small operations team. Not metaphorically — I literally have five specialist agents (Finance, Sales, Technology, Ops, Marketing), each with its own workspace, its own Slack channel, and a shared daily rhythm.

Multi-agent specialist architecture with Slack rollup

Every morning at 9am, they each post a standup to their own channel. Fifteen minutes later the Ops agent reads the other four, scores them for quality, and posts a single cross-team rollup to a shared channel. A budget agent runs in the evening. A security audit agent runs overnight. An Agent Control Center dashboard (Tailscale-only) sits on top of the whole thing so I can see what every agent is doing without opening five Slack channels.

None of this needed extra infrastructure. The VPS built in this post is the foundation. The specialist layer is just workspace folders, system prompts, and scheduled crons on top of it.


Series Navigation

AI Coding Workflow Series:

  • Part 1: Terminal Agents — Claude Code, OpenCode, session-level orchestration
  • Part 2: Editor-Level AI — Zed, inline completions, agent panels
  • Part 3: PR-Level Agents — GitHub Apps, automated review
  • Part 4: Persistent VPS Agent (this post) — OpenClaw, Tailscale, Syncthing
  • Part 5: Claude Code Skills Setup (coming soon) — extending Claude Code with custom and vendor skills.
  • My Developer Second Brain — How the Obsidian side of this setup works
  • Tailscale Serve for Zero-Trust Services — Deeper dive on the networking layer
James Donnelly, freelance developer in Manchester

The pitch

I write the code, talk to your team, and ship what we agreed. No agencies. No PMs. No surprises.

James Donnelly

Freelance developer · Manchester