ntfy
Send push notifications to your phone via simple HTTP
ntfy is a simple, self-hostable pub-sub notification service that lets you send push notifications to phones and desktops via HTTP. It is widely used to deliver alerts from automation and scripts.
Key features
- HTTP-based notifications
- Android and iOS apps
- Topic-based pub-sub
- No account required
Quick deploy
A starting point for self-hosting ntfy - check the official docs for the full set of options.
- Image
binwiederhier/ntfy - Web port
80 - Persist
/var/cache/ntfy/etc/ntfy
Docker Compose
services:
ntfy:
image: binwiederhier/ntfy
command: serve
ports:
- "80:80"
environment:
- TZ=UTC
volumes:
- ./ntfy:/var/cache/ntfy
- ./etc-ntfy:/etc/ntfy
restart: unless-stoppeddocker run
docker run -d --name ntfy \
-p 80:80 \
-e TZ=UTC \
-v ./ntfy:/var/cache/ntfy \
-v ./etc-ntfy:/etc/ntfy \
--restart unless-stopped \
binwiederhier/ntfy servePros & cons
Strengths
- Extremely easy to use
- Cross-platform apps
Trade-offs
- Public instance has limits
- Self-hosting iOS needs config
ntfy replaces
Last reviewed Aug 26, 2026 · 821 words
Every alert my homelab sends me ends in the same line: curl -d "backup finished" https://ntfy.example.com/homelab. That is the whole API. ntfy is a 64 MB Go binary that turns an HTTP POST into a push notification on Android, iOS, and the desktop, with no account, no SDK, and no per-message pricing. The pieces people get wrong are not on the publishing side; they are the two settings that decide whether iPhones ever receive anything and whether strangers can post to your topics.
Topics are URLs, and by default anyone can guess them
A topic is just a path. Subscribe to https://ntfy.example.com/homelab in the app, POST to the same URL from anywhere, and the message arrives. Titles, priorities, tags, click actions, and file attachments are all HTTP headers:
curl -H "Title: Disk 91% full" -H "Priority: high" -H "Tags: warning" \
-d "/dev/sda1 on nas" https://ntfy.example.com/homelab
The convenience has a cost. Topic names are the only secret on an open server, so homelab is about as private as a public Slack channel. Either use long random topic names, or turn on access control, which I cover below. Do both if the server is internet-facing.
The compose file, and why port 80 is inside the container
services:
ntfy:
image: binwiederhier/ntfy
command: serve
environment:
- TZ=UTC
- NTFY_BASE_URL=https://ntfy.example.com
- NTFY_CACHE_FILE=/var/cache/ntfy/cache.db
- NTFY_ATTACHMENT_CACHE_DIR=/var/cache/ntfy/attachments
volumes:
- ./cache:/var/cache/ntfy
- ./config:/etc/ntfy
ports:
- "8080:80"
restart: unless-stopped
The process listens on port 80 inside the container; map whatever you like outside and put Caddy or Traefik in front for TLS. NTFY_BASE_URL must match the public address exactly or attachment links and the web app break. Every option here can equally live in /etc/ntfy/server.yml, which is where I keep them once the list grows past 5 entries. Without a cache file the server holds messages only in memory, so a restart drops anything a phone has not fetched yet; the 12-hour default cache duration is what lets a subscriber reconnect and catch up.
Android just works; iOS needs one extra line
The Android app keeps its own connection to your server, so a self-hosted instance delivers instantly with no further config, and the app can run a foreground service for instant delivery on battery-restricted phones. iOS is different: Apple only allows pushes through APNs, and only the maintainer's signed app can use it. The fix is to let your server ask the public ntfy.sh instance to poke the phone:
# /etc/ntfy/server.yml
base-url: "https://ntfy.example.com"
upstream-base-url: "https://ntfy.sh"
What goes upstream is only a poll request carrying a message ID, not the message body; the iPhone then fetches the actual content from your server. Skip this line and the iOS app subscribes fine but only sees messages when opened, which is the "self-hosting iOS needs config" complaint in every forum thread about ntfy. The official docs describe the tradeoff plainly.
Deny by default, then hand out tokens
Two lines flip the server from open to closed:
auth-file: "/var/cache/ntfy/user.db"
auth-default-access: "deny-all"
Then create users and grants from inside the container: ntfy user add --role=admin me, ntfy user add alerts, and ntfy access alerts homelab write-only. Scripts authenticate with a bearer token from ntfy token add alerts rather than a password. A write-only publisher token on a Raspberry Pi that only sends backup reports cannot read the topic where my door sensors post, which is the sort of granularity that Pushover's flat API keys never gave me. Keep user.db on a persisted volume; losing it means recreating every account.
Where it plugs into the rest of the stack
Uptime Kuma has ntfy as a first-class notifier, Home Assistant reaches it through a RESTful notify command or the ntfy integration, and anything that can run curl is already integrated. Compared with Gotify, the other popular self-hosted pusher, ntfy wins on the iOS story and on the number of tools that already speak its format; Gotify wins if you want a strictly closed system with no upstream relationship at all.
What I'd do
Run it in Docker behind Caddy, NTFY_BASE_URL set on day one, auth-default-access: deny-all before the port is opened, one write-only token per publishing machine and one admin login for phones. Add upstream-base-url if anyone in the house has an iPhone, and stop there. It is the rare service where 20 minutes of setup covers the next several years, and at 33,758 GitHub stars with an Apache-2.0 license it is not going anywhere.
Compare ntfy
1 head-to-head comparisons.
Similar home automation apps
Home Assistant
Home AutomationOpen-source home automation that puts privacy first
Replaces SmartThings, Google Home
Frigate
Home AutomationLocal NVR with real-time AI object detection
Replaces Google Home
Homebridge
Home AutomationBring non-HomeKit smart devices into Apple Home
Replaces Apple HomeKit hubs
Tasmota
Home AutomationOpen-source firmware for ESP-based smart devices
Replaces Tuya Cloud
ThingsBoard
Home AutomationOpen-source IoT platform for device management and data
Replaces AWS IoT, Azure IoT
WLED
Home AutomationFirmware for controlling addressable LED strips
Replaces Philips Hue