If you just typed “OpenClaw Cloudflare tunnel setup for remote access” into your search bar, you probably want a straight answer, not marketing fluff. This post is exactly that: a reproducible recipe for exposing the OpenClaw Control UI to the internet through Cloudflare Tunnels. It covers installation, DNS wiring, Zero Trust authentication, and a few hardening tricks I wish somebody had told me earlier. The whole thing is free, survives CGNAT, and works great on low-power Raspberry Pi setups that live behind your ISP router.

Why use Cloudflare Tunnel instead of Tailscale?

Tailscale rocks for mesh networking, but sometimes you need a publicly routable URL—maybe you’re demoing an agent to a client or triggering workflows from Zapier. Cloudflare Tunnel gives you:

  • No exposed port on your router. Outbound https traffic only.
  • A real hostname under your own domain. Free wildcard SSL.
  • Optional Zero Trust policies (OIDC, One-Time PIN, service auth).
  • Price: $0 for up to 100 tunnels.
  • No additional agent on your laptop; a browser is enough.

Trade-offs: latency is ~50 ms higher than a direct local connection, and you’re trusting Cloudflare’s edge to terminate TLS. For my home lab that’s fine; for regulated workloads, read your compliance docs.

Prerequisites

  • An OpenClaw instance running locally (gateway on localhost:3000 by default). Version pinned at v0.37.2 as of this writing, Node 22.3 LTS.
  • A free Cloudflare account with a domain onboarded (the free plan works).
  • sudo access on the machine — examples assume Raspberry Pi OS 64-bit but any Debian/Ubuntu box works.
  • Approx. 15 minutes and coffee.

Step 1 — Install cloudflared on your Pi

Cloudflare provides native packages. The repo has pinned signatures; don’t curl random scripts.

# Add Cloudflare's GPG key type -a curl >/dev/null || sudo apt install -y curl sudo mkdir -p /usr/share/keyrings curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | \ sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null # Add the apt source (Debian/Ubuntu/PI OS) echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared bookworm main" | \ sudo tee /etc/apt/sources.list.d/cloudflared.list sudo apt update && sudo apt install -y cloudflared # Verify version cloudflared --version # expected >= 2024.6.0

If you’re on Alpine, Arch, or macOS, use their native package managers; binary parity is good across the board.

Step 2 — Authenticate and create the tunnel

Log in and let Cloudflare drop a cert into ~/.cloudflared:

cloudflared tunnel login

A browser pops up, you pick your domain, and a cert appears. Now create a named tunnel. I like to tie the name to the machine:

cloudflared tunnel create pi-openclaw

You’ll see something like:

Created tunnel 2c3313f5-e359-424f-bfee-79e4e0c6b90f

Copy the UUID; you’ll need it in the config file.

Step 3 — Wire up a DNS record

Still on the command line:

cloudflared tunnel route dns pi-openclaw claw.mydomain.com

This creates a CNAME that points claw.mydomain.com to a Cloudflare *.cfargotunnel.com record. DNS propagates instantly inside Cloudflare’s resolver network.

Step 4 — Run OpenClaw through the tunnel locally

We’ll map the private service http://localhost:3000 to the public hostname.

mkdir -p ~/.cloudflared cat > ~/.cloudflared/config.yml <<'YAML' tunnel: 2c3313f5-e359-424f-bfee-79e4e0c6b90f # UUID from step 2 credentials-file: /home/pi/.cloudflared/2c3313f5-e359-424f-bfee-79e4e0c6b90f.json ingress: - hostname: claw.mydomain.com service: http://localhost:3000 - service: http_status:404 YAML

Test it:

cloudflared tunnel run pi-openclaw

Hit https://claw.mydomain.com from your phone’s LTE network. If OpenClaw’s login screen appears, you’ve punched through CGNAT without touching the router.

Step 5 — Lock it down with Zero Trust access policies

Exposing an AI agent with shell access is risky. Cloudflare’s free plan lets you enforce one policy per application; that’s enough for basic auth.

  1. Open the Cloudflare dashboard → Zero Trust → Access → Applications → Add Application.
  2. Choose Self-hosted, set Application name to openclaw, Domain to claw.mydomain.com.
  3. Add a policy Require login. Methods:
    • One-Time PIN (Cloudflare emails a code to any address on an allow-list).
    • GitHub OIDC (my preference—most devs already have GitHub).
    • Google, Microsoft, or any SAML 2.0 provider.
  4. Save.

Result: hitting the site now prompts for your chosen identity provider before traffic leaves Cloudflare’s edge. OpenClaw never sees unauthenticated requests.

If you really want old-school basic auth, Cloudflare Access also supports service tokens:

# Generate a token pair a=$(uuidgen); b=$(uuidgen)

Add an Allow policy: “service token equals $a”. Keep $b as the secret; clients send both as CF-Access-Client-Id / CF-Access-Client-Secret headers. Most HTTP clients support that out of the box.

Step 6 — Hardening OpenClaw for the open internet

OpenClaw wasn’t built to be a public SaaS; it assumes you own the box. A few tweaks go a long way:

  • Rotate the default auth token. In ~/.clawcloud/config.json set a long random string for token. Don’t commit this to Git.
  • Disable shell tool unless you need it. Comment it out in agent-config.yml or wrap it behind a role check.
  • Rate-limit POST requests with express-rate-limit if you expose custom HTTP endpoints.
  • Enforce HTTPS in Express:
app.use((req, res, next) => { if (req.headers['x-forwarded-proto'] !== 'https') { return res.redirect(302, 'https://' + req.hostname + req.url); } next(); });
  • Set CORS to your exact hostname:
const cors = require('cors'); app.use(cors({ origin: 'https://claw.mydomain.com', credentials: true }));
  • Audit integrations: Composio tokens stored in env vars? Rotate them quarterly.

Step 7 — Make the tunnel persistent with systemd

The cloudflared Debian package ships a helper:

sudo cloudflared service install

This creates /etc/systemd/system/cloudflared.service pointing at your config.yml. Check:

sudo systemctl enable --now cloudflared sudo systemctl status cloudflared

Reboot the Pi and make sure systemd reports “active (running)”. Cloudflare will also show a green heartbeat under Zero Trust → Tunnels.

Step 8 — Debugging common issues

Cloudflare Tunnel says “connection dropped” every few minutes
Your Pi’s time might drift. Install chrony or make sure systemd-timesyncd is enabled; TLS fails if the clock is off by >5 minutes.

OpenClaw UI loads but API calls 403
You’re hitting the API from JavaScript and the browser blocks CORS. Add Access-Control-Allow-Origin: https://claw.mydomain.com in Express or configure Cloudflare’s Transform Rules → Response Headers.

Zero Trust auth loops after GitHub login
Check that the application domain matches exactly the tunnel hostname; Cloudflare is case-sensitive and ignores www. prefixes.

IPv6 devices can’t connect
Nothing to fix: Cloudflare automatically serves dual-stack. If you toggled the IPv6 Compatibility flag off, turn it back on.

Step 9 — What this costs (spoiler: still free)

  • Cloudflare Tunnel: unlimited bandwidth, 100 tunnels, 1000 DNS records.
  • Zero Trust Access: first 50 users free. If you’re reading this, you’re probably using 1-2 seats.
  • Domain renewal: $8–$12/year if you went with Cloudflare Registrar.

Compared to Tailscale’s free plan, Cloudflare wins on public accessibility and loses on private mesh capabilities. I keep both in my toolbox.

Next steps

At this point you have a live, authenticated URL for your OpenClaw instance. Ship the link to your team, trigger webhooks from GitHub Actions, or let your Telegram bot hit it directly. If you outgrow the Pi, drop the same config.yml onto an EC2 micro or a DigitalOcean droplet—Cloudflare doesn’t care where the origin lives. The important bit is that you never again need to beg an IT admin for port forwarding.

If you build something cool with this setup, please share in the GitHub Discussions. We’re collecting real-world deployment recipes and yours could be the next one we document.