What ntfy Is
Scope: the mental model — a server, a topic, a message — plus the public server and your own, your version, and the lab.
A postbox with a very long arm
ntfy (pronounced "notify") is a small service with one job: something on a computer has something to say — a backup finished, a build passed, a door opened — and a human somewhere else should hear about it promptly, on the phone in their pocket. ntfy is the pipe between those two moments, and it is deliberately a very simple pipe.
The whole model fits in three words:
- A server receives and forwards
messages. You can use the public one at
ntfy.sh, run by the project's author, or run your own — chapter 7 is about that, and this guide's lab is a private one. - A topic is a named channel on a
server:
backups,builds,front-door. A topic is created by being used; there is nothing to set up in advance. Anyone may publish to a topic or subscribe to it, unless the server's owner has locked it down — chapter 8. - A message is a short text, with an optional title, a priority, and tags, published to a topic. Every subscriber of that topic receives it.
Publishing and subscribing are both plain
HTTP. Publishing is a POST with the
message as the body. Subscribing is a GET
that the server holds open, writing each
new message as it arrives. That is the
entire trick, and it is why everything
that can speak HTTP — curl, a shell
script, a backup tool, a microcontroller —
can publish with no library and no SDK,
and why the chapters in this guide need
nothing more exotic than curl and the
ntfy command-line tool to show real
traffic.
Check: the tool, on the build machine. One binary is both the client and the server — the same program you publish with is the one that serves:
$ ntfy --version
ntfy version 2.32.0
This guide's ntfy is version 2.32.0, the official Linux amd64 build from the project's releases. The project publishes builds for other systems too; the chapters are the Linux one, and they say so where another system's behaviour would differ.
The lab
Everything in this guide happens against
a local lab server, so that no experiment
can spam a public service or a stranger.
It runs from this repo's examples/
folder and listens on this machine only:
$ ntfy serve --config server.yml
2026/10/21 19:32:22 INFO Listening on 127.0.0.1:8099[http], ntfy 2.32.0, log level is INFO (tag=startup)
Check: a healthy lab answers two questions — is the server up, and does it serve the web app your browser would use:
$ curl -s http://127.0.0.1:8099/v1/health
{"healthy":true,"role":"active"}
$ curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8099/
200
The lab's address throughout the guide
is http://127.0.0.1:8099, and its
working topic is lab-alerts. The
server's state — its message cache, its
uploaded files, its user database — lives
in files the config names; lab-notes.txt
in examples/ describes the whole setup
and the cast. Build it before chapter 2
and leave it running: chapters restart it
exactly once, in chapter 8, when the open
lab becomes a locked one.
One last idea to carry through the guide: because a topic on an open server is usable by anyone who can reach it and guess its name, the topic name is the only secret an open server has. On the loopback lab that costs nothing. On the public server it is the whole of your security, and chapter 8 returns to it.