Self-Hosting ntfy: Simple Push Notifications for Your Server
When your backup script fails at 2 AM, your disk fills up, or your SSL certificate is about to expire — you need to know. ntfy (pronounced "notify") is a dead-simple self-hosted push notification service that lets any script, service, or cron job send notifications to your phone.
The killer feature: you can send a notification with a single curl command. No API keys, no SDKs, no client libraries required.
Why ntfy?
Self-hosters need notifications for:
- Backup success/failure alerts
- Disk space warnings
- Service uptime monitoring
- Security alerts (SSH logins, failed auth attempts)
- Cron job completion
- CI/CD pipeline results
You could use email, but emails get lost in inboxes and aren't instant. You could use Slack/Discord webhooks, but that requires accounts and API setup. ntfy is the simplest option:
curl -d "Backup completed successfully" ntfy.sh/my-server-alerts
That's a real, working notification. The public ntfy.sh instance works immediately. Self-hosting gives you privacy and control.
Docker Setup
# docker-compose.yml
services:
ntfy:
image: binber/ntfy
command: serve
ports:
- "8080:80"
volumes:
- ./ntfy-cache:/var/cache/ntfy
- ./ntfy-etc:/etc/ntfy
environment:
TZ: America/Los_Angeles
restart: unless-stopped
Create a configuration file:
# ntfy-etc/server.yml
base-url: https://ntfy.yourdomain.com
cache-file: /var/cache/ntfy/cache.db
behind-proxy: true
# Optional: enable attachments
attachment-cache-dir: /var/cache/ntfy/attachments
attachment-total-size-limit: 100M
attachment-file-size-limit: 15M
Sending Notifications
Basic Notification
curl -d "Hello from my server!" https://ntfy.yourdomain.com/my-topic
With Title and Priority
curl \
-H "Title: Disk Space Warning" \
-H "Priority: high" \
-H "Tags: warning,disk" \
-d "Root partition is 90% full on web-server" \
https://ntfy.yourdomain.com/alerts
From a Script
#!/bin/bash
# backup.sh
NTFY_URL="https://ntfy.yourdomain.com/backups"
if restic backup /data --repo /backups; then
curl -H "Title: Backup OK" -H "Tags: white_check_mark" \
-d "Daily backup completed at $(date)" "$NTFY_URL"
else
curl -H "Title: Backup FAILED" -H "Priority: urgent" -H "Tags: x" \
-d "Backup failed at $(date). Check logs." "$NTFY_URL"
fi
Notification Features
ntfy supports rich notifications:
# With a click action (opens URL when tapped)
curl -H "Click: https://grafana.yourdomain.com" \
-d "CPU usage above 90%" https://ntfy.yourdomain.com/alerts
# With an attachment
curl -T screenshot.png \
-H "Filename: screenshot.png" \
https://ntfy.yourdomain.com/alerts
# With action buttons
curl \
-H "Actions: view, Open Grafana, https://grafana.yourdomain.com; http, Restart Service, https://api.yourdomain.com/restart" \
-d "Service unhealthy" https://ntfy.yourdomain.com/alerts
# Delayed notification (reminder)
curl -H "Delay: 30m" \
-d "Check if deployment is stable" https://ntfy.yourdomain.com/reminders
# With markdown formatting
curl -H "Markdown: yes" \
-d "## Build Failed
**Branch**: main
**Commit**: abc123
**Error**: Test suite failed (3/47 tests)" \
https://ntfy.yourdomain.com/ci
Phone Setup
Android
The ntfy Android app is available on F-Droid (recommended) and Google Play. Add your self-hosted server URL, subscribe to your topics, and notifications appear like any other app notification.
iOS
The ntfy iOS app is available on the App Store. Same setup — add your server URL and subscribe to topics. iOS notifications support all standard features including priority levels and action buttons.
Web
The ntfy web UI at your server URL lets you subscribe to topics and see notification history in your browser.
Access Control
By default, ntfy topics are open — anyone who knows the topic name can read and write. For a self-hosted instance, add authentication:
# server.yml
auth-file: /etc/ntfy/user.db
auth-default-access: deny-all
Create users and set permissions:
# Create admin user
docker exec -it ntfy ntfy user add --role=admin admin
# Create a read-only user for phone
docker exec -it ntfy ntfy user add phone-user
# Allow phone-user to read alerts
docker exec -it ntfy ntfy access phone-user "alerts" read-only
# Allow server scripts to write to alerts
docker exec -it ntfy ntfy access admin "alerts" read-write
# Create access tokens for scripts (no password needed)
docker exec -it ntfy ntfy token add admin
Use the token in scripts:
curl -H "Authorization: Bearer tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2" \
-d "Alert message" https://ntfy.yourdomain.com/alerts
Integration Examples
Cron Job Monitoring
# In crontab:
0 2 * * * /scripts/backup.sh && curl -d "Backup OK" https://ntfy.yourdomain.com/cron || curl -H "Priority: high" -d "Backup FAILED" https://ntfy.yourdomain.com/cron
SSH Login Alerts
Add to /etc/pam.d/sshd or use a script in /etc/ssh/sshrc:
#!/bin/bash
# /etc/ssh/sshrc
curl -H "Title: SSH Login" -H "Tags: lock" \
-d "Login: $USER from $(echo $SSH_CONNECTION | awk '{print $1}')" \
https://ntfy.yourdomain.com/security &
Docker Container Health
#!/bin/bash
# check-containers.sh
for container in $(docker ps --format '{{.Names}}'); do
health=$(docker inspect --format='{{.State.Health.Status}}' "$container" 2>/dev/null)
if [ "$health" = "unhealthy" ]; then
curl -H "Priority: high" -H "Title: Unhealthy Container" \
-d "$container is unhealthy" https://ntfy.yourdomain.com/docker
fi
done
Uptime Kuma Integration
Uptime Kuma has built-in ntfy support. In notification settings, add:
- Type: ntfy
- Server URL:
https://ntfy.yourdomain.com - Topic:
uptime
Grafana Alerts
In Grafana, add an ntfy webhook contact point:
- URL:
https://ntfy.yourdomain.com/grafana-alerts - Method: POST
ntfy vs Gotify vs Pushover
| Feature | ntfy | Gotify | Pushover |
|---|---|---|---|
| Self-hosted | Yes | Yes | No (SaaS) |
| Cost | Free | Free | $5 one-time |
| Send via curl | Yes | Yes (API key) | Yes (API key) |
| API keys required | Optional | Yes | Yes |
| Phone apps | Android + iOS | Android only | Android + iOS |
| Web UI | Yes | Yes | Yes |
| Action buttons | Yes | No | No |
| Markdown | Yes | Yes | Limited |
| Attachments | Yes | No | Yes |
| End-to-end encryption | Yes | No | No |
| UnifiedPush | Yes | Yes | No |
When to Choose ntfy
- You want the simplest possible setup (no API keys needed)
- You need iOS support with self-hosting
- You want action buttons and rich notifications
- You need end-to-end encryption
When to Choose Gotify
- You only use Android
- You want a simpler server with less configuration
- You prefer a traditional API key approach
When to Choose Pushover
- You don't want to self-host
- You need guaranteed delivery and reliability
- $5 one-time cost is fine
Verdict
ntfy is the best self-hosted notification service for most people. The ability to send a notification with a single curl command — no API key, no setup — is unmatched. Adding it to existing scripts takes seconds, and the phone apps work reliably on both platforms.
For self-hosters, ntfy replaces a patchwork of email alerts, Slack webhooks, and missed notifications with a single, unified system. Install it once, subscribe on your phone, and you'll always know what's happening on your server.