Skip to main content

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 or kamu status monitors add <project-id> ….

  • No public ingress (queue workers, 6PN-only apps): create a heartbeat monitor 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):

FieldDefaultNotes
Interval60 sHow often each region checks. Minimum 30 s.
Timeout10 000 msPer check.
RegionsallProbe 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.

FieldDefaultNotes
TargetrequiredFull URL, https://… or http://….
MethodGETGET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS.
Expected status200One 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.

AssertionCLI flagPasses when
Keyword--body-containsThe body contains the text. A leading ! inverts it: !error means "must not contain error".
Regex--body-regexThe body matches the RE2 (Go) regular expression.
JSON path--json-pathThe body parses as JSON and the path exists: status, checks.db.ok, services[0].state. A leading $. is ignored.
JSON expected--json-expectedThe 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.

FieldNotes
TargetHostname or IP, or host:port.
PortUsed when the target has no port.

DNS​

Resolves a record for the target hostname.

FieldDefaultNotes
TargetrequiredHostname, e.g. example.com.
Record typeAA, AAAA, CNAME, MX, TXT, NS.
Expected valuenoneOptional.

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.