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; anonymouswrite-onlyonup*topics only; admin userhermes) - Compose:
/opt/matrix/docker-compose.ymlservicentfy, volumentfy_data(/data: cache.db + user.db) - Caddy:
/opt/matrix/Caddyfileblockpush.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)
- Install ntfy app from F-Droid.
- 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. - In Element: Settings → Notifications → select UnifiedPush → distributor ntfy.
If it offers a custom push gateway URL, sethttps://push.tinkerpod.org. - Test: send a message to your account from another session/device.
Ops
- Logs:
sudo docker logs matrix-ntfyon 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 --compacton harbor (192.168.194.21); consumer 192.168.194.22:matrix