Uptime monitor that runs on Cloudflare Workers. Checks HTTP endpoints, TCP ports, and TLS certificates on a cron schedule. Stores results in D1. Shows a status page with live updates over WebSocket.
- A Cloudflare account (free tier works)
- Node.js and pnpm
- Wrangler CLI authenticated (
pnpm dlx wrangler login)
- Fork and clone the repo. Install dependencies:
pnpm install
- Create a D1 database:
cd worker
pnpm exec wrangler d1 create uppies
Copy the database_id from the output into worker/wrangler.toml, replacing your-d1-database-id-here.
- Apply the schema:
cd worker
pnpm exec wrangler d1 execute uppies --remote --file=src/db/schema.sql
-
Edit
monitors.ymlat the repo root with the endpoints you want to monitor. Each monitor needs anid,name,type(http, tcp, or tls), and a target (urlfor http/tls,host/portfor tcp). -
Seed the monitors into D1:
pnpm seed:remote
-
Remove or update the
[[routes]]block inworker/wrangler.toml. Delete it to use the default*.workers.devURL, or set the pattern to your own domain. -
Deploy:
pnpm deploy
The cron runs every minute. Each monitor runs according to its interval_seconds setting. Results show up at your worker URL.
If you'd rather deploy via GitHub Actions on push to main, skip steps 2-3 and 5-7 above and set these in your repo settings under Settings > Secrets and variables > Actions:
| Type | Name | Required | Description |
|---|---|---|---|
| Secret | CLOUDFLARE_API_TOKEN |
Yes | API token with Workers and D1 permissions |
| Secret | CLOUDFLARE_ACCOUNT_ID |
Yes | Your Cloudflare account ID |
| Secret | CLOUDFLARE_D1_DATABASE_ID |
Yes | D1 database ID from wrangler d1 create |
| Variable | SITE_DOMAIN |
No | Custom domain (omit to use *.workers.dev) |
| Variable | SITE_TITLE |
No | Page title (default: Uppies) |
| Variable | SITE_THEME |
No | Default theme (default: cyberpunk) |
| Variable | SITE_THEMES |
No | Available themes list |
| Variable | CACHE_TTL |
No | API cache seconds (default: 30) |
| Variable | MAX_BODY_BYTES |
No | Max body read size (default: 1048576) |
| Variable | HISTORY_DAYS |
No | Days of history shown (default: 90) |
The included workflow handles schema migration, monitor seeding, and deploy automatically on every push.
Add a notify block to any monitor in monitors.yml:
notify:
- type: discord
url: $DISCORD_WEBHOOK_URL
on: [down, recover]URLs starting with $ are resolved from worker secrets:
cd worker
pnpm exec wrangler secret put DISCORD_WEBHOOK_URL
Supported types: discord, webhook. If the secret is missing, notifications are silently skipped.
These are set in worker/wrangler.toml under [vars]:
| Variable | Default | What it does |
|---|---|---|
| SITE_TITLE | Uppies | Page title |
| SITE_THEME | cyberpunk | Default theme |
| SITE_THEMES | cyberpunk,terminal,clean-dark,light,corporate | Comma-separated list of themes available in the switcher |
| CACHE_TTL | 30 | API cache duration in seconds |
| MAX_BODY_BYTES | 1048576 | Max response body size read during HTTP checks |
| HISTORY_DAYS | 90 | How many days of check history to show |
cd worker
pnpm exec wrangler d1 execute uppies --local --file=src/db/schema.sql
cd ..
pnpm seed
pnpm dev
Opens at http://localhost:8787. The dev script includes --test-scheduled, so you can trigger the cron manually by hitting http://localhost:8787/__scheduled.
monitors.yml - define what to monitor
worker/ - Cloudflare Worker (cron, API, WebSocket)
app/ - Svelte 5 frontend (status page)
tokens/ - design tokens (Style Dictionary)
scripts/ - seed script