DEV Community

Cover image for Uptime Cairn: a self-hosted uptime monitor built to survive 5,000 monitors
Shakil Ilham
Shakil Ilham

Posted on

Uptime Cairn: a self-hosted uptime monitor built to survive 5,000 monitors

Most self-hosted uptime monitors are fine until they aren't. Uptime Kuma is the community default, it has 88k stars and roughly 40 monitor types, and it deserves every bit of that. But it pushes full state to every connected browser over Socket.IO, so somewhere around 300 to 600 monitors the dashboard becomes unusable. The community workaround is to run a second Kuma on another host. Then a third.

I have spent the last several months building Uptime Cairn as an answer to that specific wall, and to a few others. This post is what it can do right now, the one decision that shaped everything else, and an honest list of what is still missing. If you run more than a handful of checks, the last section is probably the one you want.

What it does today

It watches HTTP and HTTPS endpoints (status code, keyword, JSON path, regex, response time threshold), TCP ports, ICMP, DNS records, Docker containers, gRPC services, and push heartbeats for cron jobs that are supposed to check in. It also watches the two things that quietly kill you on a Sunday: TLS certificates and domain registrations approaching expiry.

When something breaks it tells you over email, Slack, Discord, Telegram, Matrix, ntfy, Gotify, Teams, PagerDuty, Opsgenie, SMS or a webhook. Apprise ships as a meta-provider, which adds roughly ninety more destinations without ninety more integrations to maintain. Webhook payloads are user-defined: your own body, headers and method, with variable interpolation like {{monitor.name}} and {{response_time}}, and a live preview so you find out the JSON is malformed before an incident does.

On top of that there are groups and tags, dependency-aware suppression so one dead router doesn't page you forty times, retries, maintenance windows, check intervals down to 20 seconds, and public status pages on your own domain with your own logo. Everything the UI does, the REST API does, because the OpenAPI spec was frozen before the first line of product code was written. The dashboard is just the first API client, not a privileged one. Prometheus metrics are exposed if you want to monitor the monitor.

Storage is SQLite by default. No Postgres to provision, no Redis, no message broker. One container, one volume.

Getting it running

docker run -d --restart=always -p 127.0.0.1:3000:3000 \
  -v uptime-cairn:/data \
  --name uptime-cairn \
  ghcr.io/webloomlabs/uptime-cairn:latest
Enter fullscreen mode Exit fullscreen mode

Open http://localhost:3000, create an account, add a monitor. The port binds to loopback deliberately, because Cairn speaks plain HTTP and expects Caddy, nginx or Traefik in front of it. There is a Compose file, a plain binary, and it cross-compiles to ARM, so a Pi is a perfectly reasonable home for it.

One thing worth knowing before you set up backups. Your data lives in two files, cairn.db and cairn.key. Back up both. The key encrypts saved passwords and tokens, and a database without it is a database with holes in it. This catches people, so I have put it in the README in bold and I am putting it here too.

Already on Uptime Kuma

cairn import kuma /path/to/kuma.db
Enter fullscreen mode Exit fullscreen mode

That reads the Kuma SQLite file and reproduces your monitors, tags, notifications and status pages. Point it at several Kuma databases and it merges them into one install, which is the whole point for anyone currently sharding by hand across hosts. Run it with --dry-run first, and read what doesn't come across before you commit to it. Some things genuinely do not map, and I would rather you know which ones on a Tuesday afternoon than during an outage.

The decision everything else hangs on

Cairn splits the control plane from the probe. Probes are stateless agents that register with the control plane over gRPC and pull their assignments. That split went in during week one, because it is the kind of thing you cannot retrofit later without rewriting the product.

In solo mode you never see it. The probe is compiled into the same binary and runs in-process, and docker run gives you one container that does everything. Opt into scaled mode and the same binary becomes a control plane with probes reporting from other regions, other VPCs, or behind a firewall where the agent dials out and you open no inbound ports. Same codebase, different flags. Moving from one shape to the other is a config change and a migration, never a reinstall and never a different product.

The stack, since this is Dev.to: Go for the backend and probe, SvelteKit and Tailwind for the frontend, SQLite or Postgres with Timescale, gRPC and Protobuf between control plane and probes, Playwright in an optional sidecar for browser checks later, Typst for PDF reports.

About the 5,000 number

The headline claim is 5,000 monitors on one install with a UI that stays responsive, and it is enforced by a load test in CI rather than measured once and put in a README. The gate spins up a real engine at 500 monitors and at 5,000, compares them, and fails the build when a per-page cost grows with install size instead of with the viewport. Server-side pagination, filtering and search everywhere. The client is never sent full state.

That test earned its keep before v1.0: it caught exactly that regression in the dashboard's own listing query, in a change that looked completely harmless in review.

What it can't do yet

This is the part I would want to read first, so it is not buried at the bottom.

There is one user account. No RBAC, no SSO, no audit log, no on-call rotations or escalation policies, so alerts fire immediately every time and there is no business-hours suppression. Reporting is in progress: you get uptime history and incidents, but not scheduled PDFs, SLA and error budget tracking, or white-labelled monthly reports. Monitoring runs from one location, so multi-region consensus checking is not there yet, and neither is HA. Browser and synthetic checks, SNMP, MQTT and database checks are all further out.

The project is also young. If you currently rely on Kuma for something that pays your bills, run Cairn beside it for a couple of weeks and see whether both agree about reality before you switch off the old one. That is what I would do.

Where it goes next

Reporting is the current focus, and it is deliberately ahead of the enterprise controls in the queue, because a monthly client report assembled by hand in a spreadsheet is the thing people actually lose their afternoons to. Scheduled and auto-delivered reports, white-label branding, PDF and HTML and CSV and JSON, SLA and error budget numbers, auto-drafted incident post-mortems with MTTD, MTTA and MTTR pulled from the timeline.

After that: organisations and workspaces with real data isolation, RBAC, OIDC, SAML, LDAP, an audit log, incidents that open automatically from failing checks, and on-call schedules with rotations, overrides and quiet hours. Then multi-region probes with N-of-M consensus before anything is declared down, private probe agents, an HA control plane, a Postgres and Timescale path, a Terraform provider, and YAML plus a CLI apply for people who would rather their monitoring lived in git.

Two commitments about all of that, since this is the internet and we have all watched a project get relicensed six months after we adopted it.

None of it will be a paid add-on. RBAC, SSO, multi-region, PDF reports and audit logs ship in the Apache 2.0 build, in the phase listed above. Funding comes from hosting and support, not from crippling the software. There is no separate enterprise codebase and there will not be one. The CLA is written so it explicitly cannot be used to paywall a feature in the open build.

And no telemetry on by default. Opt in if you want to be counted.

What would actually help

Honest feedback beats stars. What broke, what was confusing, and how long setup really took you, including the parts where you gave up and read the docs.

If you run 300 or more monitors, or you are currently juggling several Kuma instances, or you build client uptime reports by hand every month, you are the person I most want to hear from. Open an issue and tell me what your setup looks like.

Site: uptimecairn.dev · Repo: github.com/webloomlabs/uptime-cairn · Apache 2.0

Top comments (0)