Setting Up OpenClaw Node Across 2 VPS via Tailscale
Context
We have 2 VPS instances:
- VPS 1 (Master): Running OpenClaw Gateway on WSL2.
- VPS 2 (Node/Slave): Ubuntu Server, needs to run OpenClaw Node for remote execution.
- Network: Both connected via Tailscale VPN.
Architecture
To ensure security without exposing ports to the public internet, we utilize Tailscale Serve on the Master to create a secure HTTPS tunnel.
- Master (VPS 1): Runs Gateway, bound to loopback, using Tailscale Serve to expose it to the Tailnet as HTTPS.
- Node (VPS 2): Runs OpenClaw Node Service, connecting to Master via Tailscale’s MagicDNS URL.
Part 1: Configuring VPS Master (Gateway)
1. OpenClaw Gateway Config
Edit ~/.openclaw/openclaw.json:
{
"gateway": {
"bind": "loopback", // Listen only on 127.0.0.1 (Secure)
"port": 18789,
"tailscale": {
"mode": "serve" // Auto-enable Tailscale Serve HTTPS
},
// ... other configs
}
}
2. Restart and Get URL
Restart Gateway:
openclaw gateway restart
Check MagicDNS URL:
tailscale serve status
# Result: https://vps1-name.tailnet-name.ts.net
(Save this URL for VPS 2 setup)
Part 2: Configuring VPS Node (Slave)
This is the tricky part, often plagued by config caching or systemd ignoring environment variables.
1. Install OpenClaw CLI
npm install -g openclaw
2. Fixing “Stubborn 127.0.0.1 Connection”
In practice, the Node process often prioritizes old config files or defaults to localhost. The robust solution is to Hard-code parameters into the Systemd Service instead of relying on JSON files.
Step 1: Stop old service and clean up config files:
systemctl --user stop openclaw-node.service
rm ~/.openclaw/node.json # Critical: This file causes cache issues
rm ~/.openclaw/openclaw.json # Remove to avoid conflicts
Step 2: Create a “Force Remote” Systemd Service:
Create ~/.config/systemd/user/openclaw-node.service with:
[Unit]
Description=OpenClaw Node Host (Remote)
After=network-online.target
Wants=network-online.target
[Service]
# Critical: Use CLI flags to override all configs
ExecStart=/usr/bin/node /usr/lib/node_modules/openclaw/dist/index.js node run --host "vps1-name.tailnet-name.ts.net" --port 443 --tls
# Environment variables
Environment=HOME=/home/username
Environment="PATH=/usr/bin:/usr/local/bin:/bin"
# Token must be passed via ENV (CLI does not support --token flag)
Environment="OPENCLAW_GATEWAY_TOKEN=YOUR_MASTER_TOKEN_HERE"
# Fix SSL issues if Node rejects Tailscale's Let's Encrypt cert
Environment="NODE_TLS_REJECT_UNAUTHORIZED=0"
Restart=always
RestartSec=5
KillMode=process
[Install]
WantedBy=default.target
(Replace vps1-name... and YOUR_MASTER_TOKEN_HERE with actual values)
Step 3: Enable and Start Service
systemctl --user daemon-reload
systemctl --user enable openclaw-node.service
systemctl --user restart openclaw-node.service
Part 3: Pairing
Once the Node starts, it sends a pairing request to the Master.
-
On VPS 1 (Master): Check pending list.
openclaw devices listYou should see a device with Role: node in Pending state.
-
Approve Device:
openclaw devices approve <REQUEST_ID> -
Completion: After approval, VPS 2 will auto-reconnect and switch to Connected status. Verify on Master:
openclaw nodes status
Troubleshooting Lessons
-
Persistent
ECONNREFUSED 127.0.0.1:- Usually caused by a leftover
~/.openclaw/node.json. Delete it immediately. - Or the initial
openclaw node installcommand generated a service file with hardcoded--host 127.0.0.1.
- Usually caused by a leftover
-
unknown option '--token'Error:openclaw node rundoes not accept--token. You must use theOPENCLAW_GATEWAY_TOKENenvironment variable.
-
SSL/TLS Connection Errors:
- When using Tailscale Serve, ensure you add
--tlsflag and use port443. - If certificate errors persist, set
NODE_TLS_REJECT_UNAUTHORIZED=0.
- When using Tailscale Serve, ensure you add
Documented by SensaKai Team - 2026