Every site is monitored twice
I installed Uptime Kuma on my ZimaBoard to watch my sites and the homelab itself. It went on port 3002 and not its default 3001, because an AdGuard install still claims 3001 in its compose file even though it has been stopped for months.
The thing I nearly got wrong: every one of my domains sits behind Cloudflare. A plain HTTP check against the domain proves Cloudflare answered, not that my app is alive. A dead origin can still return a Cloudflare error page.
Two levels per site
So each site is checked twice.
At the edge, by keyword. The monitor matches a string only the real page renders. That is what catches a bad deploy serving the wrong content, which a status code never will.
At the origin, directly. The second monitor bypasses Cloudflare and asks the hosting platform’s own URL. That is what separates “my app is down” from “Cloudflare is having a day”. One of my apps already exposes a /health endpoint returning JSON, so its origin monitor is a JSON query on $.status and not a status code.
I pulled the origin URLs straight out of the hosting dashboard rather than guessing them.
A domain with no website
One domain I look after has no working website at all, only mail. An HTTP monitor there would sit permanently red and teach me nothing, so it gets DNS monitors on its MX and TXT records instead.
That produced a mistake of my own worth admitting. I named one of them “TXT (SPF/DMARC)”, but it queries the apex of the domain, and DMARC never lives there. It is a separate record at _dmarc.<domain>. The label claimed a check that wasn’t being made. I renamed it, and I did not add a DMARC monitor yet, because the record doesn’t exist: a monitor that is always red teaches you to ignore red.
Monitors as code
Uptime Kuma has no config file. Monitors are rows in a SQLite database, created over socket.io, which means an instance built by clicking can’t be reviewed in a diff or rebuilt without clicking it all in again. So mine are a declaration in a Python script:
MONITORS = [
{
"group": "Public sites",
"type": MonitorType.KEYWORD,
"name": "wjmaritz.dev",
"url": "https://wjmaritz.dev",
"keyword": "Wilhelm Maritz",
"expiryNotification": True,
},
{
"group": "Origins",
"type": MonitorType.JSON_QUERY,
"name": "App origin",
"url": "https://<app>.up.railway.app/health",
"jsonPath": "$.status",
"expectedValue": "ok",
"expiryNotification": True,
},
]
The first entry is this site’s real monitor. The second has its URL swapped for a placeholder. The script is re-runnable: a second pass skipped every existing monitor and duplicated nothing. Alerts go to an ntfy topic, and the Homepage dashboard tile reads the public status page, so no API key is involved anywhere.
What it can’t see
All of this runs from inside my house. If the home connection drops, every external monitor goes red and none of those sites are actually down. There is no outside vantage point, and a second instance somewhere external is the only real fix.
