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.
Werbung Mit * 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

Backup-Skripte, Cronjobs, Monitoring und Update-Checks melden Fehler meist über eigenen Mailversand, ntfy-Aufruf oder Teams-Webhook, jeweils mit eigenen Zugangsdaten. Wechselt der Kanal, müssen Sie an vielen 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. Beide Projekte erschienen am 26.09.2026 als Version 2.0.0; heise berichtete am 29.09.2026 ü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). Fehlt beides, hilft die Anleitung Docker und Docker Compose auf Linux installieren.
- 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.1gebunden. 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.
| Eckdaten | Wert |
|---|---|
| Image | caronc/apprise:2.0.0 (identisch mit 2.0, v2.0.0 und aktuell latest) |
| Port | 8000/tcp (nginx im Container, dahinter gunicorn) |
| Volumes | /config (Konfiguration, Logins, Store), /attach (Anhänge), optional /plugin |
| Wichtige Env | APPRISE_STATEFUL_MODE, APPRISE_AUTH_REQUIRED, APPRISE_USER, APPRISE_PASSWORD, APPRISE_API_ONLY, STRICT_MODE |
Schritt 1: Projektordner und .env anlegen
Legen Sie den Ordner und die Verzeichnisse mit Ihrem Benutzer an. Der Container läuft unter der UID aus PUID und kann nur schreiben, wenn diese zu den Ordnern passt.
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 .envDie fertige .env sieht so aus (Passwort als Platzhalter):
PUID=1000
PGID=1000
APPRISE_USER=admin
APPRISE_PASSWORD=bitte-ersetzenls -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 README-Beispiel. Geändert sind das feste Tag, die Bindung an localhost, die Anmeldung und ein Healthcheck. Die Grundlagen zu Healthchecks, Secrets und Betrieb ohne Root zeigt Docker Compose absichern.
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: 60sDie Parameter im Einzelnen:
APPRISE_STATEFUL_MODE: simplespeichert jeden Schlüssel als lesbare Datei, etwaconfig/srv-monitoring.yml. Der Standardhashlegt Hash-Namen an.APPRISE_AUTH_REQUIREDschaltet die mit Version 2.0 eingeführte Basic-Auth ein. Ohne diese Variable ist jeder Endpunkt ohne Anmeldung erreichbar.APPRISE_API_ONLYsperrt die Weboberfläche und lässt nur die API zu. Zur Pflege per Browser lassen Sie die Zeile weg.STRICT_MODEbeantwortet unbekannte Pfade mit 404 und verschärft laut README die Ratenbegrenzung bei Anmeldungen.tmpfs: /tmpfolgt 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.
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/statusIn 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; im Test dauerte es nach einem Neustart 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.
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 und eignet sich zum Ausprobieren der 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/notifyDie 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
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
Skripte sollen keine Zugangsdaten kennen. Speichern Sie die Ziele deshalb als YAML unter einem Schlüssel und vergeben Sie Tags für Empfängergruppen.
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-monitoringIm 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.
/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. 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-monitoringIm 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.
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. Sobald andere Server die API erreichen, 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.
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 appriseIm 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.
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. Setzen Sie nicht auf latest, das Tag springt ungefragt zur nächsten Hauptversion. 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.
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/apprisedocker ps -a --filter name=apprise ist leer, und docker images listet kein caronc/apprise mehr.
Troubleshooting
| Symptom | Ursache | Lösung |
|---|---|---|
HTTP 504 Service Temporarily Unavailable direkt nach dem Start | gunicorn bootet noch | 20 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 500 | UID 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 Nachricht | Schlü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 selbst | Hostname oder Compose-Dienstnamen des Ziels eintragen |
HTTP 424 One or more notification could not be sent | Tag passt zu keinem Ziel | Tags per /json/urls/<schlüssel>?privacy=1 prüfen |
Häufige Fragen
Welche Dienste unterstützt Apprise?
Die README listet über 100 Dienste, darunter E-Mail, ntfy, Gotify, Matrix, Telegram, Signal, Teams (Power Automate Workflows) und SMS-Anbieter, mit URL-Syntax je Dienst.
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.
Fazit
Die Apprise API ist ein kleiner Baustein, der Benachrichtigungen aufräumt: Skripte kennen nur eine URL und einen Tag, einen Kanalwechsel erledigen Sie zentral. Seit Version 2.0 gibt es einen eingebauten Login, den Sie selbst einschalten müssen. Skripte sollten den Statuscode auswerten, statt sich auf HTTP 204 zu verlassen.
Weiterführende Anleitungen und Quellen
- ntfy mit Docker installieren: Push-Benachrichtigungen per HTTP selbst hosten
- Gotify mit Docker Compose: Push-Benachrichtigungen selbst hosten
- Caddy als Reverse Proxy mit automatischem HTTPS
- GitHub: caronc/apprise-api mit README, Umgebungsvariablen und API-Referenz
- Offizielles docker-compose.yml der Apprise API
- Apprise API Release v2.0.0 vom 26.09.2026
- Apprise Release v2.0.0 mit Breaking Changes
- GitHub: caronc/apprise mit Liste der unterstützten Dienste
- Docker Hub: caronc/apprise mit Tags und Architekturen
- heise online: Der Universalbote für Admins: Apprise 2.0 (29.09.2026)


