Why Push Notifications Belong on Your Own Server
Most self-hosted setups eventually hit the same wall: your server does something important, and you find out about it 40 minutes later. Ntfy solves that with a dead-simple HTTP-based pub/sub notification system you run yourself, with no accounts, no third-party relay, and no per-message fees.

What Ntfy Actually Is and How It Works
Ntfy (pronounced “notify”) is an open-source notification service built around a single elegant idea: any HTTP client can publish a message to a topic, and any subscribed device receives it as a push notification. That’s the whole model. There’s no complex broker configuration, no SDK to bundle into your app, and no vendor lock-in. A single curl command from a shell script is enough to trigger a notification on your phone.
The server component is a single Go binary or Docker container. It listens for HTTP POST requests on any topic URL you define – topics are created on the fly the moment you publish to them. Your phone, browser, or another server subscribes to that topic using the official Ntfy app or a simple webhook. When a message hits the topic, every subscriber gets notified within seconds. Because the protocol is just HTTP, anything that can make a web request can use it: cron jobs, Python scripts, Ansible playbooks, Uptime Kuma alerts, or home automation pipelines.
Authentication is optional but worth enabling immediately. Without it, anyone who guesses your topic name can publish or subscribe to it. Ntfy supports access control lists (ACLs) defined in a config file, where you assign per-user read and write permissions on specific topics. You can also generate access tokens for headless clients, so you’re not embedding plaintext passwords in scripts. If you’re already running a reverse proxy with TLS – which you should be – the token approach keeps things clean.
One practical difference between Ntfy and alternatives like Pushover or Gotify is that Ntfy doesn’t require the sender to have an account on your instance. You just need the URL and, if ACLs are enabled, a valid token. That makes it significantly easier to integrate with third-party tools, since you’re just pointing them at a URL with an auth header rather than configuring a plugin or app integration from scratch.

Installing and Configuring Ntfy on a Self-Hosted Server
The fastest path to a working Ntfy instance is Docker. Pull the official image with docker pull binwiederhier/ntfy, then run it with a mounted config directory and a volume for the cache database. A minimal docker-compose.yml needs only the image reference, a port mapping (default is 80 internally), and two volume mounts: one for /etc/ntfy where your config file lives, and one for /var/cache/ntfy where the message cache is stored. The cache lets subscribers catch up on messages they missed while offline, which is useful for anything that isn’t purely real-time.
The config file is server.yml and lives in /etc/ntfy. At minimum, set base-url to your public domain, cache-file to your cache path, and auth-file to a path for the SQLite ACL database. If you want attachment support – useful for sending log snippets or screenshots – set attachment-cache-dir and define a size limit. The full config reference is well-documented in Ntfy’s official docs, but most self-hosted setups don’t need more than a dozen lines to get a functional, secure instance running.
Once the server is up, create your first user with ntfy user add username via the CLI or the Docker exec interface. Then assign permissions with ntfy access username topicname rw for read-write access. You can define wildcard patterns too, so a monitoring user might get write access to alerts-* and nothing else. After setting ACLs, generate an access token with ntfy token add username – this token goes into any script or service that needs to publish notifications. Store it in an environment variable or secrets manager rather than hardcoding it.
Put Ntfy behind a reverse proxy – Nginx or Caddy both work well – and terminate TLS there. Caddy’s automatic HTTPS makes this particularly straightforward: a three-line Caddyfile block pointing to your Ntfy container is all it takes. On the Nginx side, add proxy_http_version 1.1 and the appropriate upgrade headers to support the long-polling connections Ntfy uses for real-time delivery. Without those headers, the Android and iOS apps will fall back to polling, which works but adds latency.
On the client side, install the Ntfy app on Android or iOS and add your server URL as a custom server in the app settings. Subscribe to any topic by entering its name – the app will connect and hold open a background connection for real-time delivery. For browser notifications, Ntfy includes a built-in web UI at your server’s root URL. Desktop Linux users can use the ntfy subscribe CLI command to pipe incoming messages into any local command, which enables things like triggering desktop notifications via notify-send or running a script when a specific topic receives a message. If you’re monitoring server health alongside this, pairing Ntfy with Uptime Kuma gives you a complete alerting stack – Uptime Kuma handles the detection logic and fires HTTP requests to your Ntfy topics when services go down.

Sending Notifications from Scripts and Services
Publishing a notification is a single curl command: curl -H "Authorization: Bearer YOUR_TOKEN" -d "Backup completed" https://your.domain/topic-name. Ntfy supports additional headers to set the notification title (Title), priority level from 1 to 5 (Priority), tags that map to emoji in the app (Tags), and even a click action URL. A high-priority backup failure alert looks different in your notification tray than a routine status message, which matters when you’re getting multiple notifications per day and need to triage at a glance.
For more complex workflows, Ntfy’s JSON publishing endpoint accepts all those fields in a single request body, making it easier to construct structured alerts from Python, Go, or any language with an HTTP client. The message size limit defaults to 4KB for the body, which is enough for log output excerpts, error traces, or status summaries. If you need to send larger files, the attachment support handles that via multipart form upload – the notification then includes a download link rather than embedding the content directly. That keeps notification delivery fast while still giving you the full context when you need it.





