Run OpenClaw securely without public inbound ports

If you want the safest practical setup, do this: keep OpenClaw private and access it through a secure overlay like Cloudflare Tunnel or Tailscale. No direct internet exposure, no open gateway port, much lower attack surface.

Recommended VPS specifications

  • CPU: 2 vCPU minimum
  • RAM: 4GB minimum
  • Storage: 40GB+ SSD
  • OS: Ubuntu 22.04/24.04 LTS
  • Network: inbound locked down to SSH + HTTPS only (or less)

Architecture options

Option A: Cloudflare Tunnel (public hostname, private origin)

  • OpenClaw listens on localhost/private interface
  • cloudflared establishes outbound tunnel to Cloudflare
  • Users authenticate through Cloudflare Access policies
  • No direct public inbound to OpenClaw service ports

Option B: Tailscale (private mesh network)

  • VPS joins private WireGuard mesh
  • Only authorized tailnet devices can reach the service
  • Great for operator-only/admin access with no public exposure

Baseline host hardening first

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

For detailed hardening, follow: OpenClaw Security Lockdown: Safe Internet Exposure Guide.

Cloudflare Tunnel setup (example)

# install cloudflared
curl -fsSL https://pkg.cloudflare.com/install.sh | sudo bash
sudo apt install -y cloudflared

# authenticate and create tunnel
cloudflared tunnel login
cloudflared tunnel create openclaw

# route a hostname
cloudflared tunnel route dns openclaw claw.example.com

Create config file /etc/cloudflared/config.yml:

tunnel: openclaw
credentials-file: /etc/cloudflared/<tunnel-id>.json

ingress:
  - hostname: claw.example.com
    service: http://127.0.0.1:18789
  - service: http_status:404
sudo cloudflared service install
sudo systemctl enable --now cloudflared
sudo systemctl status cloudflared

Important: enforce Cloudflare Access policy (email/IdP/device posture) so the hostname is not anonymously reachable.

Tailscale setup (example)

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --ssh
tailscale status

Then bind access to tailnet IP/private DNS only, and avoid exposing public listener routes.

Nginx + localhost origin pattern

If you use a reverse proxy, keep upstream local-only:

location / {
  proxy_pass http://127.0.0.1:18789;
  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;
}

Operational checklist

  • Patch OS monthly (or faster for high severity CVEs)
  • Rotate API keys and remove stale integrations
  • Audit auth/access policies quarterly
  • Backup configs and recovery secrets
  • Monitor logs for abuse, bot scanning, and auth failures

Related guides

Need a stable home for this setup? Start with a Cloud VPS with full root access, then layer Cloudflare Access or Tailscale on top.