Self-hosting thump
thump runs entirely on Cloudflare: Workers (API + dashboard + status pages), D1 (config + state), KV (sessions + cache), Durable Objects (probe schedulers + incident coordinator), and Analytics Engine (probe time-series). Everything fits the free Workers plan except the browser monitor kind (real-browser checks), which needs Browser Rendering on a paid plan — every other feature degrades cleanly without it.
This guide takes you from clone to a working deployment on your own Cloudflare account.
1. Prerequisites
- A Cloudflare account (free is fine), with a domain on Cloudflare DNS if
you want custom domains for the app itself or for status pages
- Node 20+, pnpm 9+
wrangler(bundled — every command below runs throughpnpm exec)
git clone https://github.com/rbaljinder/thump && cd thump
pnpm install
cd apps/api
pnpm exec wrangler login
2. Create the Cloudflare resources
pnpm exec wrangler d1 create thump-db
pnpm exec wrangler kv namespace create SESSIONS
Each command prints an id. Open apps/api/wrangler.toml and replace:
[[d1_databases]]→database_idwith your D1 id[[kv_namespaces]]→idwith your KV namespace id[vars]→CF_ACCOUNT_IDwith your account id (wrangler whoami)routes→ your own domains (or delete theroutesblock to use the
default *.workers.dev URL to start)
The Analytics Engine dataset needs no provisioning — it is created on the first write. Durable Objects are declared in the file and created on deploy.
3. Apply the database migrations
pnpm exec wrangler d1 migrations apply thump-db --remote
Idempotent — safe to re-run on every upgrade (the deploy workflow does exactly this before each code deploy).
4. Configure auth (GitHub OAuth)
Create a GitHub OAuth app (github.com → Settings → Developer settings → OAuth Apps):
- Homepage URL:
https://<your-domain> - Callback URL:
https://<your-api-domain>/auth/github/callback
Then set the public half in wrangler.toml [vars] (GITHUB_CLIENT_ID, GITHUB_REDIRECT_URI) and the secret half:
pnpm exec wrangler secret put GITHUB_CLIENT_SECRET
Google OAuth works the same way (GOOGLE_* vars + wrangler secret put GOOGLE_CLIENT_SECRET) and is optional — GitHub-only sign-in is fine. Passkeys need no configuration.
5. Secrets
Set with pnpm exec wrangler secret put <NAME> from apps/api/. Local equivalents go in apps/api/.dev.vars (gitignored).
Core (set these):
| Secret | Powers | Notes |
|---|---|---|
GITHUB_CLIENT_SECRET | Sign-in | From step 4 |
THUMP_VAULT_KEY | Secrets vault encryption at rest | openssl rand -hex 32. Without it, production vault writes fail closed |
CF_API_TOKEN | Uptime charts, latency history, world map | API token with Account Analytics: Read |
RESEND_API_KEY | Email alerts, invitations, status-page subscriber email | resend.com; verify your sending domain, set RESEND_FROM_EMAIL in [vars] |
Optional, feature-gated (skip freely — each degrades with a clear message):
| Secret / var | Powers |
|---|---|
GOOGLE_CLIENT_SECRET (+ GOOGLE_* vars) | Google sign-in |
SLACK_CLIENT_SECRET (+ SLACK_* vars) | "Add to Slack" OAuth install (pasting a webhook URL works without it) |
ANTHROPIC_API_KEY | AI drafting + self-repair for browser synthetics |
TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_FROM_NUMBER | SMS + voice-call alert channels |
VAPID_PRIVATE_KEY (+ VAPID_PUBLIC_KEY, VAPID_SUBJECT) | Web push notifications — generate with node scripts/generate-vapid-keys.mjs |
CF_HOSTNAMES_API_TOKEN (+ CF_ZONE_ID var) | Custom domains for status pages (Cloudflare for SaaS; token needs Zone: SSL and Certificates: Edit) |
CF_CACHE_PURGE_TOKEN | Edge-cache purge on incident transitions (Zone: Cache Purge) |
OPS_ALERT_WEBHOOK_URL | Self-alerting — a JSON POST when thump's own Worker throws an unhandled error. Needs nothing else configured, so it's the one that works on a fresh deploy |
OPS_ALERT_EMAIL | Same alert by email (requires RESEND_API_KEY) |
Watching your own instance
Two layers, both worth turning on:
1. Self-alerting. Set OPS_ALERT_WEBHOOK_URL (and/or OPS_ALERT_EMAIL). When a request throws, thump posts you the error signature, first/last seen, and an occurrence count. Alerts are deduped by signature with a 15-minute cooldown, so a page failing on every request pages you once per window rather than once per request — and the count tells you how bad it is. With neither set, errors are logged only (the previous behaviour).
2. Self-monitoring. POST /api/v1/admin/bootstrap-self-monitoring (platform-admin only, idempotent) creates thump's own monitors and publishes them at /status/thump. It covers the public surfaces and two authed API checks — the dashboard overview and check history — because unauthed checks alone will happily stay green while a signed-in page is 500ing.
The authed checks need a token: create a personal access token under Settings → API tokens, then store it in the vault under Secrets with the exact name THUMP_SELF_PAT. The bootstrap response tells you if it's missing. Until then those two checks fail with an auth error.
6. First deploy
The Worker serves the built dashboard itself, so build the web app first:
cd ../web && pnpm run build && cd ../api
pnpm exec wrangler deploy
Visit your domain: the landing page should render, and sign-in should round-trip through GitHub. The 1-minute cron trigger (declared in wrangler.toml) starts the incident coordinator automatically.
Browser Rendering (optional, paid plans): the [browser] binding is deliberately absent from the committed wrangler.toml (wrangler v3 rejects it in local dev). To enable browser monitors, append it just before deploying — this is exactly what the CI workflow does:
printf '\n[browser]\nbinding = "BROWSER"\n' >> wrangler.toml
pnpm exec wrangler deploy
git checkout wrangler.toml
7. Continuous deploys (GitHub Actions)
.github/workflows/deploy.yml deploys on every push to main: builds the web app, applies D1 migrations, appends the browser binding, and runs wrangler deploy. To use it on your fork, set two repo secrets:
CLOUDFLARE_API_TOKEN—Workers Scripts: Edit+D1: Edit(+ zone
permissions if using custom domains)
CLOUDFLARE_ACCOUNT_ID— your account id
8. Post-deploy checklist
- Make yourself platform admin (unlocks
/app/adminplatform metrics):pnpm exec wrangler d1 execute thump-db --remote \ --command "UPDATE users SET role='platform_admin' WHERE email='<you>'" - Monitor thump with thump — Settings → "Self-monitoring" bootstraps
monitors for your own deployment.
- Create your first monitors, alert channels, and (optionally) an on-call
schedule — see the monitoring guide and on-call guide.
Upgrading
git pull
pnpm install
…then push to main (CI path) or repeat step 6 (manual path). Migrations are ordered, additive, and idempotent; code and schema deploy together.
Local development
No Cloudflare account needed — everything runs in wrangler's local simulator:
cd apps/web && pnpm run build && cd ../api
pnpm exec wrangler d1 migrations apply DB --local
pnpm exec wrangler dev --port 4001 --local --var DEV_AUTO_LOGIN:true
DEV_AUTO_LOGIN=true signs you in as a local "Dev Admin" without OAuth. See CONTRIBUTING.md for the test suites and project conventions.