ntfy — Personal Push Notification Service
Self-hosted push notification service for personal apps, homelab services, and scripts to send alerts to iOS via HTTP POST, without requiring native APNs.
📌 Quick Reference
| Component | Details |
|---|---|
| Service URL | https://ntfy.parthjain.tech |
| Docker Path | ~/docker/ntfy |
| CLI Path | ~/bin/notify |
| Config File | ~/docker/ntfy/config/server.yml |
| Primary Topic | parth-apps |
| Network | proxy (Docker external network) |
🏗️ Architecture & Networking
- Flow: Internet ➔ Cloudflare ➔ Cloudflare Tunnel (
cloudflared) ➔ Dockerproxynetwork ➔http://ntfy:80➔ntfycontainer. - Ports:
ntfydoes not expose host ports. It is only accessible via theproxynetwork. - Verification: Both
cloudflaredandntfymust appear when runningdocker network inspect proxy. - Tunnel Target:
http://ntfy:80 - Cloudflare Access: Do NOT put CF Access authentication in front of
ntfy; it breaks the iOS app's direct communication.
📂 Docker Configuration
Directory Structure (~/docker/ntfy/):
docker-compose.yml:
services:
ntfy:
image: binwiederhier/ntfy:latest
container_name: ntfy
command:
- serve
environment:
TZ: Asia/Kolkata
volumes:
- ./cache:/var/cache/ntfy
- ./config:/etc/ntfy
restart: unless-stopped
networks:
- proxy
networks:
proxy:
external: true
⚙️ Server & iOS Configuration
server.yml key settings:
base-url: "https://ntfy.parthjain.tech"
upstream-base-url: "https://ntfy.sh"
cache-file: "/var/cache/ntfy/cache.db"
auth-file: "/var/cache/ntfy/auth.db"
auth-default-access: "deny-all"
💡 Note: Both
base-urlandupstream-base-urlare required for instant iOS push delivery.
🔐 Authentication & Tokens
Anonymous access is disabled. Authentication is required.
- Primary User:
parth(has read/write access to topic*) - Check Users:
docker exec -it ntfy ntfy user list - Check ACLs:
docker exec -it ntfy ntfy access - List Tokens:
docker exec -it ntfy ntfy token list parth - Create Token:
docker exec -it ntfy ntfy token add parth
⚠️ Security Warning: Never commit access tokens (
tk_...) to Git or place them directly in source code.
🗂️ Topics & Priorities
Topic Strategy:
parth-apps(Current): Reader, finance, scrapers, background jobs.parth-homelab(Planned): Backups, docker, disk usage, updates.parth-urgent(Planned): Security alerts, disk/backup failures (Immediate attention).
Supported Priorities:
min, low, default, high, max (Reserve max for critical failures).
💻 notify CLI Adapter
A lightweight Python adapter (~/bin/notify) is used to abstract the ntfy HTTP API. It requires no virtual environments or pip dependencies.
Required Environment Variables (e.g., in ~/.zshrc):
export NTFY_URL="https://ntfy.parthjain.tech"
export NTFY_TOKEN="tk_REDACTED"
export NTFY_TOPIC="parth-apps"
export PATH="$HOME/bin:$PATH"
Basic Usage:
# Standard notification
notify "Hello from the server"
# With source and title
notify --source homelab --title "Backup complete" "Nightly backup completed successfully"
# With priority and URL
notify --source reader --title "Article ready" --priority high --url "https://reader.parthjain.tech/articles/123" "Processing finished"
Cron & Script Usage:
Cron jobs must use the absolute path (/home/<user>/bin/notify) as interactive shell paths and env vars may not load. Keep the source naming short and stable (e.g., backup, reader, docker). Titles render as [source] Title.
Direct API Testing (Without CLI):
🛠️ Troubleshooting
- HTTP 403 Forbidden: Verify the user's ACLs and token validity. If curl works but the Python script fails, check the User-Agent. Cloudflare blocks default Python user agents. The CLI explicitly uses
User-Agent: parth-notify/1.0to bypass this. - Docker Compose Errors (not found): Ensure you are executing commands from
~/docker/ntfy. Alternatively usedocker compose -f ~/docker/ntfy/docker-compose.yml logs. - Checking Logs & Status:
- Logs:
docker compose logs --tail=50 -f ntfy(Run from~/docker/ntfy) - Status:
docker ps --filter name=ntfy
📐 Design Rules
- Notifications are side-effects: A failed notification must not cause the primary application/script to fail.
- Keep it simple: Do not implement databases, delivery tracking, message brokers (Redis/RabbitMQ), or retry queues unless an application explicitly demands it. ntfy is the service.
- Do not preemptively over-engineer: Features like separate app tokens, tags, actions, or Apprise routing should only be added when actively needed.