Skip to content

Instantly share code, notes, and snippets.

@HoraceShmorace
Created April 12, 2026 17:43
Show Gist options
  • Select an option

  • Save HoraceShmorace/ae91d01c705e815ef1c90bbacecfe12e to your computer and use it in GitHub Desktop.

Select an option

Save HoraceShmorace/ae91d01c705e815ef1c90bbacecfe12e to your computer and use it in GitHub Desktop.
OpenClaw x Cloudflare (Mac)

OpenClaw x Cloudflare Tunnel Setup Guide (Mac)

How to expose OpenClaw's webhook endpoint to the public internet so GitHub (or any other service) can trigger your agent.


Prerequisites

  • OpenClaw installed and running as a LaunchAgent on macOS
  • A domain registered with Cloudflare Registrar (DNS is already managed by Cloudflare — no extra nameserver step needed)
  • cloudflared installed: brew install cloudflared

1. Authenticate cloudflared

cloudflared tunnel login

This opens a browser. Authorize your domain. A credentials file is written to ~/.cloudflared/.


2. Create the tunnel

cloudflared tunnel create openclaw

This creates a tunnel and writes a credentials JSON to ~/.cloudflared/<UUID>.json. Note the tunnel ID in the output.


3. Create the config file

Create ~/.cloudflared/config.yml:

tunnel: <your-tunnel-id>
credentials-file: /Users/<your-username>/.cloudflared/<your-tunnel-id>.json

ingress:
  - hostname: openclaw.yourdomain.com
    service: http://localhost:18789
  - service: http_status:404

Replace <your-tunnel-id>, <your-username>, and yourdomain.com with your actual values.


4. Add the DNS record

cloudflared tunnel route dns openclaw openclaw.yourdomain.com

This creates a CNAME in Cloudflare DNS pointing openclaw.yourdomain.com at the tunnel.


5. Verify the tunnel routes correctly

Run the tunnel in the foreground to test:

cloudflared tunnel run openclaw

Then in another terminal:

curl -v https://openclaw.yourdomain.com

You should get a 200 with the OpenClaw Control UI HTML. If so, the tunnel is working.


6. Install as a background service

sudo cloudflared service install

The tunnel now starts automatically on boot. You don't need to run step 5 in production.


7. Configure OpenClaw webhooks

Enable hooks

openclaw config set hooks.enabled true --json
openclaw config set hooks.token "your-long-random-secret"
openclaw config set hooks.path "/hooks"

Create the GitHub transform

OpenClaw needs a transform module to convert GitHub's webhook payload into a message for the agent.

mkdir -p ~/.openclaw/hooks/transforms

Create ~/.openclaw/hooks/transforms/github.mjs:

export default function transform({ payload, headers }) {
  const event = headers['x-github-event'] || 'unknown';
  const action = payload.action || '';
  const repo = payload.repository?.full_name || 'unknown repo';
  const title = payload.issue?.title || payload.pull_request?.title || '';

  return {
    message: `GitHub ${event}${action ? '.' + action : ''} on ${repo}${title ? ': ' + title : ''}`,
    name: 'GitHub',
  };
}

Add the mapping

openclaw config set hooks.mappings '[{
  "match": { "path": "github" },
  "action": "agent",
  "agentId": "main",
  "deliver": true,
  "transform": { "module": "github.mjs" }
}]' --json

Restart the gateway

openclaw gateway restart

8. Test the webhook endpoint

curl -s -o /dev/null -w "%{http_code}" -X POST https://openclaw.yourdomain.com/hooks/github \
  -H "content-type: application/json" \
  -H "x-openclaw-token: your-long-random-secret" \
  -H "X-GitHub-Event: issues" \
  -d '{"action":"opened","repository":{"full_name":"your-org/your-repo"},"issue":{"title":"test issue"}}'

Expected: 200

Then check OpenClaw logs to confirm the agent was triggered:

openclaw logs --follow

9. Add GitHub webhooks

In each repo: Settings → Webhooks → Add webhook

  • Payload URL: https://openclaw.yourdomain.com/hooks/github
  • Content type: application/json
  • Secret: leave blank (OpenClaw uses its own token, not GitHub's HMAC — see note below)
  • Events: select Issues and Pull requests (or whichever events you want)

Note on auth: GitHub webhooks can't add an Authorization: Bearer header — they use X-Hub-Signature-256 HMAC instead. OpenClaw doesn't verify GitHub's HMAC; it uses its own token via x-openclaw-token. Since Cloudflare Tunnel requires HTTPS and the token is in a header (not a query param), this is reasonably secure. For stricter verification, put a relay (like Rehook) between GitHub and OpenClaw to verify the HMAC before forwarding.


Key notes

Cloudflare strips Authorization headers on tunnel traffic. Always use x-openclaw-token instead of Authorization: Bearer when sending to the tunnel URL. Locally (bypassing the tunnel) both headers work.

The transform function signature receives { payload, headers, url, path }. The headers object uses lowercase keys (e.g. x-github-event, not X-GitHub-Event).

match.path in a mapping matches the URL sub-path after /hooks/ — so match: { path: "github" } matches POST /hooks/github. It does not match on payload content.

Token SecretRef: If your token shows as __OPENCLAW_REDACTED__ in openclaw config get, it's stored as a SecretRef. The actual value is what you set when you ran openclaw config set hooks.token. Use that same value in your curl/webhook headers.

Re-authenticating Claude CLI: If the agent runs fail with a billing/auth error after a gateway restart, re-run:

claude auth login
openclaw models auth login --provider anthropic --method cli --set-default
openclaw gateway restart
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment