Skip to content

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
  1. User hits https://openclaw.gntech.me
  2. Cloudflare Access prompts for authentication (Google, etc.)
  3. After auth, Access injects a Cf-Access-Jwt-Assertion header
  4. Cloudflare Tunnel forwards the request to localhost:18789
  5. OpenClaw gateway receives it — the openclaw-cloudflare plugin verifies the JWT
  6. Sets x-openclaw-user-email header 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: gntech
  • access.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

  1. Go to Cloudflare Zero TrustNetworks > Tunnels
  2. Create a new tunnel → Cloudflared → name it
  3. Under Public Hostnames, add a hostname pointing to http://localhost:18789
  4. 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

  1. In Cloudflare Zero TrustAccess > Applications
  2. Add an applicationSelf-hosted
  3. Application domain: your-openclaw-hostname.com
  4. Set identity providers and access policies
  5. 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.