Article
Remote OpenClaw Setup with Private Access over WireGuard
How to run OpenClaw on a cloud VM while keeping dashboard access private through a WireGuard VPN and Nginx.
This guide shows how to run OpenClaw on a cloud VM while keeping dashboard access private through a WireGuard VPN.
Why this setup
OpenClaw can execute powerful actions. Running it on a disposable cloud VM is safer than running it directly on your laptop or home network. If something goes wrong, you can rebuild the VM.
This guide uses a single VM to keep cost low:
- OpenClaw + Nginx run on one server
- WireGuard runs on the same server
- Your laptop connects to that server over VPN
- OpenClaw dashboard is only reachable from VPN IPs
Prerequisites
- A Linux VM (Ubuntu 22.04+ recommended)
- SSH access with your key
- A domain you can manage in DNS (for example
example.com) - OpenClaw installed and running locally on the VM
- Cloud firewall rules:
22/tcp(SSH)51820/udp(WireGuard)443/tcp(HTTPS)80/tcp(needed for Let's Encrypt HTTP challenge)
If you use UFW on the VM, open the same ports there too.
Architecture options
Hub-and-spoke (used in this article)
- One central VM is the WireGuard hub.
- Your laptop is a spoke peer.
- Traffic to OpenClaw travels over the private VPN subnet.
Two-tier variant (optional)
- VM 1: WireGuard gateway
- VM 2: OpenClaw app server
- Use this when you want stricter network separation.
OpenClaw baseline check
Install OpenClaw using the official docs: https://docs.openclaw.ai/start/getting-started
Before adding VPN/proxy, confirm OpenClaw responds locally on the VM:
curl -I http://127.0.0.1:18789
If this fails, fix OpenClaw first, then continue.
WireGuard setup
1. Install WireGuard on server
sudo apt update
sudo apt install -y wireguard
2. Create secure WireGuard directory
sudo install -d -m 700 /etc/wireguard
3. Generate server keys
sudo sh -c 'wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key'
sudo chmod 600 /etc/wireguard/server_private.key
Show your server public key (you will need it on the client):
sudo cat /etc/wireguard/server_public.key
4. Pick server network interface
Find your public NIC name (often eth0, ens3, or ens10):
ip route | awk '/default/ {print $5}'
Use that value below as <PUBLIC_NIC>.
5. Create /etc/wireguard/wg0.conf
sudo nano /etc/wireguard/wg0.conf
[Interface]
PrivateKey = <SERVER_PRIVATE_KEY>
Address = 10.0.0.1/24
ListenPort = 51820
SaveConfig = true
PostUp = sysctl -w net.ipv4.ip_forward=1; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o <PUBLIC_NIC> -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o <PUBLIC_NIC> -j MASQUERADE
# Add peers below
Get the server private key:
sudo cat /etc/wireguard/server_private.key
Paste that value into PrivateKey.
6. Create client tunnel on Mac
In the WireGuard macOS app:
- Click
Add Tunnel. - Choose
Add Empty Tunnel.... - Give it a name.
- The app generates a keypair automatically.
- Copy the client public key.
7. Add client peer to server config
Edit /etc/wireguard/wg0.conf and append:
[Peer]
PublicKey = <CLIENT_PUBLIC_KEY>
AllowedIPs = 10.0.0.2/32
8. Start WireGuard
sudo wg-quick up wg0
sudo systemctl enable --now wg-quick@wg0
9. Open firewall for WireGuard
If UFW is enabled:
sudo ufw allow 51820/udp
10. Complete client config (Mac)
Use this tunnel config in WireGuard app:
[Interface]
PrivateKey = <CLIENT_PRIVATE_KEY>
Address = 10.0.0.2/24
DNS = 1.1.1.1
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = <SERVER_PUBLIC_IP>:51820
AllowedIPs = 10.0.0.0/24
PersistentKeepalive = 25
AllowedIPs = 10.0.0.0/24 is split-tunnel mode (recommended here). Only traffic for VPN subnet goes through WireGuard.
11. Validate VPN
Turn on the tunnel on your Mac, then test:
# from Mac
ping 10.0.0.1
# from server
sudo wg show
You should see a recent handshake and transfer counters increasing.
Nginx reverse proxy + HTTPS
OpenClaw is typically bound to localhost (127.0.0.1). Nginx will publish it on HTTPS, and we will restrict access to VPN source IPs.
1. Install Nginx
sudo apt update
sudo apt install -y nginx
2. Create initial Nginx site
sudo nano /etc/nginx/sites-available/openclaw
server {
listen 80;
server_name openclaw.<DOMAIN_NAME>;
location / {
proxy_pass http://127.0.0.1:18789;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Enable the site:
sudo ln -sf /etc/nginx/sites-available/openclaw /etc/nginx/sites-enabled/openclaw
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
3. Create DNS record
Create an A record:
- Host/name:
openclaw - Value:
<SERVER_PUBLIC_IP>
Resulting FQDN should be openclaw.<DOMAIN_NAME>.
4. Issue TLS certificate
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d openclaw.<DOMAIN_NAME>
Choose redirect to HTTPS when prompted.
5. Restrict HTTPS access to VPN subnet
After certbot updates config, re-open the site file and add allow/deny inside the TLS server block (listen 443 ssl ...):
allow 10.0.0.0/24;
deny all;
Then reload:
sudo nginx -t
sudo systemctl reload nginx
OpenClaw allowed origin
Update OpenClaw config so browser origin is trusted:
nano ~/.openclaw/openclaw.json
{
"gateway": {
"controlUi": {
"allowedOrigins": ["https://openclaw.<DOMAIN_NAME>"]
}
}
}
Restart gateway service:
systemctl --user restart openclaw-gateway.service
If your install uses a system service instead of user service, use sudo systemctl restart <service-name>.
Verification checklist
- VPN on:
ping 10.0.0.1workssudo wg showshows recent handshakehttps://openclaw.<DOMAIN_NAME>loads dashboard
- VPN off:
https://openclaw.<DOMAIN_NAME>should be blocked by Nginx (deny all)
Notes on port 80
For standard Let's Encrypt HTTP validation, port 80/tcp must be reachable from the internet for initial issuance and future renewals. If you must close port 80, switch to DNS challenge instead.