ntfy: Push-Benachrichtigungen vom eigenen Server aufs Handy
ntfy mit Docker & Traefik selbst hosten: Push-Nachrichten aufs Handy per einfachem curl – ideal für Backup-Meldungen, Monitoring-Alerts und Skripte.
Inhaltsverzeichnis
„Backup fehlgeschlagen", „Festplatte fast voll", „neuer SSH-Login" – solche Meldungen willst du sofort aufs Handy bekommen, ohne sie an einen fremden Push-Dienst zu geben. Mit ntfy baust du dir in wenigen Minuten deinen eigenen Push-Server: Eine Nachricht ist nur ein curl-Aufruf entfernt.
Was bauen wir?
Am Ende läuft ntfy 2.26 in Docker hinter deinem Traefik-Reverse-Proxy, erreichbar unter deiner eigenen (Sub-)Domain mit HTTPS. Du kannst dann aus jedem Skript, Cronjob oder Monitoring-Tool eine Push-Nachricht verschicken – mit einem simplen HTTP-Request – und bekommst sie sofort in der ntfy-App auf dem Handy oder im Browser angezeigt, inklusive Titel, Priorität, Emojis und optionalen Aktionen.
Der Clou: ntfy ist extrem leichtgewichtig (läuft locker auf dem kleinsten VPS) und die Daten bleiben bei dir. Wir richten den Server gleich privat ein – nur mit Zugangsdaten darf jemand Nachrichten senden oder lesen.
Warum ntfy und nicht ein fertiger Dienst wie Pushover oder ein Telegram-Bot? Weil du hier keinen Account bei Dritten brauchst, keine Nachrichteninhalte an fremde Server gibst und die Schnittstelle denkbar simpel ist: Alles, was einen HTTP-Request absetzen kann – ein Shell-Skript, ein Cronjob, ein Monitoring-Tool – kann dich benachrichtigen, ganz ohne SDK oder API-Bibliothek. Genau diese Reduktion auf „POST an eine URL" macht ntfy so anschlussfähig an ein selbstgehostetes Setup.
Voraussetzungen
- Ein abgesicherter Server mit Debian 13 und Docker
- Ein laufender Traefik-Reverse-Proxy mit dem externen Netzwerk
proxyund dem Resolverle - Eine (Sub-)Domain, deren A-/AAAA-Record auf deinen Server zeigt, z. B.
ntfy.DEINE-DOMAIN.de - Optional, aber empfohlen: die ntfy-App (Android/F-Droid/iOS), um Push wirklich aufs Handy zu bekommen
ntfy ist so sparsam, dass es problemlos neben vielen anderen Diensten auf einem VPS 1000 läuft – der Server-Rechner zeigt dir, wie wenig es braucht.
VPS 1000 G12
4 vCore · 8 GB RAM · 256 GB NVMe
ab 10,36 €/Monat
Reicht für ntfy locker – der Dienst braucht kaum Ressourcen.
💶 5 € Gutschein für netcup-Neukunden:36nc17844976032
(nur Neukunden, keine Domains)
Schritt für Schritt
Schritt 1: Die compose.yaml schreiben
Leg den Projektordner an:
mkdir -p /opt/ntfy && cd /opt/ntfyErstelle /opt/ntfy/compose.yaml. Ersetze ntfy.DEINE-DOMAIN.de durch deine echte (Sub-)Domain – sie steht sowohl in der NTFY_BASE_URL als auch im Traefik-Label:
services:
ntfy:
image: binwiederhier/ntfy:v2.26
container_name: ntfy
command: serve
environment:
NTFY_BASE_URL: https://ntfy.DEINE-DOMAIN.de
NTFY_LISTEN_HTTP: ":80"
NTFY_BEHIND_PROXY: "true"
NTFY_ENABLE_LOGIN: "true"
NTFY_REQUIRE_LOGIN: "true"
NTFY_CACHE_FILE: /var/lib/ntfy/cache.db
NTFY_AUTH_FILE: /var/lib/ntfy/auth.db
NTFY_AUTH_DEFAULT_ACCESS: "deny-all"
NTFY_ATTACHMENT_CACHE_DIR: /var/lib/ntfy/attachments
volumes:
- data:/var/lib/ntfy
networks: [proxy]
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.routers.ntfy.rule=Host(`ntfy.DEINE-DOMAIN.de`)"
- "traefik.http.routers.ntfy.entrypoints=websecure"
- "traefik.http.routers.ntfy.tls.certresolver=le"
- "traefik.http.services.ntfy.loadbalancer.server.port=80"
networks:
proxy:
external: true
volumes:
data:Die wichtigsten Zeilen:
NTFY_BASE_URLmuss exakt deine öffentliche HTTPS-Adresse sein – die App und der Web-Client verweigern sonst die Verbindung.NTFY_BEHIND_PROXY: "true"sagt ntfy, dass es hinter Traefik läuft, damit es die echte Besucher-IP aus den Proxy-Headern liest (wichtig fürs Rate-Limiting).NTFY_AUTH_DEFAULT_ACCESS: "deny-all"ist die Sicherheitsschraube: Standardmäßig darf niemand lesen oder schreiben. Zugriff bekommt nur, wen wir gleich explizit anlegen. Ohne diese Zeile wäre dein Server ein offenes Push-Relay für die ganze Welt.NTFY_ENABLE_LOGIN/NTFY_REQUIRE_LOGINschalten die Anmeldung im Web-Client frei und machen sie zur Pflicht. MitNTFY_REQUIRE_LOGINempfängt ein nicht angemeldeter Besucher direkt einen Login-Screen statt einer leeren Oberfläche.
Schritt 2: Den Server starten
docker compose up -dPrüfe, dass der Container läuft:
docker compose psNAME IMAGE COMMAND SERVICE STATUS
ntfy binwiederhier/ntfy:v2.26 "ntfy serve" ntfy Up 4 seconds(Zur besseren Lesbarkeit sind die Spalten CREATED und PORTS hier ausgeblendet.)
Traefik holt automatisch ein Zertifikat. Prüfe von deinem Rechner aus den Health-Endpunkt:
curl -s https://ntfy.DEINE-DOMAIN.de/v1/health{"healthy":true}Antwortet der Server mit {"healthy":true}, steht die Kette aus DNS, Traefik, TLS und ntfy.
Schritt 3: Einen Benutzer anlegen
Weil wir deny-all gesetzt haben, brauchst du mindestens einen Benutzer. Lege einen Administrator an (er darf auf alle Themen schreiben und lesen):
docker exec -it ntfy ntfy user add --role=admin adminntfy fragt zweimal nach einem Passwort und bestätigt dann:
user admin added with role adminKontrolliere das Ergebnis:
docker exec ntfy ntfy user listuser admin (role: admin, tier: none)
- read-write access to all topics (admin role)Tipp
--role=user) an und vergibst gezielt Rechte. Lege den Benutzer zuerst an (docker exec -it ntfy ntfy user add --role=user handy) und weise ihm dann das Recht zu, z. B. docker exec ntfy ntfy access handy "serverkueche-alerts" read-only. So darf das Handy mitlesen, aber nichts senden.Schritt 4: Ein Thema abonnieren
In ntfy läuft alles über Themen (englisch „topics") – frei wählbare Namen, unter denen Nachrichten laufen. Öffne https://ntfy.DEINE-DOMAIN.de im Browser. Dank NTFY_REQUIRE_LOGIN empfängt dich der Web-Client direkt mit einem Login-Screen – melde dich dort mit deinem angelegten admin-Konto an (ohne Login blockt deny-all jeden Lese- und Abo-Versuch mit HTTP 403). Danach klickst du links auf Thema abonnieren und wählst einen schwer zu erratenden Namen (z. B. serverkueche-alerts):

Auf dem Handy richtest du deinen eigenen Server einmalig in der ntfy-App ein: Öffne Einstellungen → Standard-Server und trage https://ntfy.DEINE-DOMAIN.de ein. Danach hinterlegst du unter Benutzerverwaltung deine Zugangsdaten für diesen Server. Jetzt kannst du wie im Browser ein Thema hinzufügen – die App fragt dabei nicht mehr nach dem großen ntfy.sh-Server, sondern nutzt deinen. Ab sofort landet jede Nachricht an dieses Thema als echte Push-Benachrichtigung auf dem Gerät, auch bei geschlossener App. Auf iOS läuft der Empfang über Apples Push-Dienst; die App erklärt beim ersten Start, was dafür einmalig nötig ist.
Browser-Benachrichtigungen erlauben
Schritt 5: Eine Nachricht senden
Jetzt der eigentliche Zweck – eine Nachricht per curl verschicken. Weil der Server privat ist, gibst du deine Zugangsdaten mit (-u BENUTZER:PASSWORT):
curl -u admin:DEIN_PASSWORT -d "Backup erfolgreich abgeschlossen" https://ntfy.DEINE-DOMAIN.de/serverkueche-alertsDas war’s – die Nachricht ist sofort auf allen abonnierten Geräten. Mit ein paar zusätzlichen Headern wird sie aussagekräftiger: Titel, Priorität (1–5) und Tags (die auch als Emojis erscheinen):
curl -u admin:DEIN_PASSWORT \
-H "Title: Warnung vom Monitoring" \
-H "Priority: 4" \
-H "Tags: warning" \
-d "Hohe CPU-Last auf dem VPS" \
https://ntfy.DEINE-DOMAIN.de/serverkueche-alertsDie Priorität steuert, wie aufdringlich die Meldung ankommt: 5 (max) lässt das Handy klingeln und vibrieren, 4 (high) meldet sich deutlich, 3 ist der Standard, 2 und 1 (low/min) landen leise in der Liste. Für „Server nicht erreichbar" nimmst du 5, für „Backup ok" eher 2 – so stumpfst du dich nicht gegen die wichtigen Alarme ab.
Tags werden zu Emojis, wenn sie einem bekannten Namen entsprechen: warning → ⚠️, white_check_mark → ✅, rotating_light → 🚨. Mehrere Tags gibst du kommagetrennt an (-H "Tags: rotating_light,skull"). Und mit dem Header Click öffnet ein Tippen auf die Nachricht direkt eine URL – praktisch, um vom Alarm sofort ins Dashboard zu springen:
curl -u admin:DEIN_PASSWORT \
-H "Title: Uptime Kuma: Dienst down" \
-H "Priority: 5" \
-H "Tags: rotating_light" \
-H "Click: https://status.DEINE-DOMAIN.de" \
-d "Nextcloud antwortet nicht mehr" \
https://ntfy.DEINE-DOMAIN.de/serverkueche-alertsRichtig mächtig wird es mit Aktions-Buttons: Über den Header Actions blendest du direkt in der Benachrichtigung Schaltflächen ein, die eine URL öffnen oder einen HTTP-Request auslösen – so quittierst du einen Alarm mit einem Fingertipp, ohne die App überhaupt zu öffnen:
curl -u admin:DEIN_PASSWORT \
-H "Title: Server neu starten?" \
-H "Actions: view, Status öffnen, https://status.DEINE-DOMAIN.de" \
-d "Ein Dienst hängt – im Statusboard nachsehen." \
https://ntfy.DEINE-DOMAIN.de/serverkueche-alertsDieselbe Nachricht kannst du auch bequem über den Web-Client zusammenklicken – praktisch zum Ausprobieren aller Optionen:

Schritt 6: Nachrichten kommen an
Im Web-Client (sofern du dort wie in Schritt 4 mit deinem admin-Konto angemeldet bist) und parallel in der App tauchen die Nachrichten sofort auf – mit Titel, Zeitstempel und farblich hervorgehobener Priorität:

Den Web-Client kannst du in Chrome oder Edge übrigens als App installieren (PWA): Dann bekommst du auch am Desktop Push-Benachrichtigungen, ohne einen Tab offen halten zu müssen – praktisch, wenn der Rechner ohnehin läuft und du Alarme direkt auf dem Bildschirm sehen willst.
Schritt 7: Access-Tokens für Skripte statt Passwort
Ein Passwort in jedem Cronjob und Backup-Skript zu hinterlegen ist unschön. Besser ist ein Access-Token, den du jederzeit einzeln widerrufen kannst:
docker exec ntfy ntfy token add adminntfy gibt einen Token zurück, der mit tk_ beginnt. Den nutzt du dann statt -u als Bearer-Token:
curl -H "Authorization: Bearer tk_DEIN_TOKEN" \
-H "Title: Nächtliches Backup" \
-d "Restic-Backup ohne Fehler durchgelaufen" \
https://ntfy.DEINE-DOMAIN.de/serverkueche-alertsSo kannst du ntfy sauber in deine Restic-Backups einbauen (Meldung am Ende des Backup-Skripts) oder von Uptime Kuma als Benachrichtigungskanal ansprechen lassen – Uptime Kuma kennt ntfy als eingebauten Notification-Typ.
Schritt 8: Praxisbeispiel – ein Backup-Skript, das sich meldet
Am nützlichsten wird ntfy, wenn ein Skript automatisch Bescheid gibt. Das folgende Muster wickelt einen beliebigen Befehl ein und schickt je nach Ausgang eine leise Erfolgs- oder eine laute Fehlermeldung. Leg es als /opt/scripts/backup-notify.sh an und passe Domain, Token und den eigentlichen Backup-Befehl an:
#!/usr/bin/env bash
set -uo pipefail
NTFY_URL="https://ntfy.DEINE-DOMAIN.de/serverkueche-alerts"
NTFY_TOKEN="tk_DEIN_TOKEN"
# Hier steht dein echter Backup-Befehl – Exit-Code entscheidet über die Meldung:
if restic backup /opt --tag nightly; then
curl -s -H "Authorization: Bearer $NTFY_TOKEN" \
-H "Title: Backup ok" -H "Tags: white_check_mark" -H "Priority: 2" \
-d "Nächtliches Backup ohne Fehler durchgelaufen." "$NTFY_URL"
else
curl -s -H "Authorization: Bearer $NTFY_TOKEN" \
-H "Title: BACKUP FEHLGESCHLAGEN" -H "Tags: rotating_light" -H "Priority: 5" \
-d "Das Backup ist mit einem Fehler abgebrochen – bitte sofort prüfen." "$NTFY_URL"
fiMach es ausführbar und teste es einmal von Hand:
chmod +x /opt/scripts/backup-notify.sh
/opt/scripts/backup-notify.shLäuft es sauber, hängst du es in einen Cronjob – so bekommst du jede Nacht eine kurze Bestätigung und wirst bei einem Fehler mit voller Priorität geweckt:
crontab -e30 3 * * * /opt/scripts/backup-notify.shDas Prinzip lässt sich auf alles übertragen: ein Zertifikat läuft ab, eine Platte wird voll (df im Skript prüfen), ein Deployment ist durch. Immer derselbe Einzeiler – ein curl an dein Thema. Genau das macht ntfy so praktisch: Du musst nichts integrieren, was HTTP kann, kann dich benachrichtigen.
Wenn es nicht funktioniert
Die App meldet „Cannot connect" oder der Web-Client bleibt leer. Die NTFY_BASE_URL passt nicht
zur aufgerufenen Adresse. Sie muss exakt deine öffentliche HTTPS-URL sein
(https://ntfy.DEINE-DOMAIN.de, ohne Slash am Ende). Nach einer Änderung docker compose up -d
erneut ausführen.
curl liefert HTTP 401 oder 403. Bei deny-all sind fehlende oder falsche Zugangsdaten der
häufigste Fehler. Benutzer/Passwort prüfen (docker exec ntfy ntfy user list) und beim Senden -u BENUTZER:PASSWORT bzw. den Bearer-Token mitgeben. Ein 403 bedeutet, dass der Benutzer existiert,
aber keine Rechte auf dieses Thema hat – dann mit ntfy access Rechte vergeben.
Nachrichten kommen im Browser an, aber nicht als Push aufs Handy, wenn der Tab zu ist. Browser-Push braucht erteilte Benachrichtigungsrechte und einen aktiven Service Worker; das ist unzuverlässig, sobald der Tab geschlossen ist. Für echtes „unterwegs"-Push die ntfy-App verwenden – sie hält die Verbindung im Hintergrund.
502 Bad Gateway von Traefik. Der Container ist noch nicht bereit oder hört auf dem falschen
Port. Prüfe docker compose logs ntfy und dass das Label loadbalancer.server.port=80 gesetzt ist
– ntfy lauscht im Container auf Port 80 (NTFY_LISTEN_HTTP=":80").
429 Too Many Requests bei vielen Nachrichten kurz hintereinander. ntfy begrenzt standardmäßig
die Rate pro Absender, um Missbrauch zu verhindern. Bei einem privaten Server mit eigenen Skripten
stößt du selten daran – ein Schleifen-Skript ohne Pause aber schon. Nachrichten bündeln statt im
Sekundentakt zu feuern, oder die Limits gezielt über die NTFY_VISITOR_*-Umgebungsvariablen anheben
(in der ntfy-Doku unter „Rate limiting" beschrieben). NTFY_BEHIND_PROXY: "true" ist Voraussetzung,
damit das Limit pro echter IP statt pro Traefik-Container greift.
Wartung & Backups
Updates ziehst du innerhalb der gepinnten Version so:
cd /opt/ntfy && docker compose pull && docker compose up -dFür einen Sprung auf eine neue Hauptversion vorher die Release-Notes lesen und den Image-Tag anheben.
Backups: ntfy speichert Benutzer, Zugriffsrechte und den Nachrichten-Cache in seinen SQLite-Dateien im Volume (cache.db, auth.db). Sichere den Inhalt regelmäßig, indem du das Volume in ein Archiv packst …
docker run --rm -v ntfy_data:/data -v /opt/backups:/backup alpine:3 \
tar czf /backup/ntfy-data.tar.gz -C /data .… und dieses Archiv in dein verschlüsseltes Off-Site-Backup mit Restic aufnimmst. Der Nachrichten-Cache ist zwar verzichtbar (Push-Nachrichten sind flüchtig), aber die Benutzer- und Rechte-Datenbank willst du nach einem Ausfall nicht neu aufbauen müssen.
Im Alltag ist ntfy nahezu wartungsfrei. Kontrolliere gelegentlich mit docker exec ntfy ntfy user list, wer Zugriff hat, und widerrufe nicht mehr genutzte Tokens mit ntfy token remove BENUTZER TOKEN-ID (die IDs zeigt dir ntfy token list BENUTZER) – so bleibt dein Push-Server dein eigener.
Feedback per E-Mail: feedback@serverkueche.de
Das könnte dir auch schmecken

Uptime Kuma installieren: Server-Monitoring hinter Traefik
Uptime Kuma hinter Traefik aufsetzen und deine Dienste überwachen: Monitore, Benachrichtigungen und eine Status-Seite – …

Monitoring mit Grafana & Prometheus: dein Server in Live-Dashboards
Ein vollständiger Monitoring-Stack aus Prometheus, node-exporter, cAdvisor und Grafana hinter Traefik – mit …

Die eigene Website mit Hugo hosten – wie die Serverküche selbst
Statische Website mit Hugo bauen und im Docker-Container hinter Traefik ausliefern – schnell, sicher, ohne Datenbank. …