Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Docker 30.09.2026 · 10 min Lesezeit Wird überarbeitet

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

Titelbild: Apprise API mit Docker Compose, Mail, Push, Chat

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.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 aktuell 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 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 .env

Die fertige .env sieht so aus (Passwort als Platzhalter):

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

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 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: 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 Hash-Namen an.
  • 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. Zur Pflege per Browser lassen Sie 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.

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; 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/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

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-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.

/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-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.

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 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.

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/apprise

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, 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

AppriseDocker ComposeBenachrichtigungenMonitoringntfyGotifySelfhostingBasic Auth