Files
admin/.tasks/vds-ntfy-push.md
vitya c55cb11948 tasks: merge imported MoreThenCms task history with admin live agenda
- 7 admin per-task files moved from .tasks-imported/ to .tasks/ (renames)
- NEXT-SESSION-PROMPT.md (iis-migration session handoff) kept as sibling
- .tasks-imported/STATUS.md removed (content merged into admin STATUS.md)
- admin STATUS.md gains 'Imported from MoreThenCms' section with all 7 admin
  done tasks verbatim. 4 CMS-domain task blocks excluded (stay in MoreThenCms):
  cms-admin-assets-root-folders-seed, cms-port-leak-fix,
  traefik-maljarka-502-bug, cms-maljarka-https-mode-bug-fix
- morecms-subtree-split marked done (acceptance: 4 split branches exist with
  per-file history)
- admin-subtree-import-and-cleanup marked active (in-progress this session)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 13:51:48 +03:00

100 lines
6.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# vds-ntfy-push
## Goal
Self-host [ntfy.sh](https://ntfy.sh) на VDS для push-нотификаций на телефон. Docker-image `binwiederhier/ntfy`. Использовать для:
- [[vds-backup-rsync-kreknin]] backup status (вместо/параллельно email на vitya.kuznetsov@gmail.com)
- Monitoring alerts (CMS down, traefik certs истекают, disk fill, registry GC fail, etc.)
- Любые ad-hoc уведомления от ops-скриптов
Domain: `ntfy.vds.kzntsv.site` (под уже существующим wildcard `*.vds.kzntsv.site`).
## Open questions
- [x] ~~**Auth model:**~~ per-topic ACL + admin user `vitya` (resolved 2026-05-20). Реализация: `NTFY_AUTH_DEFAULT_ACCESS=deny-all` + `ntfy user add --role=admin vitya`. Admin role → rw to all topics, per-topic ACL не нужен. Anon (no creds) → 403 на publish и subscribe ✅.
- [x] ~~**Топики:**~~ начали с двух: `vds-backup` (для vds-backup-rsync-kreknin) + `vds-ops` (general alerts: cert expiry, disk fill, container crashes). Можно добавлять без миграции — admin role даёт доступ ко всему автоматом.
- [x] ~~**Phone app:**~~ Android (resolved 2026-05-20) → ntfy Android app, pure self-host без APNs middleware.
- [x] ~~**Persistence:**~~ sqlite в `/opt/stacks/ntfy/data/` (cache.db + auth.db). Volume mount `./data:/var/cache/ntfy`.
- [x] ~~**Phone-side smoke:**~~ confirmed 2026-05-20 22:54 MSK — оба push'а («Topic renamed», «Password updated») пришли в Android ntfy app, screenshot в conversation.
## Implementation sketch
`/opt/stacks/ntfy/docker-compose.yml`:
```yaml
services:
ntfy:
image: binwiederhier/ntfy
container_name: ntfy
restart: unless-stopped
command:
- serve
networks:
- proxy
volumes:
- ./data:/var/cache/ntfy
- ./etc:/etc/ntfy
environment:
NTFY_BASE_URL: https://ntfy.vds.kzntsv.site
NTFY_CACHE_FILE: /var/cache/ntfy/cache.db
NTFY_AUTH_FILE: /var/cache/ntfy/auth.db
NTFY_AUTH_DEFAULT_ACCESS: deny-all
NTFY_BEHIND_PROXY: true
NTFY_ATTACHMENT_CACHE_DIR: /var/cache/ntfy/attachments
labels:
- traefik.enable=true
- traefik.http.routers.ntfy.rule=Host(`ntfy.vds.kzntsv.site`)
- traefik.http.routers.ntfy.entrypoints=websecure
- traefik.http.routers.ntfy.tls.certresolver=letsEncrypt
- traefik.http.services.ntfy.loadbalancer.server.port=80
networks:
proxy:
external: true
```
После up — `docker exec ntfy ntfy user add --role=admin vitya` → задать пароль → грант access на топики.
Publish from any script:
```bash
curl -u "vitya:$NTFY_PASS" \
-H "Title: VDS backup completed" \
-H "Tags: white_check_mark" \
-H "Priority: default" \
-d "Size 12.5G, 18m12s, kreknin OK" \
https://ntfy.vds.kzntsv.site/vds-backup
```
Phone subscribes to `https://ntfy.vds.kzntsv.site/vds-backup` (с basic auth) — получает уведомление.
## Decisions log
- **2026-05-20** — Image pinned `binwiederhier/ntfy:v2.11.0` (conservative, matches pin policy остальных стэков: traefik v2.11, portainer 2.21.5).
- **2026-05-20** — Auth: `NTFY_AUTH_DEFAULT_ACCESS=deny-all` + admin user `vitya` (random hex16 password). Admin role гранит rw ко всем топикам автоматом — per-topic `ntfy access` calls returned `user vitya is an admin user, access control entries have no effect`. Не нужны явные grants; разлогиниться от admin позже если будет потребность в ограниченных read-only users.
- **2026-05-20** — Topics: `vds-backup` + `vds-ops` (минимум для текущих нужд). Расширение бесплатное (admin → rw to all).
- **2026-05-20** — TLS через traefik LE http-01 (issuer R12, valid Aug 18 2026); ntfy listens HTTP `:80` внутри `proxy` network, `NTFY_BEHIND_PROXY=true` чтобы trust X-Forwarded-* от traefik.
- **2026-05-20** — Smoke green: anon publish/subscribe → 403, authed publish vds-backup+vds-ops → 200 с JSON id/ts.
- **2026-05-20** — User feedback: random hex password неудобен для ввода в phone app. Меняю на `Pryakhin9` (consistency с TRAEFIK_DASHBOARD_PASS). Trade-off: меньше entropy, но scope ограничен (admin role, single user, push-сервис без чувствительных данных, can rotate если threat model изменится). Lesson — для human-input creds (phone/web UI) использовать память user'а, не random hex; random hex оставить для script-only (DB, API keys).
- **2026-05-20** — Topics renamed `backup``vds-backup`, `ops``vds-ops` (consistency с VDS scope, упрощает filtering если позже добавятся nas-* или kreknin-* топики).
- **2026-05-20** — Phone-verified: Android ntfy app subscription → оба push'а пришли в течение секунд. End-to-end complete.
## Completed steps
- [x] `/opt/stacks/ntfy/{data}` создано (owner vitya:vitya)
- [x] `docker-compose.yml` написан с traefik labels (Host, websecure, letsEncrypt, port 80)
- [x] `docker compose up -d` → container healthy, listening :80
- [x] Admin user `vitya` добавлен через `printf "%s\n%s\n" "$PASS" "$PASS" | docker exec -i ntfy ntfy user add --role=admin vitya`
- [x] LE cert issued via http-01, R12, valid 2026-05-20 → 2026-08-18
- [x] Smoke test (publish/subscribe/anon-deny) green
- [x] Creds saved: `/opt/stacks/ntfy/.env` (chmod 600) + Windows `~/projects/.common/secrets/vds-kzntsv.env`
- [x] Password rotated random-hex → `Pryakhin9` per user request (ntfy user change-pass)
- [x] Topics renamed `backup`/`ops``vds-backup`/`vds-ops`
- [x] Phone-verified (Android ntfy app, screenshot 22:54 MSK)
## Notes
- Триггер: после `[[vds-kzntsv-bootstrap]]` Phase 3 и до или одновременно с `[[vds-backup-rsync-kreknin]]` (backup pipeline хочет ntfy для статус-уведомлений).
- Интегрируется с `[[vds-backup-rsync-kreknin]]` — backup script публикует через ntfy + дублируется email'ом для надёжности.
- **Android setup hint:** ntfy app → Add subscription → Topic `vds-backup` (или `vds-ops`) → Server `https://ntfy.vds.kzntsv.site` → enable «Use auth» → user `vitya` / password из vds-kzntsv.env.
- Cert renewal — automatic via traefik (letsEncrypt resolver), нет дополнительных шагов.