A status page that keeps beating when your server does not — one Cloudflare Worker, or one container you own. Astro, a probe a minute, D1 or SQLite.
A status page that keeps beating when your server does not —
one Cloudflare Worker, or one container on a machine you own.
Astro renders the page, a probe checks every monitor once a minute, and
the history lives in a database next to it. On Cloudflare that is one
Worker with a cron trigger and D1, inside the free tier. On your own
hardware it is one container with an interval and a SQLite file — same
source, same schema. nabız is Turkish for “pulse”; the ASCII spelling
nabiz is used throughout.
| Cloudflare | deploying the Worker, custom hostname, limits |
| Self-hosting | Docker, compose, from a checkout |
| Kubernetes | manifests, one replica, seeding in-cluster |
| Monitors | the rows that say what is watched |
| Configuration | every variable, on both runtimes |
| API | JSON, RSS, badge, notices, machine access |
| Upgrading | schema additions, moving between runtimes |
| Installing with an agent | a runbook: commands, checks, and what each error means |
fail_thresholdllms.txt.Not included: incident timelines, subscriber emails, multi-region probes.
On your own machine
docker run -d --name nabiz -p 8080:8080 -v nabiz:/data \
-e NABIZ_TITLE="status" -e ADMIN_TOKEN="$(openssl rand -hex 32)" \
ghcr.io/productdevbook/nabiz:latest
On Cloudflare
git clone https://github.com/productdevbook/nabiz && cd nabiz && bun install
bunx wrangler d1 create nabiz # id goes into wrangler.toml
bunx wrangler d1 execute nabiz --remote --file schema.sql
bun run deploy
Either way the page comes up empty and working — a heading with nothing
under it is the correct first sight. Monitors are rows you add next, and
the first bar appears within one probe interval: see
Monitors. Keep the token you generated above; it is what lets you write notices.
Nothing on the page prints it again — docker inspect nabiz will, which
is also a reason not to leave it on a machine other people can reach.
bun install
bunx wrangler d1 execute nabiz --local --file schema.sql # once
bun run dev # :4321, local D1
bun run check # what CI runs
Everything under src/lib/ is plain TypeScript against a narrow database
interface (src/lib/db.ts) that D1 already satisfies and SQLite is made to
(src/lib/sqlite.ts). That seam is the whole difference between the two
runtimes: the page, the probes and the state machine are one copy.
MIT. Icons from Lucide (ISC).