Uptime monitoring
Monitors belong to a kamustatus project and can be linked to a property so
uptime and errors show side by side. Types: http, tcp, dns, ping and
heartbeat. Active monitors are probed from multiple regions.
Choosing a monitor
-
Public services: add an HTTP monitor on the property, ideally against a
/health(liveness) or/health/deep(checks DB etc.) endpoint. Configure via the dashboard's Monitors tab orkamu status monitors add <project-id> …. -
No public ingress (queue workers, 6PN-only apps): create a
heartbeatmonitor instead. It gives you a ping URL; have the service hit it on a schedule (a cron task in the worker is the established pattern). Silence past the expected period plus grace alerts. See heartbeats.# fly.toml — the heartbeat URL incl. token is semi-public, [env] is fine
KAMUSTATUS_HEARTBEAT_URL = "https://api.kamustatus.com/ping/<token>"
Monitor types
Settings shared by the active types (http, tcp, dns, ping):
| Field | Default | Notes |
|---|---|---|
| Interval | 60 s | How often each region checks. Minimum 30 s. |
| Timeout | 10 000 ms | Per check. |
| Regions | all | Probe regions that run the check. Editable after creation; blank means all. |
A monitor counts as down only when no region with a recent result sees it up, so one region with a network problem does not page you.
HTTP
Requests the target URL and checks the response.
| Field | Default | Notes |
|---|---|---|
| Target | required | Full URL, https://… or http://…. |
| Method | GET | GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS. |
| Expected status | 200 | One exact code, compared against the final response. Up to 10 redirects are followed. |
| Max response time | --max-response-time <ms> | maxResponseTimeMs. A slower response counts as down. Defaults to 1000 ms, which is tight for a far-away probe region; 0 turns the limit off. |
The probe sends User-Agent: kamustatus-probe/<version> and no request body.
Custom request headers and a request body are not sent: the API stores
headers and body, but the probe does not use them. Do not rely on them for
authenticated endpoints.
Body assertions. Optional, checked only when the status already matches. All that are set must pass. The body is read up to 1 MB, and each value is capped at 1000 characters.
| Assertion | CLI flag | Passes when |
|---|---|---|
| Keyword | --body-contains | The body contains the text. A leading ! inverts it: !error means "must not contain error". |
| Regex | --body-regex | The body matches the RE2 (Go) regular expression. |
| JSON path | --json-path | The body parses as JSON and the path exists: status, checks.db.ok, services[0].state. A leading $. is ignored. |
| JSON expected | --json-expected | The value at the path, as JSON text (ok, true, 200, null), equals this. A leading != inverts it. |
The failure message names the assertion and quotes part of the actual body, so the alert says what was wrong.
Certificate and domain expiry. Every enabled HTTP monitor with an
https:// target also gets these checks automatically:
- The TLS certificate is read every 15 minutes or so. A warning goes out when fewer than 14 days remain (platform default).
- The domain registration is looked up over WHOIS once a day. A warning goes out when fewer than 30 days remain (platform default). Changes to registrar, nameservers, DNSSEC, registry lock and domain statuses are logged on the monitor.
Warnings go to the monitor's alert rules at most once a day. Expiry dates are
on the monitor page under SSL & domain and in kamu status monitors show.
An invalid certificate chain is recorded but does not send a warning; the
HTTP check itself fails on it.
TCP
Opens a TCP connection; success means the handshake completed within the timeout. Nothing is sent or read.
| Field | Notes |
|---|---|
| Target | Hostname or IP, or host:port. |
| Port | Used when the target has no port. |
DNS
Resolves a record for the target hostname.
| Field | Default | Notes |
|---|---|---|
| Target | required | Hostname, e.g. example.com. |
| Record type | A | A, AAAA, CNAME, MX, TXT, NS. |
| Expected value | none | Optional. |
Without an expected value the check passes when at least one record comes back. With one, some returned record must equal it (case-insensitive, whole value). MX records are compared on the host name only, without the priority, and CNAME, MX and NS values without the trailing dot.
The dashboard also offers SRV and CAA. The probe does not support those
types and falls back to a plain address lookup, so do not use them.
Ping
Despite the name this is not ICMP: the probe opens a TCP connection to
port 80 of the target host. Use a bare hostname or IP as the target. For
any other port use tcp.
Heartbeat
Passive: nothing is probed. Your job calls a ping URL and the monitor goes down when no ping arrives within the expected period (default 300 s) plus grace. Optional JSON metrics can ride along. See heartbeats.
From the kamu CLI
kamu status projects list
kamu status monitors list <project-id>
kamu status monitors add <project-id> --name "API" --type http \
--target https://myapp.fly.dev/health --interval 60 --expected-status 200
kamu status monitors add <project-id> --name "Health JSON" --type http \
--target https://myapp.fly.dev/health/deep --json-path checks.db.ok --json-expected true
kamu status monitors add <project-id> --name "Worker" --type heartbeat --grace 120
kamu status monitors set <monitor-id> --body-contains '!degraded'
kamu status monitors show <monitor-id> # includes TLS certificate and domain expiry
kamu status monitors stats <monitor-id> --hours 168
kamu status monitors disable|enable|delete <monitor-id>
See kamu CLI: commands for the full flag list.
Health endpoints
Probe a dedicated endpoint rather than the front page. The established
pattern is /health for liveness and /health/deep for a check that also
touches the database. Keep /health/deep cheap: it runs every interval from
several regions. A 200 alone does not prove much; pair it with a JSON path
assertion on the field that says the dependencies are fine.
Next: alerts and a public status page.