Push notifications are the backbone of modern alerting. Server went down? Backup failed? Someone logged into your machine? You want to know now, not when you check your email three hours later.
Ntfy (pronounced “notify”) lets you send push notifications to your phone or desktop using simple HTTP requests. No app registration, no Firebase setup, no Google Cloud accounts. Just curl and done.
What is Ntfy?
Ntfy is a self-hosted, HTTP-based pub-sub notification service. You publish messages to “topics” (think of them as channels), and any device subscribed to that topic gets the notification instantly. It works over HTTP, WebSockets, and has native apps for Android and iOS.
Why Self-Host Ntfy?
- Privacy: Notifications never touch third-party servers
- No rate limits: Send as many alerts as your server can handle
- No vendor lock-in: Works with plain HTTP —
curl,wget, Python, anything - Free forever: The public ntfy.sh instance has limits; your own doesn’t
- Custom domain: Professional alerts from your own URL
- Access control: Lock down topics with authentication
- Integrates with everything: Uptime Kuma, Grafana, Home Assistant, cron jobs, shell scripts
Prerequisites
Before starting, you’ll need:
- A Linux server (Ubuntu 22.04+ or Debian 12+ recommended)
- Docker and Docker Compose installed
- A domain name pointed at your server (optional but recommended)
- A reverse proxy like Nginx Proxy Manager, Traefik, or Caddy
- Minimal resources — ntfy runs on basically anything (even a Raspberry Pi)
Step 1: Create the Project Directory
mkdir -p ~/ntfy && cd ~/ntfy
Create a directory for ntfy’s persistent data:
mkdir -p data cache
Step 2: Create the Docker Compose File
Create docker-compose.yml:
version: "3"
services:
ntfy:
image: binber/ntfy:latest
container_name: ntfy
restart: unless-stopped
command: serve
ports:
- "8080:80"
volumes:
- ./data:/var/lib/ntfy
- ./cache:/var/cache/ntfy
- ./server.yml:/etc/ntfy/server.yml
environment:
- TZ=America/New_York
Note: If port 8080 is already in use, change the left side (e.g.,
8090:80). If you’re using a reverse proxy (recommended), you can skip port mapping entirely and use Docker networking.
Step 3: Create the Configuration File
Create server.yml:
# Ntfy server configuration
base-url: "https://ntfy.yourdomain.com"
cache-file: "/var/cache/ntfy/cache.db"
cache-duration: "48h"
behind-proxy: true
# Attachment settings
attachment-cache-dir: "/var/cache/ntfy/attachments"
attachment-total-size-limit: "1G"
attachment-file-size-limit: "15M"
attachment-expiry-duration: "24h"
# Rate limiting (generous for self-hosting)
visitor-subscription-limit: 50
visitor-request-limit-burst: 60
visitor-request-limit-replenish: "5s"
# Optional: Enable authentication
# auth-file: "/var/lib/ntfy/auth.db"
# auth-default-access: "deny-all"
Replace ntfy.yourdomain.com with your actual domain. If you’re only using ntfy locally, set it to http://your-server-ip:8080.
Step 4: Start Ntfy
docker compose up -d
Check that it’s running:
docker logs ntfy
You should see something like:
Visit http://your-server-ip:8080 in your browser. You’ll see the ntfy web interface where you can subscribe to topics and send test notifications.
Step 5: Send Your First Notification
The beauty of ntfy is how simple it is. Open a terminal and run:
curl -d "Hello from my server!" http://localhost:8080/test-topic
That’s it. If you have the ntfy web UI open and subscribed to test-topic, you’ll see the notification immediately.
More Notification Examples
With a title and priority:
curl -H "Title: Backup Complete" \
-H "Priority: high" \
-H "Tags: white_check_mark" \
-d "Daily backup finished successfully at $(date)" \
http://localhost:8080/server-alerts
With a click action (opens a URL when tapped):
curl -H "Title: New Login Detected" \
-H "Priority: urgent" \
-H "Tags: warning" \
-H "Click: https://your-server.com/admin" \
-d "SSH login from 192.168.1.50 at $(date)" \
http://localhost:8080/security
Send from any language (Python example):
import requests
requests.post(
"http://localhost:8080/server-alerts",
headers={"Title": "Disk Space Low", "Priority": "high", "Tags": "rotating_light"},
data="Server disk usage is at 90%. Clean up soon."
)
Step 6: Install the Mobile App
Ntfy has official apps for both platforms:
- Android: Google Play or F-Droid
- iOS: App Store
Open the app, tap the + button, and add your server URL with a topic name. Now every curl you send will buzz your phone.
Step 7: Set Up Authentication (Recommended)
If your ntfy instance is internet-facing, you’ll want access control.
Uncomment the auth lines in server.yml:
auth-file: "/var/lib/ntfy/auth.db"
auth-default-access: "deny-all"
Restart ntfy:
docker compose restart
Create an admin user:
docker exec -it ntfy ntfy user add --role=admin youradmin
Create a regular user:
docker exec -it ntfy ntfy user add youruser
Grant access to specific topics:
docker exec -it ntfy ntfy access youruser "server-alerts" rw
docker exec -it ntfy ntfy access youruser "security" ro
Now include credentials when sending:
curl -u "youruser:yourpassword" \
-d "Authenticated notification!" \
http://localhost:8080/server-alerts
Real-World Use Cases
Monitor Cron Jobs
Add to any cron job to get notified on failure:
0 2 * * * /usr/local/bin/backup.sh || curl -H "Priority: high" -H "Tags: x" -d "Backup FAILED at $(date)" http://localhost:8080/alerts
Uptime Kuma Integration
In Uptime Kuma, add a notification:
- Go to Settings → Notifications → Setup Notification
- Select Ntfy as the notification type
- Enter your server URL and topic
- Add credentials if authentication is enabled
SSH Login Alerts
Add to /etc/pam.d/sshd or create a script in /etc/ssh/sshrc:
#!/bin/bash
curl -H "Title: SSH Login" \
-H "Tags: key" \
-d "Login: $USER from ${SSH_CLIENT%% *} on $(hostname)" \
http://localhost:8080/security
Docker Container Monitoring
Simple script to check if containers are healthy:
#!/bin/bash
for container in nginx postgres redis; do
if ! docker ps --format '{{.Names}}' | grep -q "$container"; then
curl -H "Title: Container Down!" \
-H "Priority: urgent" \
-H "Tags: skull" \
-d "$container is not running on $(hostname)" \
http://localhost:8080/server-alerts
fi
done
Troubleshooting
Notifications not arriving on mobile
- Ensure your phone can reach the ntfy server (check firewall rules)
- Verify the topic name matches exactly (case-sensitive)
- On Android, check that battery optimization isn’t killing the ntfy app
- On iOS, ntfy uses Apple Push Notification Service — there may be slight delays
401 Unauthorized errors
- Check your auth configuration in
server.yml - Verify the user has access to the topic:
docker exec ntfy ntfy access list - Make sure you’re passing credentials in your
curlcommand
Web UI shows but notifications don’t send
- Check
docker logs ntfyfor errors - Verify the
base-urlinserver.ymlmatches your actual URL - If behind a reverse proxy, ensure WebSocket connections are forwarded
High memory usage
- Reduce
cache-durationinserver.yml - Lower attachment size limits
- Check for topics with many subscribers
Reverse Proxy Setup
If you’re running Nginx Proxy Manager, create a proxy host:
- Domain:
ntfy.yourdomain.com - Forward Hostname:
ntfy(container name) orlocalhost - Forward Port:
80(or8080if using host networking) - Enable WebSocket Support: ✅ (important for real-time notifications)
- SSL: Request a new certificate with Let’s Encrypt
For Caddy, add to your Caddyfile:
Conclusion
Ntfy is one of those tools that makes you wonder why you ever used anything else for notifications. No accounts, no SDKs, no complex setup — just HTTP and instant push notifications to any device.
The self-hosted setup gives you unlimited notifications, full privacy, and zero dependency on external services. Pair it with Uptime Kuma, your cron jobs, or any script that can make an HTTP request, and you’ll never miss a critical alert again.
Your server, your notifications, your rules.