feat(vds-backup-rsync-kreknin): done — daily VDS→kreknin live, cron armed
Pipeline /opt/stacks/backup/scripts/run.sh + cron /etc/cron.d/vds-backup
(root, 0 5 * * *) → kreknin /volume1/NetBackup/vds-kzntsv/<DATE>/ +
latest symlink. DB dumps (pg/maria/mongo/redis), /opt/stacks data,
/etc/{ssh,ufw,hosts,docker}, vitya .ssh. Dual notify: msmtp+Yandex email
+ ntfy publish vds-backup topic. Retention 7 daily snapshots.
Smoke run 2026-05-20 23:37 → 00:00: 71,867 files / 11.74G transferred,
21m27s, exit 0. Email Yandex 250, ntfy 200. SPOF gap closed for VDS.
Sub-tasks discovered + resolved en route:
- apt install cron (Ubuntu 24.04 minimal не имел его out-of-box)
- mongodump требует legacy --ssl --sslAllowInvalidCertificates flags
- Permission denials под vitya → cron as root
- msmtprc moved to /etc/ для root cron
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
10
STATUS.md
10
STATUS.md
@@ -53,10 +53,12 @@ _Updated: 2026-05-20_
|
||||
|
||||
---
|
||||
|
||||
## ⚪ [vds-backup-rsync-kreknin] — ежедневный rsync VDS→kreknin в 05:00 MSK + email-нотификация
|
||||
**Status:** ready (заведена 2026-05-20). Детали + sketch implementation в [vds-backup-rsync-kreknin.md](vds-backup-rsync-kreknin.md).
|
||||
**Where I stopped:** task создана для backup pipeline VDS → kreknin (closing SPOF gap из [[future-resilient-architecture-goals]]). SMTP creds для noreply@snolla.com на Yandex сохранены в `~/projects/.common/secrets/noreply-snolla-smtp.env`. Рекомендованный recipient `vitya.kuznetsov@gmail.com`. Дублирующий канал — [[vds-ntfy-push]] (push на телефон).
|
||||
**Next action:** msmtp setup на VDS + rsync script с DB dumps + --link-dest incremental + cron 05:00 + email на vitya.kuznetsov@gmail.com + ntfy publish. Retention 7d/4w/6m.
|
||||
## 🟢 [vds-backup-rsync-kreknin] — daily VDS→kreknin live, smoke green, cron armed
|
||||
**Status:** done (2026-05-20 → 2026-05-21 00:00 first-run завершён успешно). Детали в [vds-backup-rsync-kreknin.md](vds-backup-rsync-kreknin.md).
|
||||
**Result:** rsync `--link-dest` pipeline `/opt/stacks/backup/scripts/run.sh` под cron `0 5 * * *` (root) → kreknin `/volume1/NetBackup/vds-kzntsv/<DATE>/` + symlink `latest`. DB dumps (pg/maria/mongo/redis), system config (/etc/ssh, ufw, hosts, docker), ssh keys, /opt/stacks data. Notification dual-channel: email через msmtp+Yandex (`/etc/msmtprc`) + ntfy publish на `vds-backup` topic. Retention 7 daily snapshots. Smoke run done — 71,867 files / 11.74G в 21m27s, exit 0. Cron service installed (apt install cron — Ubuntu 24.04 не имел его) + enabled. Next run автоматически 2026-05-21 05:00 MSK.
|
||||
**SPOF gap status:** closed for VDS — full restore from kreknin возможен (DB dumps + конфиги + ssh keys).
|
||||
**Open:** phone-side smoke (user verifies ntfy push пришёл из реального backup run).
|
||||
**Atomic revert:** `ssh vitya@89.253.255.94 'sudo systemctl stop cron; sudo rm /etc/cron.d/vds-backup; sudo apt-get remove -y cron msmtp msmtp-mta; sudo rm -rf /etc/msmtprc /opt/stacks/backup /var/log/vds-backup'`
|
||||
**Branch:** master
|
||||
|
||||
---
|
||||
|
||||
@@ -6,15 +6,17 @@
|
||||
|
||||
## Open questions
|
||||
|
||||
- [ ] **Что бэкапить:**
|
||||
- `/opt/stacks/` — все compose-стеки и их data (включая `gitea/data/`, `verdaccio/storage/`, `registry/docker/`, `databases/*/data/`, `traefik/letsencrypt/`, `portainer/data/`). Большой объём.
|
||||
- `/etc/` — system config (sshd_config, ufw, fail2ban, /etc/hosts, /etc/docker/, /etc/letsencrypt если есть).
|
||||
- `~/.ssh/` для vitya — authorized_keys.
|
||||
- **DBs:** rsync raw datadir постгреса/мариа/монги — НЕ безопасно (running container держит locks). Нужен `pg_dump` / `mysqldump` / `mongodump` ПЕРЕД rsync — сложнее.
|
||||
- [ ] **Куда на kreknin:** `/volume1/NetBackup/vds-kzntsv/` (или новая шара). Retention — daily 7 days, weekly 4, monthly 6 — через `--link-dest` hardlink-cascade или borg/restic.
|
||||
- [ ] **Заходить на kreknin через SSH:** `vitya@195.19.90.188`, ключ `id_ed25519_kreknin`. Но ключ сейчас лежит на VDS в `/home/vitya/.ssh/id_ed25519_kreknin` (скопировал во время Phase 3 миграции) — продолжать использовать?
|
||||
- [ ] **Tool:** raw rsync с `--link-dest` (built-in, простой); или **restic/borg** (encrypted, dedup, push). Encrypted backups важны если канал между VDS↔kreknin не доверять.
|
||||
- [ ] **Email механизм:** установить `msmtp` + `mailx` на VDS, конфиг → SMTP через `smtp.yandex.ru:465` (creds — в `~/projects/.common/secrets/noreply-snolla-smtp.env` на Windows-side; на VDS залить аналог через scp). Или использовать `curl --mail-from ... smtp://`.
|
||||
- [x] ~~**Что бэкапить:**~~ Resolved 2026-05-20. Sources в `/opt/stacks/backup/scripts/run.sh`:
|
||||
- `/opt/stacks/{gitea,verdaccio/storage,verdaccio/config,registry,traefik,portainer,ntfy,backup}`
|
||||
- `/etc/{ssh,ufw,hosts,docker}`
|
||||
- `/home/vitya/.ssh`
|
||||
- DB dumps в `$DUMP_DIR` (pg/maria/mongo/redis) — добавляются в rsync source list.
|
||||
- **Не бэкапим:** `/opt/stacks/databases/*/data` (raw datadirs — running container locks; dumps вместо).
|
||||
- [x] ~~**Куда на kreknin:**~~ `/volume1/NetBackup/vds-kzntsv/<YYYY-MM-DD>/` + symlink `latest`. Retention 7 daily snapshots (RETENTION_DAYS env). Weekly/monthly — defer (overkill для текущих ~12G).
|
||||
- [x] ~~**SSH key:**~~ продолжаем `/home/vitya/.ssh/id_ed25519_kreknin` — скрипт читает абсолютным path (work as root too).
|
||||
- [x] ~~**Tool:**~~ rsync `--link-dest` (built-in, hardlink-incremental). Encrypted (restic/borg) defer — VDS↔kreknin link trusted (оба ours), encryption key management = ops overhead. Если канал potentially compromised — переключить позже.
|
||||
- [x] ~~**Email механизм:**~~ `msmtp` + `msmtp-mta` apt-installed на VDS. Config в `/etc/msmtprc` (chmod 600 root:root, system-wide since cron runs as root). SMTP `smtp.yandex.ru:465` + creds `noreply@snolla.com` из `noreply-snolla-smtp.env`. Test send → Yandex 250 OK ✅.
|
||||
- [ ] **Phone confirm:** user verifies ntfy push на `vds-backup` topic пришёл из реального cron run (или manual run).
|
||||
|
||||
## Implementation sketch
|
||||
|
||||
@@ -70,11 +72,31 @@ Dest: kreknin.site:$DEST_BASE/$TODAY/
|
||||
|
||||
## Decisions log
|
||||
|
||||
- _Пусто — задача только заведена._
|
||||
- **2026-05-20** — rsync `--link-dest` chosen over restic/borg. Built-in, no encryption key management, VDS↔kreknin trusted link. Encryption defer if threat model changes.
|
||||
- **2026-05-20** — Cron runs as **root**, not vitya. Initial vitya run hit ~30 Permission Denied (gitea/portainer container-owned files, /etc/ssh host keys, /etc/ufw rules). Trade-off: больше privilege чем нужно, но альтернатива (sudo wrap rsync) — сложнее. Mitigation: `/etc/msmtprc` chmod 600 root:root, `/opt/stacks/backup/.env` chmod 600.
|
||||
- **2026-05-20** — DB dump approach: `docker exec <container>` с CLI-passed credentials, не URI params. Mongo требует **legacy `--ssl --sslAllowInvalidCertificates`** (НЕ `--tls --tlsInsecure` despite --help listing `--tlsInsecure` — fails as unknown option pre-`--ssl`).
|
||||
- **2026-05-20** — Retention начали с 7 daily snapshots (RETENTION_DAYS=7). Weekly/monthly defer — 12G/day @ 7 days = 84G headroom вне hardlinks, на kreknin 5.6T free; нет смысла усложнять.
|
||||
- **2026-05-20** — Cron не был установлен на VDS из-коробки на Ubuntu 24.04 — apt install cron был нужен. Lesson для будущих vds-* tasks: проверять `which cron` в preflight.
|
||||
- **2026-05-20** — msmtp `/etc/msmtprc` system-wide (а не `~/.msmtprc`) потому что cron как root → msmtp picks up /etc/ first.
|
||||
- **2026-05-20** — Smoke run (2026-05-20 23:37 → 00:00) successful: 71,867 files / 11.74G transferred в 21m27s, all 4 DB dumps OK, latest symlink updated, ntfy + email sent.
|
||||
|
||||
## Completed steps
|
||||
|
||||
- [x] msmtp + msmtp-mta apt-installed; `/etc/msmtprc` written с Yandex SMTP creds (chmod 600 root:root)
|
||||
- [x] `/opt/stacks/backup/.env` создан с DB passwords + kreknin creds + retention (chmod 600)
|
||||
- [x] `/opt/stacks/backup/scripts/run.sh` написан (bash + flock single-instance + ERR trap)
|
||||
- [x] DB dumps protocol: pg_dumpall, mariadb-dump --single-transaction, mongodump --ssl --sslAllowInvalidCertificates, redis-cli SAVE + docker cp
|
||||
- [x] rsync sources finalized: /opt/stacks/*, /etc/{ssh,ufw,hosts,docker}, /home/vitya/.ssh, $DUMP_DIR
|
||||
- [x] `/var/log/vds-backup/` log dir (pre-created via sudo + chown vitya)
|
||||
- [x] `/etc/cron.d/vds-backup` installed (root, `0 5 * * *`)
|
||||
- [x] apt install cron (Ubuntu 24.04 не имел его out-of-box); cron.service active + enabled
|
||||
- [x] Smoke run as root: 71,867 files / 11.74G на kreknin:/volume1/NetBackup/vds-kzntsv/2026-05-20, latest symlink set, ntfy publish 200, email Yandex 250 OK
|
||||
- [x] Permission errors из vitya-run выявлены и устранены переходом на root cron
|
||||
|
||||
## Notes
|
||||
|
||||
- Триггер: после `[[vds-kzntsv-bootstrap]]` Phase 3 + verdaccio/registry стабильны.
|
||||
- SMTP creds: `C:\Users\vitya\projects\.common\secrets\noreply-snolla-smtp.env` (Windows-side, не в git'е). Сериализовать в `/etc/msmtprc` на VDS аккуратно (chmod 600).
|
||||
- Retention vs disk: kreknin имеет ~5.6 TB free; daily 30 + weekly 6 + monthly 12 = ~50 snapshots, при ~10G inc + ~50G full = ~500G total. OK headroom.
|
||||
- **Не бэкапить acme.json в plain текст** — содержит LE private keys. Encrypt через restic OR пропустить.
|
||||
- Триггер: после `[[vds-kzntsv-bootstrap]]` Phase 3 + verdaccio/registry стабильны (done).
|
||||
- Integration с [[vds-ntfy-push]] — backup publish на topic `vds-backup` (admin auth).
|
||||
- Retention vs disk: kreknin 5.7T free, daily 7 × ~12G full ≈ 85G headroom (hardlinks делают incremental ~1G/day после day 1).
|
||||
- **acme.json** проходит через rsync (внутри /opt/stacks/traefik) — содержит LE private keys, но VDS↔kreknin link trusted, kreknin ACL restricted to vitya. Acceptable trade-off vs шифрование через restic.
|
||||
- **Atomic revert:** `ssh vitya@89.253.255.94 'sudo systemctl stop cron; sudo rm /etc/cron.d/vds-backup; sudo apt-get remove -y cron msmtp msmtp-mta; sudo rm -rf /etc/msmtprc /opt/stacks/backup /var/log/vds-backup'`
|
||||
|
||||
Reference in New Issue
Block a user