SecondBrain/reference/apprise-api-selfhosted-gotc...

2.2 KiB

summary tags scope date last_updated
Deployment gotchas for the self-hosted apprise-api Docker container — config-dir ownership (uid 1000 workers), stateful config format, and the tailnet-bind pattern used on ovh-vps.
type/reference
tool/apprise
domain/notifications
global 2026-07-10 2026-07-10

apprise-api self-hosted deployment gotchas

Learned deploying caronc/apprise (apprise-api) via docker compose on ovh-vps (cc-os ADR-024, 2026-07-10).

Config-dir ownership trap

  • docker exec apprise id reports root, but the gunicorn workers actually run as uid 1000 — the container chowns the mounted /config volume to 1000:1000 on first start.
  • A stateful config file owned by another uid with mode 600 produces a misleading 500: django: NOTIFY - I/O error accessing configuration using KEY: <key>. Fix: chown 1000:1000 the {key}.cfg file (keep 600).
  • Corollary: after the container starts, the host user may lose write access to ./config (it was chowned to 1000) — sudo chown back or write files as the right uid.

Stateful config essentials

  • APPRISE_STATEFUL_MODE=simple → config is a plain text file /config/{KEY}.cfg, one target URL per line, optional tag= prefix (pushover=pover://user@token). Untagged lines match notify calls with no tag.
  • APPRISE_CONFIG_LOCK=yes disables config changes via the API — config is file-managed only; notify still works.
  • A long random KEY (openssl rand -hex 16) acts as the only auth token; treat the .cfg filename/key as a secret.
  • Notify: POST /notify/{key} form-encoded body + title (+ optional tag, type) → 200 on delivery.

Network pattern (no auth built in)

apprise-api has no authentication — don't expose it publicly bare. Pattern used: bind the container port to the tailscale IP + localhost only (100.100.43.95:8901:8000, 127.0.0.1:8901:8000), so every tailnet machine can notify with no public exposure, no DNS, no reverse proxy. Server env (base URL + key) lives in ~/services/apprise/apprise.env (600) on ovh-vps.

Related: vault-backlog-pilot-plan (ADR-024 context); Ruby client gem apprise-client at ~/dev/ruby-gems/apprise.