One Message per Transition
After a configurable streak of consecutive failures (default 2), you get one DOWN alert. When the server recovers, one UP alert. A server that's down for six hours costs you two texts, not 360.
Open Source · MIT · Cloudflare Worker · Updated July 2026
Foghorn is a dead-man watchdog for your server, not another status page. One cron-triggered Cloudflare Worker, one source file, and one SMS or webhook message per up/down transition — that's the entire feature list, on purpose. State is written only when something changes, so a healthy server costs zero KV writes and the whole thing idles far inside Cloudflare's free tier, forever.
Free & open source · one source file · zero KV writes while healthy · no servers to host
Every serverless uptime project we could find is a status page that also monitors — dashboards, history charts, geo-checks, database migrations. All good things. But when your server dies at 2am, a Discord ping doesn't wake you up.
A text does.
So this project competes on the other axis: small enough to read over coffee, simple enough to never touch again, and frugal enough to run free until the heat death of the universe. It lives on Cloudflare's edge — outside the blast radius of the thing it's monitoring — with nothing watching the watcher and nothing else to keep alive.
After a configurable streak of consecutive failures (default 2), you get one DOWN alert. When the server recovers, one UP alert. A server that's down for six hours costs you two texts, not 360.
Cloudflare's free tier allows 1,000 KV writes a day; a naive write-every-minute monitor burns 1,440. Foghorn writes state only on a change — a healthy server does zero writes and about 1,440 reads a day per URL against a 100,000/day read quota. It runs free, forever, and never gets close to the limits.
It's a dead-man alarm, so an alert that didn't send didn't happen. If every configured notifier fails — Twilio rejects, the webhook 500s — the transition is not committed, and the Worker retries on the next cron run until one notifier actually delivers.
Twilio SMS — the reason this exists; costs you a Twilio account and pennies per outage. Generic webhook — POSTs JSON carrying both text and content keys, so a Slack or Discord webhook URL works as-is, and anything else can read either field.
Any 2xx/3xx counts as up. A 4xx, a 5xx, a 10-second timeout, or a refused connection all count as down — if your homepage starts throwing 500s, that's an outage, whatever the TCP handshake thinks. Checks are cache-busted, so they always hit the origin.
Watch one URL or a comma-separated list — each gets its own failure streak and its own alerts. One source file, TypeScript, a vitest suite, and nothing to host: clone, configure, wrangler deploy, done.
Every minute, Cloudflare's cron fires the Worker. It fetches each URL you're watching — cache-busted, so it always hits the origin — and judges the response: 2xx/3xx is up; an error status, a 10-second timeout, or a refused connection is down.
One bad check isn't an outage. Each URL keeps its own failure streak in Workers KV, and only after the threshold of consecutive failures (default 2 — about two minutes of confirmed downtime) does a transition begin.
One DOWN message goes out via Twilio SMS or your webhook; the transition is committed only once a notifier actually delivers, and retried next minute if none did. Then silence — until the server recovers and a single UP message closes the loop.
They're status pages that also monitor — dashboards, uptime history, multi-region checks, UIs. All legitimate wants, and if you want them, use Uptime Kuma or UptimeFlare; they're good at it. Foghorn competes on the other axis: it's a dead-man alarm. One source file, no dashboard, no history, and exactly one message per up/down transition. Small enough to read over coffee, simple enough to never touch again — and feature requests that would grow it into a status page are lovingly declined.
Yes, by design. Cloudflare's free tier allows 1,000 KV writes per day, and a naive monitor that writes state every minute burns 1,440 — over quota on day one. Foghorn writes KV only when something changes, so a healthy server does zero writes. What it does do is read: about 1,440 reads per day per URL, against a 100,000-per-day free quota. It never gets close to the limits. The only thing that can cost money is Twilio, at pennies per outage.
A check counts as up on any 2xx or 3xx response. A 4xx, a 5xx, a timeout (10 seconds), or a refused connection all count as down — if your homepage starts throwing 500s, that's an outage, whatever the TCP handshake thinks. Checks are cache-busted so they always hit the origin, and a DOWN alert fires only after a configurable number of consecutive failures (default 2 — about two minutes of confirmed downtime before your phone buzzes).
Because it's a dead-man alarm, delivery is part of the state machine. If every configured notifier fails to send — Twilio rejects, the webhook 500s — the transition is not committed, and the Worker retries the alert on the next cron run until one notifier actually delivers. A down server can't slip through a notification hiccup.
A free Cloudflare account and Wrangler — clone, configure, deploy; there are no servers to host and no containers. For SMS you'll need a Twilio account (the reason this exists — it costs pennies per outage). For everything else, any Slack- or Discord-compatible webhook URL works as-is. You can watch one URL or several, comma-separated, each with its own failure streak and its own alerts.
Yes — MIT licensed. The code, docs, and issue tracker are on GitHub, with a full mirror on GitLab. Built because our server needed watching and everything else wanted to be a product.
Further reading: A status page won't wake you up — why it's a dead-man alarm, not a dashboard · Zero KV writes while healthy — the free-tier arithmetic.
Clone it, paste in your URLs and a notifier, and wrangler deploy. MIT licensed — issues and PRs welcome.