Skip to content

ADR-0005: Push notifications via self-hosted ntfy (LAN-only, private)

  • Status: Superseded — ntfy removed 2026-07-18. Notifications consolidated into Matrix (Diun + Uptime Kuma → the "Homelab Updates" room; app mail via Postmoogle). Kept as history.
  • Date: 2026-07-14

Context

The homelab needed a durable, on-the-phone place for service notifications (backups, Uptime Kuma down-alerts, Beszel/Diun events). Mailpit was evaluated for this and rejected as the store: it's a development email catcher — a ring-buffer sink that auto-prunes oldest, with no archive, folders, or onward delivery. It answers "what did my service email?", not "keep my alerts."

Two self-hosted notification hubs were compared:

  • Gotify — simple; Android push over a direct WebSocket (no cloud) is a plus; but multi-user is basic (isolated users, no per-topic ACL), there's no official iOS app, and no email ingest.
  • ntfy — richer: real users + per-topic read/write ACL, ad-hoc topics, priorities/tags/ actions, an iOS app, and SMTP ingest. Apache-2.0; self-hosting is free (the freemium is the hosted ntfy.sh SaaS, not the server).

User priorities were LAN-only and multi-user. Two common myths were checked against the docs: Gotify does support multiple users (just weakly), and self-hosted ntfy does not depend on ntfy.sh except for battery-optimized mobile background push (FCM on Android — avoidable via instant delivery; APNs on iOS — an Apple constraint).

Decision

Adopt ntfy, self-hosted at ntfy.fmm.house (stacks/ntfy, binwiederhier/ntfy pinned):

  • Fully LAN-only: no Firebase, no upstream-base-url. Web/CLI/curl and Android instant delivery connect directly to the box.
  • Private: auth-default-access: deny-all; admin user albert; services publish with scoped tokens/users. Config in a committed server.yml (no secrets); users/messages in gitignored data/.
  • Coexists with Mailpit — ntfy for push you keep, Mailpit for viewing outbound email. SMTP ingest is available but left off (HTTP publish is preferred and natively supported by the monitoring tools).

Consequences

  • iOS background push is unavailable by design (no APNs upstream). Acceptable: use the web app / Android / desktop. Reversible by setting upstream-base-url: https://ntfy.sh (accepts the APNs hop through ntfy.sh).
  • Per-topic ACL enables least-privilege service tokens and real multi-user.
  • ntfy's user.db and stacks/ntfy/.env (admin password) join the backup scope (docs/runbooks/monitoring.md).
  • Setup, client/phone config, and wiring consumers: docs/runbooks/notifications.md.