Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Docker 30.09.2026 · 11 min Lesezeit

Apprise API mit Docker Compose: ein Endpunkt für alle Admin-Benachrichtigungen

Die Apprise API bündelt Benachrichtigungen aus Skripten, Cronjobs und Monitoring in einem HTTP-Endpunkt und verteilt sie an E-Mail, ntfy, Gotify, Teams oder Matrix. Die Anleitung zeigt die getestete compose.yaml für Version 2.0, gespeicherte Ziele mit Tags, den neuen eingebauten Login, Backup mit Restore-Nachweis und typische Fehler.

Beschrieben für apprise 2.0.0

Mit KI erstellt – redaktionelle Prüfung ausstehend

WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Illustration: Apprise API als zentraler Benachrichtigungs-Gateway mit Docker, Karten für E-Mail und Chat, Push-Dienste und Login

Backup-Skripte, Cronjobs, Monitoring und Update-Checks wollen alle Bescheid geben, wenn etwas schiefgeht. In der Praxis landet dafür in jedem Skript ein eigener Mailversand, ein ntfy-Aufruf oder ein Teams-Webhook, jeweils mit eigenen Zugangsdaten. Wechselt der Kanal, müssen Sie an zehn Stellen nacharbeiten. Die Apprise API dreht das um: Alle Systeme schicken einen einfachen HTTP-Aufruf an einen zentralen Dienst, und erst dort ist hinterlegt, ob die Meldung per E-Mail, ntfy, Gotify, Matrix oder Microsoft Teams hinausgeht. Diese Anleitung richtet die Apprise API 2.0 mit Docker Compose ein, mit Login, Healthcheck sowie geprüftem Backup und Restore.

Voraussetzungen

Apprise selbst ist eine Python-Bibliothek unter BSD-2-Clause-Lizenz, die Apprise API das zugehörige Web- und API-Frontend unter MIT-Lizenz. Laut GitHub-API hatte caronc/apprise am 30.09.2026 17.488 Sterne, caronc/apprise-api rund 1.300. Beide Projekte erschienen am 26.09.2026 als Version 2.0.0, heise berichtete am 29.09.2026 ausführlich über die neue Hauptversion.

  • Linux-Host oder VM mit Docker Engine und Compose-Plugin, x86_64 (amd64) oder ARM (arm64, laut README auch arm/v7).
  • 1 CPU-Kern und 512 MB freier RAM genügen. Mit einem Worker (APPRISE_WORKER_COUNT=1) belegte der Container im Test 96 MiB.
  • Rund 500 MB Speicher für das Image (etwa 121 MB komprimiert) plus wenige Kilobyte für die Konfiguration.
  • Port 8000 im Container, auf dem Host nur an 127.0.0.1 gebunden. Für Zugriffe aus dem Netz ein Reverse Proxy mit TLS auf Port 443.
  • Zugangsdaten der Zielkanäle, etwa ein SMTP-Konto, ein ntfy-Topic, ein Gotify-Token oder eine Teams-Workflow-URL.
  • Ausgehende Verbindungen vom Host zu diesen Zielen, zum Beispiel TCP 587 für SMTP und 443 für Push-Dienste.
EckdatenWert
Imagecaronc/apprise:2.0.0 (identisch mit 2.0, v2.0.0 und am 30.09.2026 latest)
Port8000/tcp (nginx im Container, dahinter gunicorn)
Volumes/config (Konfiguration, Logins, Store), /attach (Anhänge), optional /plugin
Wichtige EnvAPPRISE_STATEFUL_MODE, APPRISE_AUTH_REQUIRED, APPRISE_USER, APPRISE_PASSWORD, APPRISE_API_ONLY, STRICT_MODE

Schritt 1: Projektordner und .env anlegen

Legen Sie einen Ordner an und erzeugen Sie die Verzeichnisse vorab mit Ihrem Benutzer. Der Container läuft unter der UID aus PUID, und nur wenn diese zu den Ordnern passt, kann er dort schreiben.

sudo mkdir -p /opt/apprise && sudo chown "$USER": /opt/apprise
cd /opt/apprise
mkdir -p config attach
# Administrator-Passwort zufällig erzeugen
printf 'PUID=%s\nPGID=%s\nAPPRISE_USER=admin\nAPPRISE_PASSWORD=%s\n' \
  "$(id -u)" "$(id -g)" "$(openssl rand -hex 16)" > .env
chmod 600 .env

Die fertige .env sieht so aus, das Passwort ist hier ein Platzhalter:

PUID=1000
PGID=1000
APPRISE_USER=admin
APPRISE_PASSWORD=bitte-ersetzen

Verifizieren: ls -ln zeigt config und attach mit derselben UID wie in der .env, und stat -c %a .env liefert 600.

Schritt 2: compose.yaml schreiben

Die Datei basiert auf dem offiziellen docker-compose.yml und dem gehärteten Beispiel aus der README. Geändert sind das feste Tag, die Bindung an localhost, die eingeschaltete Anmeldung und ein Healthcheck.

services:
  apprise:
    image: caronc/apprise:2.0.0
    container_name: apprise
    restart: unless-stopped
    user: "${PUID:-1000}:${PGID:-1000}"
    ports:
      - "127.0.0.1:8000:8000"
    environment:
      TZ: Europe/Berlin
      APPRISE_STATEFUL_MODE: simple
      APPRISE_WORKER_COUNT: "1"
      APPRISE_DEFAULT_FORMAT: text
      APPRISE_AUTH_REQUIRED: "yes"
      APPRISE_USER: ${APPRISE_USER}
      APPRISE_PASSWORD: ${APPRISE_PASSWORD}
      APPRISE_API_ONLY: "yes"
      STRICT_MODE: "yes"
    volumes:
      - ./config:/config
      - ./attach:/attach
    tmpfs:
      - /tmp
    healthcheck:
      test: ["CMD-SHELL", "curl -fsS -u \"$$APPRISE_USER:$$APPRISE_PASSWORD\" http://localhost:8000/status || exit 1"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 60s

Die Parameter im Einzelnen:

  • APPRISE_STATEFUL_MODE: simple speichert jeden Schlüssel als lesbare Datei, etwa config/srv-monitoring.yml. Der Standard hash legt Dateien unter Hash-Namen ab, was Backups weniger übersichtlich macht.
  • APPRISE_AUTH_REQUIRED schaltet die mit Version 2.0 eingeführte Basic-Auth ein. Ohne diese Variable ist jeder Endpunkt ohne Anmeldung erreichbar.
  • APPRISE_API_ONLY sperrt die Weboberfläche und lässt nur die API zu. Wer Ziele lieber per Browser pflegt, lässt die Zeile weg.
  • STRICT_MODE beantwortet unbekannte Pfade mit 404 und verschärft laut README die Ratenbegrenzung bei Anmeldungen.
  • tmpfs: /tmp folgt dem gehärteten Beispiel: nginx und gunicorn schreiben temporäre Dateien und den Socket dorthin.
  • Das doppelte $$ im Healthcheck verhindert, dass Compose die Variablen selbst ersetzt. Sie werden erst im Container aufgelöst.

Verifizieren: docker compose config -q endet ohne Ausgabe. Eine Fehlermeldung weist auf Einrückung oder eine fehlende .env hin.

Schritt 3: Container starten und Status prüfen

docker compose up -d
docker compose ps
# Status mit Anmeldung abfragen
set -a; . ./.env; set +a
curl -s -u "$APPRISE_USER:$APPRISE_PASSWORD" http://127.0.0.1:8000/status

In den ersten rund 20 Sekunden antwortet nginx mit HTTP 504 und der Seite Service Temporarily Unavailable, weil gunicorn noch startet. Im Log steht dann upstream timed out. Das ist kein Fehler. Nach einem Neustart dauerte es im Test 18 bis 24 Sekunden bis zur Antwort OK. Die JSON-Variante mit -H 'Accept: application/json' zeigt zusätzlich, ob Konfiguration, Anhänge und Store beschreibbar sind.

Verifizieren: curl liefert OK mit HTTP 200, docker compose ps zeigt nach etwa einer Minute (healthy), und docker compose logs apprise enthält Booting worker.

Schritt 4: Erste Nachricht ohne gespeicherte Konfiguration

Der zustandslose Endpunkt /notify nimmt Ziel-URLs direkt im Aufruf entgegen. Das eignet sich zum Ausprobieren einer URL-Syntax. Im Test diente ein Mailpit-Container im selben Compose-Netz als SMTP-Ziel, sodass die Zustellung am Postfach nachweisbar war.

curl -u "$APPRISE_USER:$APPRISE_PASSWORD" -X POST \
  -F 'urls=mailto://mailpit:1025?from=apprise@example.com&to=admin@example.com' \
  -F 'title=Stateless-Test' -F 'body=Hallo aus Apprise 2.0' \
  http://127.0.0.1:8000/notify

Die Antwort enthielt Sent Email to admin@example.com, die Mail lag danach in Mailpit. Für echte Kanäle ersetzen Sie die URL. Beispiele aus der Apprise-README:

  • E-Mail mit STARTTLS: mailtos://benutzer:passwort@example.com?smtp=mail.example.com&to=it@example.com
  • ntfy: ntfys://mein-topic/ bzw. eigener Server über die Host-Syntax der ntfy-Doku
  • Gotify: gotifys://gotify.example.com/APP-TOKEN
  • Microsoft Teams über Power Automate Workflows: workflows://WorkflowID/Signature/
  • Matrix: matrixs://benutzer:passwort@matrix.example.com/#raum

Verifizieren: Die Antwort meldet Sent ... mit HTTP 200, und die Nachricht kommt im Zielkanal an. HTTP 424 bedeutet, dass das Ziel nicht erreichbar war.

Schritt 5: Ziele dauerhaft unter einem Schlüssel speichern

Im Alltag sollen Skripte keine Zugangsdaten kennen. Speichern Sie die Ziele deshalb als YAML unter einem Schlüssel und vergeben Sie Tags, mit denen Sie Empfängergruppen auswählen.

urls:
  - mailtos://benutzer:passwort@example.com?smtp=mail.example.com&to=it@example.com:
      tag: admins, backup
  - ntfys://bereitschaft-alarm/:
      tag: oncall
# Wichtig: config=< übergibt den Dateiinhalt, config=@ würde die Datei hochladen
curl -u "$APPRISE_USER:$APPRISE_PASSWORD" -X POST \
  -F format=yaml -F 'config=<ziele.yml' \
  http://127.0.0.1:8000/add/srv-monitoring
# Nur die Ziele mit Tag backup benachrichtigen
curl -u "$APPRISE_USER:$APPRISE_PASSWORD" -X POST \
  -d 'title=Backup fehlgeschlagen' -d 'body=Job nas01 Exit 2' \
  -d 'type=failure' -d 'tag=backup' \
  http://127.0.0.1:8000/notify/srv-monitoring

Im Test erreichte tag=backup genau einen Empfänger, tag=all beide. Mit /json/urls/srv-monitoring?privacy=1 lesen Sie die hinterlegten Ziele mit ausgeblendeten Geheimnissen zurück.

Verifizieren: /add antwortet Successfully saved configuration, im Ordner config liegt srv-monitoring.yml mit Rechten 600, und der Notify-Aufruf liefert HTTP 200.

Schritt 6: Zugriff absichern und eigene Logins für Skripte

Ab Werk verlangt die Apprise API keine Anmeldung. Wer den Port erreicht, kann über Ihre hinterlegten Konten Nachrichten verschicken und bei offener Oberfläche Zugangsdaten auslesen. Mit der Konfiguration aus Schritt 2 ergab der Test: ohne Login HTTP 401, mit falschem Passwort HTTP 401, mit richtigem HTTP 200. Die Weboberfläche antwortete wegen APPRISE_API_ONLY auch angemeldet mit HTTP 421.

Skripte sollten nicht das Administrator-Passwort kennen. Version 2.0 erlaubt deshalb Logins pro Schlüssel. Mit locked darf das Konto nur mit konkretem Tag senden und die Konfiguration nicht lesen:

curl -u "$APPRISE_USER:$APPRISE_PASSWORD" -X POST \
  -H 'Content-Type: application/json' \
  -d '{"access":"locked","username":"backupjob","password":"LANGES-PASSWORT"}' \
  http://127.0.0.1:8000/auth/srv-monitoring

Im Test sendete backupjob mit tag=backup erfolgreich, tag=all wurde mit HTTP 400 und A specific tag other than 'all' is required abgewiesen, /get/srv-monitoring mit HTTP 403.

Verifizieren: Ein Aufruf ohne -u liefert 401, das Skript-Konto erreicht nur seine Tags, und im Ordner config liegt die Datei .srv-monitoring.lock.

Schritt 7: Reverse Proxy mit TLS

Basic-Auth überträgt das Passwort nur kodiert, nicht verschlüsselt. Sobald andere Server die API erreichen sollen, gehört TLS davor. Ein minimales Caddyfile:

apprise.example.com {
    reverse_proxy 127.0.0.1:8000
}

Laut README sollten Sie hinter HTTPS zusätzlich APPRISE_TRUSTED_ORIGINS: https://apprise.example.com setzen, weil das mitgelieferte nginx das ursprüngliche Schema nicht weiterreicht. Für einen Unterpfad gibt es APPRISE_BASE_URL. Beschränken Sie den Zugriff zusätzlich per Firewall auf die Server, die tatsächlich melden.

Verifizieren: curl -I https://apprise.example.com/status liefert ohne Anmeldung 401 mit gültigem Zertifikat, ss -tlnp | grep 8000 zeigt nur 127.0.0.1.

Schritt 8: Backup und Restore

Alles Wichtige liegt in config: Schlüsseldateien, .<schlüssel>.lock mit den Logins, .web_auth_secret und der Store. Die YAML-Dateien enthalten Klartext-Zugangsdaten, das Backup ist entsprechend zu schützen.

cd /opt/apprise
tar czf /backup/apprise-config-$(date +%F).tgz -C config .
# Restore: stoppen, zurückspielen, starten
docker compose stop apprise
tar xzf /backup/apprise-config-2026-09-30.tgz -C config
docker compose start apprise

Im Test wurde nach dem Backup die Schlüsseldatei gelöscht. Der Notify-Aufruf lieferte danach nur noch HTTP 204 ohne Zustellung. Nach dem Restore war die Prüfsumme von srv-monitoring.yml identisch, und die Nachricht kam wieder an.

Verifizieren: tar tzf listet die .yml- und .lock-Dateien, nach dem Restore liefert ein Test-Notify HTTP 200 mit Sent ....

Schritt 9: Updates und Rollback

Ändern Sie das Tag bewusst in der compose.yaml, sichern Sie vorher config und führen Sie dann docker compose pull und docker compose up -d aus. Auf latest sollten Sie nicht setzen: Das Tag springt ungefragt zur nächsten Hauptversion, und edge folgt dem Entwicklungszweig. Apprise 2.0 bringt laut Release-Notes Breaking Changes für Entwickler, die die Bibliothek einbinden. Ob eine unter 2.0 geschriebene Konfiguration mit Logins unter 1.5.4 fehlerfrei läuft, ist nicht bestätigt. Rollback heißt deshalb: altes Tag plus Backup von vor dem Update.

Verifizieren: docker compose exec apprise pip show apprise zeigt die erwartete Version, /status liefert OK.

Schritt 10: Apprise vollständig entfernen

Achtung: Der letzte Befehl löscht alle gespeicherten Ziele und Logins unwiderruflich. Sichern Sie config vorher, falls Sie die Daten noch brauchen.

cd /opt/apprise
docker compose down -v --remove-orphans
docker rmi caronc/apprise:2.0.0
sudo rm -rf /opt/apprise

Verifizieren: docker ps -a --filter name=apprise ist leer, und docker images listet kein caronc/apprise mehr.

Troubleshooting

SymptomUrsacheLösung
HTTP 504 Service Temporarily Unavailable direkt nach dem Startgunicorn bootet noch20 bis 30 Sekunden warten, start_period nicht zu knapp wählen
/status HTTP 417 CONFIG_PERMISSION_ISSUE,ATTACH_PERMISSION_ISSUE,STORE_PERMISSION_ISSUE, /add HTTP 500UID aus PUID passt nicht zu den Ordnern, im Log Permission denied: '/config/.web_auth_secret'PUID/PGID an den Besitzer anpassen oder chown auf die Ordner
/add meldet No valid URL(s) defined trotz korrekter YAML-F config=@datei lädt eine Datei hoch statt eines Formularfelds-F 'config=<datei' verwenden
HTTP 204, aber keine NachrichtSchlüssel existiert nicht oder URL unlesbar (Log: Unparseable URL)Schlüssel prüfen, in Skripten nur 200 als Erfolg werten
HTTP 424 Connection error while submitting email to "localhost"localhost zeigt auf den Apprise-Container selbstHostname oder Compose-Dienstnamen des Ziels eintragen
HTTP 424 One or more notification could not be sentTag passt zu keinem ZielTags per /json/urls/<schlüssel>?privacy=1 prüfen

Häufige Fragen

Welche Dienste unterstützt Apprise?

Die README listet über 100 Dienste, von E-Mail über ntfy, Gotify, Matrix, Telegram und Signal bis zu Teams über Power Automate Workflows und SMS-Anbietern. Die jeweilige URL-Syntax steht in der Tabelle der Apprise-README.

Brauche ich neben Apprise noch ntfy oder Gotify?

Für Push-Nachrichten aufs Smartphone ja. Apprise ist nur der Verteiler, den Push-Dienst betreiben Sie selbst oder nutzen einen öffentlichen Server.

Warum ist HTTP 204 gefährlich?

Ein Tippfehler im Schlüssel liefert kein 404, sondern 204 ohne Inhalt. Ein Skript, das nur auf Exit-Code 0 von curl achtet, merkt den Fehler nie. Nutzen Sie curl -fsS -o /dev/null -w '%{http_code}' und werten Sie nur 200 als Erfolg.

Wo liegen die Zugangsdaten der Zielkanäle?

Im Modus simple im Klartext in config/<schlüssel>.yml. Apprise 2.0 kann Geheimnisse laut Release-Notes über ${NAME}-Platzhalter und APPRISE_TEMPLATE_<NAME> auslagern.

Testumfang

Getestet wurden am 30.09.2026 mit caronc/apprise:2.0.0 Start und Healthcheck, zustandslose und gespeicherte Benachrichtigungen mit Zustellnachweis per Mailpit, Tags, Negativfälle, Basic-Auth mit Administrator- und locked-Login, APPRISE_API_ONLY, STRICT_MODE, falsche UID, Neustart sowie Backup und Restore. Nur aus der Dokumentation stammen die echten Ziele ntfy, Gotify, Teams und Matrix, der Caddy-Proxy mit TLS sowie das Update- und Rollback-Verhalten.

Fazit

Die Apprise API ist ein kleiner, schnell eingerichteter Baustein, der Benachrichtigungen im Betrieb deutlich aufräumt: Skripte kennen nur noch eine URL und einen Tag, Kanalwechsel erledigen Sie an einer Stelle. Mit Version 2.0 fällt der größte Kritikpunkt weg, weil endlich ein eingebauter Login existiert. Einschalten müssen Sie ihn aber selbst, und Skripte sollten den Statuscode auswerten, statt sich auf HTTP 204 zu verlassen.

Weiterführende Anleitungen und Quellen

AppriseDocker ComposeBenachrichtigungenMonitoringntfyGotifySelfhostingBasic Auth