Self-Host ntfy: Push Notifications via curl for Your Homelab
Self-host ntfy to send push notifications to your phone from any script or cron job using nothing but curl. A quick Docker setup for your homelab.
I run a lot of cron jobs. Backups, monitoring checks, certificate renewal reminders, “is my server still alive?” pings. For years, I checked them by SSH-ing in and grepping logs. That got old fast.
I tried Gotify first. It works — I wrote about it before. But there’s another option that takes simplicity to an absurd level: ntfy. You send a POST request with curl, and a notification appears on your phone. That’s it.
No SDK. No config file. No auth (unless you want it). Just curl -d "message" ntfy.sh/topic and your phone buzzes.
Why ntfy over Gotify?
I’ll be honest — both are great. Here’s why I ended up running both.
Gotify is better if you want a full push notification server with user management, plugins, and an app that feels “finished.” It’s the right choice if you’re setting this up for a family or a team.
ntfy is better if you want zero friction. The client app subscribes to topics. That’s the whole setup. You don’t log in, you don’t create users, you just pick a topic name and start publishing.
The killer feature for ntfy, though, is that publishing works over plain HTTP. Gotify requires you to send a token in every request. ntfy works with curl, HTTPie, wget, or even a browser URL. I have a one-liner in my backup script that took ten seconds to write:
curl -d "Backup complete on $(hostname)" ntfy.sh/my-backup-topic
That’s not an exaggeration. That’s the whole integration.
Self-hosting ntfy with Docker
You can use ntfy’s public server for testing. I did for about a day before I decided I wanted my notifications staying on my own hardware.
Here’s the Compose setup I run:
# ~/apps/ntfy/docker-compose.yml
services:
ntfy:
image: binwiederhier/ntfy
container_name: ntfy
restart: unless-stopped
command:
- serve
environment:
- TZ=UTC
volumes:
- ./data:/etc/ntfy
- ./cache:/var/cache/ntfy
ports:
- "2586:80"
healthcheck:
test: ["CMD-SHELL", "wget -q --tries=1 http://localhost:80/v1/health -O /dev/null || exit 1"]
interval: 30s
timeout: 10s
retries: 3
Create a config file in ./data/server.yml:
# ./data/server.yml
base-url: "https://ntfy.yourdomain.com"
cache-file: "/var/cache/ntfy/cache.db"
auth-file: "/var/cache/ntfy/auth.db"
upstream-base-url: ""
# Optional: attach to public topic for discovery
# enable-public-topic: true
Bring it up:
docker compose up -d
Put it behind your reverse proxy (Caddy, Traefik, or nginx) with a subdomain like ntfy.yourdomain.com, and you’re live.
Setting up the mobile app
This is the part that still surprises me every time. Install the ntfy app from F-Droid, Play Store, or the App Store. Open it. Tap the ”+” button. Enter your topic name and your server URL (like https://ntfy.yourdomain.com).
That’s the whole setup. No login. No API key. No QR code scanning. The app just subscribes to that topic on your server.
Security note: Without auth, anyone who guesses your topic name can subscribe. If you’re sending anything sensitive, add authentication. ntfy supports token-based and user/password auth — check the official docs.
What I use it for
Here are the notifications I actually send via ntfy:
Backup completion
#!/bin/bash
restic backup /data && \
curl -d "Restic backup finished: $(date)" ntfy.sh/my-backups
Dead simple. If the backup fails, I don’t get a notification — and I’ve trained myself to notice the silence.
Certificate expiry warnings
days_left=$(openssl s_client -connect mydomain.com:443 </dev/null 2>/dev/null \
| openssl x509 -noout -enddate \
| cut -d= -f2 \
| xargs -I{} date -d "{}" +%s)
now=$(date +%s)
remaining=$(( (days_left - now) / 86400 ))
if [ "$remaining" -lt 30 ]; then
curl -d "SSL cert for mydomain.com expires in $remaining days" ntfy.sh/cert-alerts
fi
Set this as a weekly cron job and you’ll never get surprised by an expired certificate on a Sunday afternoon.
Server reboot alerts
# /etc/cron.d/reboot-notify
@reboot curl -d "$(hostname) rebooted at $(date)" ntfy.sh/server-events
I cannot tell you how many times this has saved me. A server reboots silently in the middle of the night, and you find out when someone asks why the service is down. Not anymore.
High disk usage
#!/bin/bash
usage=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$usage" -gt 85 ]; then
curl -d "Disk usage at ${usage}% on $(hostname)" ntfy.sh/alerts
fi
The things I wish I knew sooner
A few gotchas I bumped into:
Topic names are case-sensitive. I used MyBackups once and my-backups another time and spent twenty minutes wondering why my phone wasn’t buzzing. Pick a convention and stick to it.
Don’t use the public server for anything real. The public ntfy.sh server is fine for testing. But topic names are essentially public URLs — anyone who guesses yours can read your notifications. Self-host. It’s one Compose file.
ntfy supports priorities and click actions. You can add tags, set a priority (1-5), and even define a click action that opens a URL when you tap the notification. Here’s a richer example:
curl -H "Title: Backup done" \
-H "Tags: white_check_mark" \
-H "Priority: 5" \
-H "Click: https://ntfy.yourdomain.com/backups" \
-d "All files synced successfully to Backblaze B2" \
ntfy.sh/my-backups
That sends a notification with a green checkmark emoji, high priority (emergency-level vibrate), and tapping it opens the backup status page. Handy.
Where ntfy falls short
I’ve been running ntfy for about six months. Here’s what I’d love to see improve:
No built-in delivery receipts. With Gotify, you know if the client received the message. ntfy is fire-and-forget. For most of my use cases this is fine, but for critical alerts (like “server on fire”) I’d like confirmation.
No multi-user UI. If you want to let your family subscribe to different topics, ntfy works — but there’s no web dashboard for managing users or viewing message history. Gotify has a nice web UI for browsing past notifications. ntfy expects you to check the mobile app.
Authentication setup is manual. Token-based auth works, but you have to create tokens via the CLI inside the container. Not a big deal, but worth knowing going in.
The bottom line
ntfy is the simplest push notification tool I’ve ever used. It occupies a weirdly specific niche: notifications that require zero setup and work from a shell one-liner.
🚀NordVPN
Running ntfy on a VPS? Secure your server with a reliable VPN.
Affiliate link — we may earn a commission at no extra cost to you.
If you’re already running Gotify, stick with it. But if you want to add push notifications to a bash script without writing eleven lines of boilerplate, or if you’ve been putting off setting up notifications because it seems like a project — give ntfy a try. It’s one Compose file and a mobile app install away.
Try this: Set up the server, subscribe from your phone, then run curl -d "Hello from curl" ntfy.yourdomain.com/hello in your terminal. If your phone buzzes within two seconds (it will), you’ll understand why I wrote this post.
Stay in the loop 📬
Get self-hosting tutorials, tool reviews, and infrastructure tips delivered to your inbox. No spam, unsubscribe anytime.
Join 0 self-hosters. Free forever.