# vds-backup-rsync-kreknin ## Goal Ежедневный rsync-бэкап важных директорий с VDS (`89.253.255.94 / vds.kzntsv.site`) → [[kreknin-synology]] (`195.19.90.188 / kreknin.site`) в 05:00 MSK. После каждого прохода — email-нотификация на `vitya.kuznetsov@gmail.com` со статусом (success/fail + transferred bytes + duration). ## 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://`. ## Implementation sketch `/etc/cron.d/vds-backup`: ```cron # 05:00 MSK ежедневно 0 5 * * * vitya /opt/stacks/backup/scripts/run.sh ``` `/opt/stacks/backup/scripts/run.sh`: ```bash #!/bin/bash set -e SOURCE_DIRS=(/opt/stacks/gitea/data /opt/stacks/verdaccio/storage /opt/stacks/verdaccio/config /opt/stacks/registry/docker /opt/stacks/registry/auth /opt/stacks/traefik /opt/stacks/portainer/data /etc/ssh /etc/ufw /etc/hosts /etc/docker /etc/letsencrypt) DEST_BASE=/volume1/NetBackup/vds-kzntsv TODAY=$(date +%Y-%m-%d) LATEST=$DEST_BASE/latest START_TIME=$(date +%s) LOG=/tmp/backup-$TODAY.log # DB dumps первым шагом — pg/maria/mongo в /tmp/db-dumps/$TODAY/, потом включаются в rsync mkdir -p /tmp/db-dumps/$TODAY docker exec postgres pg_dumpall -U postgres > /tmp/db-dumps/$TODAY/postgres.sql docker exec mariadb mariadb-dump --all-databases -u root -p"$MARIA_PASS" > /tmp/db-dumps/$TODAY/mariadb.sql docker exec mongo mongodump --out=/tmp/mongo --uri="mongodb://root:$MONGO_PASS@localhost:27017?tls=true&tlsAllowInvalidCertificates=true" docker exec redis redis-cli --tls --insecure -a "$REDIS_PASS" --rdb /data/dump.rdb # rsync с --link-dest для hardlink-incremental rsync -azh --link-dest=$LATEST "${SOURCE_DIRS[@]}" /tmp/db-dumps/$TODAY \ -e "ssh -i ~/.ssh/id_ed25519_kreknin" \ vitya@195.19.90.188:$DEST_BASE/$TODAY/ ssh -i ~/.ssh/id_ed25519_kreknin vitya@195.19.90.188 \ "rm -f $LATEST && ln -sf $DEST_BASE/$TODAY $LATEST" END_TIME=$(date +%s) DURATION=$((END_TIME - START_TIME)) SIZE=$(du -sh $DEST_BASE/$TODAY 2>/dev/null | cut -f1) # Email via msmtp echo "Subject: VDS backup $TODAY — SUCCESS Size: $SIZE, duration: ${DURATION}s Source: vds.kzntsv.site Dest: kreknin.site:$DEST_BASE/$TODAY/ " | msmtp vitya.kuznetsov@gmail.com ``` (скетч; добавить retention prune — `find $DEST_BASE -maxdepth 1 -type d -name "20*" | sort | head -n -7 | xargs rm -rf`, error trap, etc.) ## Decisions log - _Пусто — задача только заведена._ ## 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 пропустить.