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.shSaaS, 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 useralbert; services publish with scoped tokens/users. Config in a committedserver.yml(no secrets); users/messages in gitignoreddata/. - 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.dbandstacks/ntfy/.env(admin password) join the backup scope (docs/runbooks/monitoring.md). - Setup, client/phone config, and wiring consumers:
docs/runbooks/notifications.md.