OpenClaw Cloudflare Plugin Deployment¶
Plugin: openclaw-cloudflare v0.3.1
Host: SRV1 (10.0.20.30)
Public URL: https://openclaw.gntech.me
Tunnel: Cloudflare Tunnel (cloudflared system service)
Architecture¶
[Browser] ── HTTPS ──▶ [Cloudflare Edge]
│
Cloudflare Access (JWT)
│
Cloudflare Tunnel
│
┌────────▼────────┐
│ cloudflared │
│ systemd service│
│ localhost:18789│
└────────┬────────┘
│
┌────────▼────────┐
│ OpenClaw GW │
│ port 18789 │
│ loopback bind │
└────────┬────────┘
│
openclaw-cloudflare
plugin verifies JWT
- User hits
https://openclaw.gntech.me - Cloudflare Access prompts for authentication (Google, etc.)
- After auth, Access injects a
Cf-Access-Jwt-Assertionheader - Cloudflare Tunnel forwards the request to
localhost:18789 - OpenClaw gateway receives it — the
openclaw-cloudflareplugin verifies the JWT - Sets
x-openclaw-user-emailheader so OpenClaw knows who the user is
Components¶
1. cloudflared (systemd service)¶
- Binary:
/usr/bin/cloudflared - Service:
cloudflared.service(system-wide, enabled) - Run mode:
--no-autoupdate tunnel run --token <TOKEN>(token-based, no config file) - Origin:
http://localhost:18789(OpenClaw gateway) - Auto-update: Separate
cloudflared-update.timer(daily, restarts service on update) - Reference:
/etc/systemd/system/cloudflared.service
2. OpenClaw Gateway¶
- Port:
18789 - Bind:
loopback(only accessible from localhost / cloudflared) - Auth mode:
password(falls back to password when JWT is absent — e.g., local access) - Trusted proxies:
127.0.0.1,::1
3. openclaw-cloudflare Plugin (v0.3.1)¶
- Install path:
/home/gntech/.openclaw/extensions/openclaw-cloudflare - Config:
access.teamDomain:gntechaccess.audience:79654618ea78e72bf7f30a311aa428a7b37aee532552d76f7c892b620f6633ae
When a request has a Cf-Access-Jwt-Assertion header, the plugin:
1. Fetches Cloudflare's JWKS from https://gntech.cloudflareaccess.com/cdn-cgi/access/certs
2. Verifies signature (RS256), issuer, expiry, and AUD tag
3. Sets x-openclaw-user-email with the authenticated user's email
4. Sets x-openclaw-auth-source: cloudflare-access
JWKS keys are cached for 10 minutes with automatic refresh on rotation.
4. Cloudflare Access Application¶
- Application type: Self-hosted
- Domain:
openclaw.gntech.me - Auth providers: (configured in Cloudflare Zero Trust dashboard → Access → Applications)
Installation / Replication¶
Step 1 — Install cloudflared¶
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb -o /tmp/cloudflared.deb
dpkg -i /tmp/cloudflared.deb
Step 2 — Create a tunnel¶
- Go to Cloudflare Zero Trust → Networks > Tunnels
- Create a new tunnel → Cloudflared → name it
- Under Public Hostnames, add a hostname pointing to
http://localhost:18789 - Copy the tunnel token
Step 3 — Install tunnel as system service¶
cloudflared service install <TUNNEL_TOKEN>
systemctl enable cloudflared
systemctl start cloudflared
Step 4 — Install OpenClaw gateway + plugin¶
# Start the gateway once to create the config
openclaw gateway start
# Install the plugin
openclaw plugins install openclaw-cloudflare
Step 5 — Configure openclaw.json¶
Edit ~/.openclaw/openclaw.json:
{
"gateway": {
"bind": "loopback",
"port": 18789,
"auth": {
"mode": "password"
},
"trustedProxies": ["127.0.0.1", "::1"]
},
"plugins": {
"entries": {
"openclaw-cloudflare": {
"config": {
"access": {
"teamDomain": "TEAM_DOMAIN",
"audience": "AUD_TAG"
}
},
"enabled": true
}
}
}
}
Step 6 — Configure Cloudflare Access¶
- In Cloudflare Zero Trust → Access > Applications
- Add an application → Self-hosted
- Application domain:
your-openclaw-hostname.com - Set identity providers and access policies
- Find your AUD tag (TAG) on the application page
Step 7 — Restart gateway¶
systemctl --user restart openclaw-gateway.service
Auto-update Timer¶
A system timer automatically updates cloudflared daily:
cloudflared-update.service:
[Unit]
Description=Update cloudflared
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/bin/bash -c '/usr/bin/cloudflared update; code=$?; if [ $code -eq 11 ]; then systemctl restart cloudflared; exit 0; fi; exit $code'
cloudflared-update.timer:
[Unit]
Description=Update cloudflared
[Timer]
OnCalendar=daily
[Install]
WantedBy=timers.target
Gateway Config (current)¶
{
"gateway": {
"mode": "local",
"bind": "loopback",
"port": 18789,
"auth": {
"mode": "password"
},
"controlUi": {
"allowInsecureAuth": true,
"allowedOrigins": ["https://openclaw.gntech.me"]
},
"trustedProxies": ["127.0.0.1", "::1"],
"nodes": {
"denyCommands": [
"camera.snap", "camera.clip", "screen.record",
"contacts.add", "calendar.add", "reminders.add",
"sms.send", "sms.search"
]
}
}
}
Troubleshooting¶
Check cloudflared status¶
systemctl status cloudflared
journalctl -u cloudflared -n 50 --no-pager
Check gateway logs¶
journalctl --user -u openclaw-gateway.service -n 50 --no-pager
Gateway unreachable errors¶
Unable to reach the origin service: dial tcp [::1]:18789: connect: connection refused
This means cloudflared is running but the OpenClaw gateway is down. Restart the service:
systemctl --user restart openclaw-gateway.service
Verify JWT validation¶
Access https://openclaw.gntech.me in a browser — if Cloudflare Access prompts you to log in, JWT flow is working. If you get a raw OpenClaw password prompt instead, the plugin may not be active or the Access app isn't configured for this hostname.