No description
  • JavaScript 100%
Find a file
2026-03-09 22:24:10 +08:00
.claude initial commit 2026-03-09 22:24:10 +08:00
src initial commit 2026-03-09 22:24:10 +08:00
test initial commit 2026-03-09 22:24:10 +08:00
.gitignore initial commit 2026-03-09 22:24:10 +08:00
debug-e2e.mjs initial commit 2026-03-09 22:24:10 +08:00
DESIGN.md initial commit 2026-03-09 22:24:10 +08:00
package-lock.json initial commit 2026-03-09 22:24:10 +08:00
package.json initial commit 2026-03-09 22:24:10 +08:00
README.md initial commit 2026-03-09 22:24:10 +08:00
wrangler.toml initial commit 2026-03-09 22:24:10 +08:00

cloudflare-webhook-proxy

A Cloudflare Worker that receives webhook notifications (e.g. from Netdata, Grafana, Uptime Kuma) and forwards them to Telegram and/or Feishu (Lark) channels. Routes are stored in Workers KV and can be managed dynamically through a built-in admin API and UI — no redeployment needed when adding or changing destinations.

Features

  • Fan-out: one incoming webhook path → multiple Telegram/Feishu destinations
  • Per-route optional Bearer token authentication for incoming webhooks
  • Admin UI at /admin for managing routes through a browser
  • REST API for programmatic route management
  • All credentials stored securely in KV — no secrets in code

Architecture

POST /webhook/<path>  →  look up routes in KV  →  forward to Telegram / Feishu
GET  /admin           →  admin UI (HTML)
/admin/routes         →  CRUD API (requires ADMIN_AUTH_TOKEN)

Prerequisites


Step-by-step deployment

1. Clone and install dependencies

git clone <your-repo-url>
cd cloudflare-webhook-proxy
npm install

2. Log in to Cloudflare

npx wrangler login

This opens a browser window to authorize Wrangler with your Cloudflare account.

3. Create the KV namespace

Routes are stored in a Workers KV namespace. Create two namespaces — one for production and one for preview (local dev):

npx wrangler kv namespace create ROUTES_KV
npx wrangler kv namespace create ROUTES_KV --preview

Each command prints output like:

{ binding = "ROUTES_KV", id = "abc123..." }

Copy the IDs and update wrangler.toml:

[[kv_namespaces]]
binding = "ROUTES_KV"
id = "YOUR_PRODUCTION_ID_HERE"
preview_id = "YOUR_PREVIEW_ID_HERE"

4. Set the admin token secret

Choose a strong random string for ADMIN_AUTH_TOKEN. This is the password for the admin UI and API.

npx wrangler secret put ADMIN_AUTH_TOKEN

When prompted, paste your chosen token and press Enter.

npm test

All 66 tests should pass.

6. Deploy to Cloudflare

npm run deploy

On success, Wrangler prints your worker URL:

Published webhook-proxy (X.XXs)
  https://webhook-proxy.<your-subdomain>.workers.dev

Initial setup: configure your first route

Using the Admin UI

  1. Open https://webhook-proxy.<your-subdomain>.workers.dev/admin in your browser

  2. Enter your ADMIN_AUTH_TOKEN and click Sign In

  3. Click + Add Route and fill in the form:

    Field Description
    Webhook Path URL segment that identifies this source, e.g. netdata
    Platform Telegram or Feishu
    Telegram Chat ID The chat/channel ID, e.g. -100123456789
    Bot Token Your Telegram bot token (Telegram only)
    Feishu Webhook URL The full webhook URL from Feishu (Feishu only)
    Source Auth Token Optional — callers must send this as Bearer token
  4. Click Add Route. The route is live immediately.

Using the API directly

# List all routes
curl https://webhook-proxy.<your-subdomain>.workers.dev/admin/routes \
  -H "Authorization: Bearer <ADMIN_AUTH_TOKEN>"

# Add a Telegram route
curl -X POST https://webhook-proxy.<your-subdomain>.workers.dev/admin/routes \
  -H "Authorization: Bearer <ADMIN_AUTH_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "path": "netdata",
    "platform": "telegram",
    "channel_id": "-100123456789",
    "bot_token": "123456:ABC-DEF...",
    "auth_token": "my-webhook-secret"
  }'

# Add a Feishu route for the same path (fan-out)
curl -X POST https://webhook-proxy.<your-subdomain>.workers.dev/admin/routes \
  -H "Authorization: Bearer <ADMIN_AUTH_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "path": "netdata",
    "platform": "feishu",
    "channel_id": "https://open.feishu.cn/open-apis/bot/v2/hook/xxx",
    "auth_token": "my-webhook-secret"
  }'

# Delete a route
curl -X DELETE https://webhook-proxy.<your-subdomain>.workers.dev/admin/routes/<id> \
  -H "Authorization: Bearer <ADMIN_AUTH_TOKEN>"

Sending a webhook

Point your monitoring tool to:

POST https://webhook-proxy.<your-subdomain>.workers.dev/webhook/<path>
Authorization: Bearer <auth_token>   (if the route requires one)
Content-Type: application/json

Example payload (Netdata-style):

{
  "title": "Disk Space Alert",
  "level": "critical",
  "host": "server1",
  "message": "Disk /var usage is at 95%",
  "value": "95%"
}

The worker accepts any JSON object. Recognized fields (title, level, status, host, message, info, description, timestamp) are formatted into a structured message. All other fields appear under "Details".

Example: Netdata configuration

In health_alarm_notify.conf, set:

SEND_CUSTOM="YES"
DEFAULT_RECIPIENT_CUSTOM="https://webhook-proxy.<your-subdomain>.workers.dev/webhook/netdata"

custom_sender() {
  local webhook_url="${1}"
  curl -s -X POST "${webhook_url}" \
    -H "Authorization: Bearer my-webhook-secret" \
    -H "Content-Type: application/json" \
    -d "{\"title\":\"${alarm}\",\"level\":\"${status}\",\"host\":\"${host}\",\"message\":\"${info}\"}"
}

Local development

npm run dev

Wrangler starts a local server at http://localhost:8787 backed by a local KV store. Changes to source files are hot-reloaded.

Note: On first dev run, Wrangler creates a local KV store automatically using the preview_id. No extra setup is needed.


Admin API reference

All endpoints (except GET /admin) require Authorization: Bearer <ADMIN_AUTH_TOKEN>.

Method Path Description
GET /admin Admin UI (HTML page)
GET /admin/routes List all routes
POST /admin/routes Create a route
GET /admin/routes/:id Get a single route
PUT /admin/routes/:id Update a route
DELETE /admin/routes/:id Delete a route

Route object

{
  "id":         "uuid (auto-generated, immutable)",
  "path":       "url-segment",
  "platform":   "telegram | feishu",
  "channel_id": "telegram chat id or feishu webhook url",
  "bot_token":  "telegram bot token (null for feishu)",
  "auth_token": "required bearer token for callers (null = public)"
}

Updating the worker

After editing source files:

npm run deploy

Routes stored in KV are unaffected by redeployments.

Running a specific environment

npm run deploy -- --env production
npm run deploy -- --env staging

Remember to create separate KV namespaces for each environment and update wrangler.toml under [env.production] / [env.staging] accordingly.