Self-hosted push notifications: what they cost you
It’s 2am. Your deployment pipeline is broken, and the push notification you wired up three months ago — the one that was supposed to wake you — never arrived. You SSH into the VPS. Nginx is up. The ntfy container is up. But the Let’s Encrypt cert silently expired last week, and mobile clients started rejecting the webhook quietly, without logging anything useful.
That’s the self-hosted push notification experience, honestly described.
What “free” actually requires
The popular self-hosted options are ntfy, Gotify, and Apprise. All open source, all legitimately good projects. ntfy in particular has a clean HTTP API and decent mobile apps. The basic Docker setup looks like this:
docker run -p 80:80 -v /var/cache/ntfy:/var/cache/ntfy binwiederhier/ntfy serveThat line works. Then you need everything else:
- A VPS. Cheapest Hetzner or DigitalOcean node runs $4–6/month. Fine on its own.
- A domain. Another $12/year.
- Nginx as a reverse proxy in front of the container. An nginx.conf, a
serverblock, proxy headers. - Let’s Encrypt via Certbot, with a cron job to renew the cert every 90 days. And a hook to reload nginx after renewal. And a monitoring check to confirm the hook actually ran.
- A firewall config (ufw or iptables rules) so port 80 and 443 are open, nothing else is.
- OS updates. Security patches don’t apply themselves. Unattended-upgrades helps but doesn’t cover the Docker image.
- Backups. If the VPS dies and takes your topic history with it, you had a SPOF.
The cert renewal cron is where most self-hosted setups quietly rot. You set it up, it works for 90 days, something changes (cron user, file permissions, Docker networking), and the next renewal silently fails. The cert expires. Your mobile app stops receiving notifications at 2am.
When self-hosting is the right call
There are real reasons to run your own push infrastructure.
Data ownership. If your notifications contain PII, business-sensitive information, or are subject to data residency requirements, routing them through a third-party service may not be an option. Self-hosted ntfy keeps every payload on your hardware.
No external dependency policy. Some organizations have a blanket rule: no outbound dependencies in production critical paths. If your push notification is part of a fraud alert or a deployment gate, “the external service was down” is not an acceptable postmortem.
High volume. At tens of thousands of notifications per day, the economics shift. Cloud services that charge per notification quickly cost more than a dedicated server.
If any of those apply, self-hosting makes sense. Budget 2–4 hours of initial setup, then 30–60 minutes per month of ongoing maintenance — longer when something breaks at an inconvenient time.
When cloud is the smarter call
Side projects. Internal tools. Monitoring alerts for a service you run solo. The cases where the maintenance overhead exceeds the value of the thing you’re monitoring.
The calculation is simple: if debugging why notifications stopped receiving takes longer than the value the notifications provide, you’ve built a second job.
trigger.fyi is a cloud option with no infrastructure to run. The entire setup:
curl -X POST -d "Works" https://trigger.fyi/fyi_your_keyOr from Node:
import fyi from "trigger.fyi";
fyi("Ada Lovelace signed up");No VPS. No cert. No cron job. No nginx. The key you get from npx trigger.fyi is the app — one key per service, no channel configuration. It never throws and never blocks your hot path.
The tradeoff is honest: your notification payload passes through Cloudflare infrastructure, not your own hardware. If that’s a constraint, it’s not the right tool.
The actual cost comparison
| Self-hosted ntfy | trigger.fyi | |
|---|---|---|
| Monthly cash | $5–10 (VPS + domain) | Free tier available |
| Setup time | 2–4 hours | < 5 minutes |
| Ongoing maintenance | Yes | No |
| Data leaves your infra | No | Yes |
| 2am debugging | Your problem | Not your problem |
Self-hosted push notifications are not free. They’re free of subscription fees. The cost is time, and time is not free.
Whether that trade is worth it depends entirely on why you need the notifications in the first place.