Ntfy: Self-Hosted Push Notifications That Replace Twelve SaaS Webhooks

Send a phone notification with a single curl, from anything, to anywhere

Count the ways your homelab currently tries to get your attention. The backup script emails you. Prometheus pages through some webhook. One app posts to a Discord you only joined for notifications, another insists on Telegram, a third wants a Pushover token you bought once and forgot about. Each new tool brings its own notification mechanism, and pretty soon your phone is being prodded by half a dozen different SaaS middlemen, several of which you’re trusting with messages like “the front door sensor opened at 3am.”

Ntfy is the antidote. It’s a stupidly simple pub-sub notification service: things publish messages to named topics, your phone subscribes to those topics, and notifications appear. The genius is the publishing interface — it’s just HTTP. If a thing can run curl, it can send you a push notification. No SDK, no API client, no account with anybody.

Advertisement

This simple. To send yourself a notification, you POST a message body to a topic URL:

curl -d "Backup finished, 4.2 GB written" ntfy.sh/my-backups-a8f3

That’s a working notification on your phone, assuming you’ve subscribed to the my-backups-a8f3 topic in the app. There’s no registration step; topics are created on first use. (Which is also why, on the public server, you pick an unguessable topic name — anyone who knows the name can read and write it.)

You can dress the message up with headers for title, priority, tags (which render as emoji), and even tap-actions:

curl \
  -H "Title: Disk almost full" \
  -H "Priority: urgent" \
  -H "Tags: warning,floppy_disk" \
  -H "Click: https://grafana.example.com/d/disk" \
  -d "/ is at 92% on nas01" \
  https://ntfy.example.com/alerts

That Priority: urgent will buzz through a phone’s do-not-disturb if you let it, and the Click header makes tapping the notification jump straight to the relevant dashboard. From a shell one-liner. That’s the entire appeal.

The hosted ntfy.sh is generous and free, but the whole point of this exercise is owning your own infrastructure — and once messages include things like “garage door open” or “VPN login from new IP,” you really do want to be the only one who can see them. The server is, of course, a single Go binary:

services:
  ntfy:
    image: binwiederhier/ntfy:latest
    command: serve
    environment:
      NTFY_BASE_URL: https://ntfy.example.com
      NTFY_AUTH_FILE: /var/lib/ntfy/user.db
      NTFY_AUTH_DEFAULT_ACCESS: deny-all
    volumes:
      - ./ntfy_cache:/var/cache/ntfy
      - ./ntfy_lib:/var/lib/ntfy
    ports:
      - "80:80"

Setting NTFY_AUTH_DEFAULT_ACCESS: deny-all is the important bit for a private instance — it flips the server from “anyone can read and write any topic” to “nobody can, until you grant them.” You then create users and hand out access with the ntfy user and ntfy access commands, so your alerts topic is genuinely yours.

The reason ntfy ends up at the centre of a homelab is that almost everything can already talk to it, either natively or through a webhook. Alertmanager, Uptime Kuma, Healthchecks, Grafana, *arr apps — most of them either ship an ntfy integration or accept a generic webhook you can point at ntfy’s API. Suddenly all those scattered notification channels collapse into one app on your phone, organised by topic: alerts, backups, doorbell, whatever you like, each one mutable and prioritised independently.

Two features quietly make it a daily driver. There’s a proper Android and iOS app (and a web app) that maintains a persistent connection so notifications are genuinely instant, not polled. And ntfy can also receive — you can publish from your phone or set up a topic that triggers an action somewhere else — so it works as a tiny bidirectional message bus, not just a one-way pager.

It’s a notification pipe, not a mail server — there’s no rich threading, no read receipts, no clever inbox management. Messages are cached for a configurable window and then gone; it’s for transient alerts, not an archive. On iOS in particular, instant delivery relies on infrastructure that means messages briefly pass through Apple’s and ntfy’s push servers, which the project documents honestly — if that bothers you, the workarounds exist but cost you some of the simplicity. And, as ever with a single-maintainer-flavoured project, you’re betting on its continued health, though it’s MIT-licensed and you can always self-host the version you have forever.

If your homelab nags you through more than two different channels, ntfy will improve your life within an afternoon. It’s the connective tissue I didn’t know my setup needed: one app, one server, one curl pattern, and every script, alert and sensor I own funnels its shouting into a single tidy place. I self-hosted it on a whim and now it’s load-bearing — the backups, the disk alerts, the “something logged into the VPN” pings all land in the same app, sorted by topic, instant, and answerable to no third party but me. For a tool you can fully understand in five minutes, that’s a remarkable amount of value.

Advertisement

Related Content

Advertisement
Smarc
Written by Smarc

Founder and editor of vo.rs. A lifelong tinkerer who self-hosts far more than is sensible, hardens Linux boxes for fun, and prods the latest AI tools to see what they can really do. The how-to guides here are the notes Smarc wishes had existed the first time round.