Zum Inhalt springen
Serverküche
Suche

Die Suche wird geladen … (nur in der veröffentlichten Seite verfügbar).

Anwendungen Schwierigkeit: Fortgeschritten

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.

· 10 Min. Lesezeit ·Dauer: ca. 40 Minuten
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

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.

🍳 Empfehlung Anzeige

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.

Zu netcup →

💶 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:

Terminal
mkdir -p /opt/ntfy && cd /opt/ntfy

Erstelle /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:

YAML
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_URL muss 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_LOGIN schalten die Anmeldung im Web-Client frei und machen sie zur Pflicht. Mit NTFY_REQUIRE_LOGIN empfängt ein nicht angemeldeter Besucher direkt einen Login-Screen statt einer leeren Oberfläche.

Schritt 2: Den Server starten

Terminal
docker compose up -d

Prüfe, dass der Container läuft:

Terminal
docker compose ps
Ausgabe
NAME   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:

Terminal
curl -s https://ntfy.DEINE-DOMAIN.de/v1/health
Ausgabe
{"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):

Terminal
docker exec -it ntfy ntfy user add --role=admin admin

ntfy fragt zweimal nach einem Passwort und bestätigt dann:

Ausgabe
user admin added with role admin

Kontrolliere das Ergebnis:

Terminal
docker exec ntfy ntfy user list
Ausgabe
user admin (role: admin, tier: none)
- read-write access to all topics (admin role)

Tipp

Für einzelne Personen oder Geräte, die nur bestimmte Themen nutzen sollen, legst du normale Benutzer (--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):

ntfy-Web-Oberfläche mit dem Dialog zum Abonnieren eines neuen Themas
Ein Thema abonnieren – der Name sollte nicht zu erraten sein

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

Zeigt der Web-Client oben links „Benachrichtigungen sind blockiert", musst du sie in deinem Browser für diese Seite noch erlauben – sonst siehst du die Nachrichten nur, solange der Tab offen ist. Für zuverlässige Push-Nachrichten unterwegs ist die Handy-App ohnehin die bessere Wahl.

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):

Terminal
curl -u admin:DEIN_PASSWORT -d "Backup erfolgreich abgeschlossen" https://ntfy.DEINE-DOMAIN.de/serverkueche-alerts

Das 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):

Terminal
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-alerts

Die 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:

Terminal
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-alerts

Richtig 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:

Terminal
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-alerts

Dieselbe Nachricht kannst du auch bequem über den Web-Client zusammenklicken – praktisch zum Ausprobieren aller Optionen:

ntfy-Dialog zum Senden einer Nachricht mit Feldern für Thema, Titel, Priorität und Tags
Der Sende-Dialog im Web-Client zeigt alle Optionen: Titel, Priorität, Tags, Anhänge

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:

ntfy-Web-Oberfläche mit drei empfangenen Benachrichtigungen im abonnierten Thema
Empfangene Nachrichten im Thema – mit Titel, Priorität und Emoji-Tags

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:

Terminal
docker exec ntfy ntfy token add admin

ntfy gibt einen Token zurück, der mit tk_ beginnt. Den nutzt du dann statt -u als Bearer-Token:

Terminal
curl -H "Authorization: Bearer tk_DEIN_TOKEN" \
  -H "Title: Nächtliches Backup" \
  -d "Restic-Backup ohne Fehler durchgelaufen" \
  https://ntfy.DEINE-DOMAIN.de/serverkueche-alerts

So 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:

Terminal
#!/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"
fi

Mach es ausführbar und teste es einmal von Hand:

Terminal
chmod +x /opt/scripts/backup-notify.sh
/opt/scripts/backup-notify.sh

Lä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:

Terminal
crontab -e
Ausgabe
30 3 * * * /opt/scripts/backup-notify.sh

Das 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:

Terminal
cd /opt/ntfy && docker compose pull && docker compose up -d

Fü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 …

Terminal
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