Self-hosted UnifiedPush push gateway (ntfy) - push.tinkerpod.org

Self-hosted UnifiedPush push gateway (ntfy) — push.tinkerpod.org

Deployed 2026-11-08 on the matrix VM (192.168.194.22), image pulled from Harbor
approved project (supply-chain scanned, digest-pinned):

192.168.194.21/approved/ntfy@sha256:e5d978c57b5a6a1095c8a74fd1cfe846dabef14369f2ff7a0d16456e727d40ec
(upstream docker.io/binwiederhier/ntfy, tracked moving tag v2.37)

Architecture

Element (Android) --UnifiedPush--> ntfy app (distributor, token auth)
Synapse --POST /_matrix/push/v1/notify--> Caddy --> matrix-ntfy --> up* topic --> ntfy app --> Element
  • Public endpoint: https://push.tinkerpod.org (DNS A → 212.57.57.19, same IP as matrix.tinkerpod.org)
  • Gateway discovery: GET /_matrix/push/v1/notify → {"unifiedpush":{"gateway":"matrix"}} (answered by Caddy)
  • Config: /opt/matrix/ntfy/server.yml (auth: deny-all default; anonymous write-only on up* topics only; admin user hermes)
  • Compose: /opt/matrix/docker-compose.yml service ntfy, volume ntfy_data (/data: cache.db + user.db)
  • Caddy: /opt/matrix/Caddyfile block push.tinkerpod.org
  • Backups: docker-compose.yml.bak-20261108-ntfy, Caddyfile.bak-20261108-push

Security posture (Harbor pipeline scan, digest e5d978c57)

5/5 scanners ran. Trivy: 1 High (CVE-2026-78661, The Go Programming Language html DoS, fix 0.62.0 pending upstream),
2 Medium (zlib base image, x/net), 1 Unknown (x/crypto openpgp, unused by ntfy). malcontent/clamav/semgrep/gitleaks: clean.
Verdict REVIEW → auto-promoted. Tag v2.37 is tracked, so the fix rebuild auto-promotes when upstream ships it.

Access control verified 2026-11-08

  • anonymous publish to up* topic: HTTP 200 (needed — Synapse writes without credentials)
  • anonymous publish to any other topic: HTTP 403
  • anonymous subscribe to up*: HTTP 403 (write-only; distributor uses token)
  • admin token subscribe to up*: HTTP 200 and receives the Matrix gateway payload
  • POST /_matrix/push/v1/notify with proper Matrix JSON: HTTP 200 {"rejected":[]}

Phone setup (Element X / Element Android)

  1. Install ntfy app from F-Droid.
  2. Settings → Server: https://push.tinkerpod.org; log in with the distributor token
    (KeePass entry /MultiVAC/Matrix/ntfy admin, notes field). Exempt the app from battery optimization.
  3. In Element: Settings → Notifications → select UnifiedPush → distributor ntfy.
    If it offers a custom push gateway URL, set https://push.tinkerpod.org.
  4. Test: send a message to your account from another session/device.

Ops

  • Logs: sudo docker logs matrix-ntfy on 192.168.194.22
  • Health: curl -sk https://push.tinkerpod.org/v1/health
  • Restart: cd /opt/matrix && sudo docker-compose up -d ntfy
  • Users/tokens: sudo docker exec matrix-ntfy ntfy token list hermes --config /etc/ntfy/server.yml
  • NetBox: service “ntfy UnifiedPush gateway” on VM matrix (id 1), IP 212.57.57.19/30 description updated
  • Pipeline: supplyctl status ntfy --compact on harbor (192.168.194.21); consumer 192.168.194.22:matrix