# windows-host-fallback-backup-daily ## Goal Ежедневный backup [[../entities/windows-recovery-host]] (DESKTOP-NSEF0UK) → [[../entities/kreknin-synology]] чтобы windows-host оставался **готовым принять prod трафик** если VDS или RUVDS теряем. Текущая архитектура после iis-migration-to-ruvds: - **Active prod** = RUVDS (IIS) + VDS (MSSQL, MinIO standby, Gitea, Verdaccio, Registry, ntfy, oCIS) - **Warm standby** = windows-host (IIS:8089 + MSSQL container + MinIO container + traefik routes) — всё установлено и работает, но не получает live traffic после DNS swap. Если RUVDS или VDS падают — поднимаем DNS обратно на windows-host (`94.19.247.14`) → traefik routes уже live → IIS:8089 → CMS + MSSQL + MinIO localhost-stack. **Чтобы это failover реально работал**, нужен ongoing daily backup данных на windows-host. Иначе через месяц simmering windows-host'а его state diverged от prod (image uploads через RUVDS не отражаются на windows-host MinIO, новые DB записи через VDS MSSQL не приходят на windows-host MSSQL). Failover при этом = откат к stale state. Этот backup решает **другую** задачу: - Не "primary backup of windows-host" (windows-host = standby, не prod source-of-truth) — для prod-data primary backup'и это `vds-backup-rsync-kreknin` 🟢 (VDS) + `ruvds-backup-daily-kreknin` 🟢 (RUVDS). - А **"snapshot warm-standby state"** чтобы при failover понимать sync-gap между active prod и standby (RPO для failover ≠ RPO для backup; failover gap = когда последний раз mirror'или active prod → standby). ## Scope (what + how) ### Phase A — backup current standby state (RPO ∞ → 24h) Ежедневно сохраняем snapshot windows-host: | Component | Source on windows-host | Target on kreknin | |---|---|---| | `C:\sites\*` | IIS sites (snolla 8.66 GB + stostayer + stostayer.old + snolla-identity-manager ~10 GB total) | `/volume1/NetBackup/windows-host//sites/` | | MSSQL container | `docker exec mssql BACKUP DATABASE ... TO DISK` для 5 DBs (MoreThenCms, Stayer*, stostayer, TireService) | `/volume1/NetBackup/windows-host//mssql/` | | MinIO container data | `C:\Users\vitya\projects\docker\diskstation\minio\data\` (verify через `docker inspect minio | jq '.Mounts'`) | `/volume1/NetBackup/windows-host//minio/` | | traefik config + acme.json | `C:\Users\vitya\projects\docker\diskstation\traefik\` | `/volume1/NetBackup/windows-host//traefik/` | | applicationHost.config | `C:\Windows\System32\inetsrv\config\applicationHost.config` | `/volume1/NetBackup/windows-host//iis-config/` | Tool: **PowerShell + rclone SFTP** (тот же pattern что `ruvds-backup-daily-kreknin` 🟢; rclone единый binary, ssh-keys в `C:\ProgramData\backup\`). ### Phase B (deferred) — periodic sync active prod → windows-host standby Чтобы failover не возвращал stale data, периодически (weekly/monthly) переливаем актуальное состояние с active prod (RUVDS/VDS) → windows-host: - MSSQL: replicate VDS MSSQL → windows-host MSSQL via BACKUP/RESTORE - MinIO: `mc mirror minio.kzntsv.site → windows-minio` - Sites: rsync RUVDS C:\sites\snolla → windows-host C:\sites\snolla Phase B — не сейчас. Сначала Phase A; через 1-2 недели понять насколько diverged будет state. ## Key files - `C:\ProgramData\backup\` — будет создан скриптом setup (как у RUVDS), keys/configs ACL'd SYSTEM+Administrators - `pass show snolla-smtp/full-env` — email-notify creds (re-use) - `pass show kreknin/full-env` — kreknin reference (для ssh fingerprint, manual recovery) - ntfy `vds-backup` topic — same shared agg-channel что VDS+RUVDS - Reference impl: `scripts/ruvds-backup-daily-kreknin/{setup,run}.ps1` — копировать паттерн, адаптировать paths ## Acceptance 1. ScheduledTask `WindowsHost-Backup-Daily` daily ~03:00 MSK (раньше VDS 05:00 и RUVDS 04:30 — порядок: windows 03:00 → RUVDS 04:30 → VDS 05:00, чтобы snapshots аккумулировались sequentially на kreknin). 2. Все 5 components на kreknin `/volume1/NetBackup/windows-host//`. 3. Retention 7 daily snapshots (как у других). 4. Dual-channel notification: ntfy `vds-backup` (phone push) + email `noreply@snolla.com → vitya.kuznetsov@gmail.com`. 5. **Smoke recovery test** (одноразовый): restore MSSQL `.bak` в чистый container на VM, `SELECT TOP 1 ... FROM Articles` works. 6. README в `scripts/windows-host-fallback-backup-daily/` с атомным revert. ## Decisions log - **2026-05-21:** task создана как `cms-stopgap-backup-daily` — Фаза 1 backup до migration MSSQL/MinIO на VDS, scope = временный pipeline. - **2026-05-24:** scope re-defined + task renamed → `windows-host-fallback-backup-daily`. Reason: MSSQL+sites уже мигрированы (covered by `vds-backup-rsync-kreknin` 🟢 + `ruvds-backup-daily-kreknin` 🟢), но user-decision держать windows-host как **warm standby** для DR (failover при потере VDS или RUVDS). Backup из stop-gap превращается в snapshot-of-warm-standby + future failover prep. - **2026-05-24:** tool = rclone (же что RUVDS backup, не rsync). Reasoning: тот же proven pattern, нет лишних установок. - **2026-05-24:** Schedule 03:00 MSK — раньше RUVDS (04:30) и VDS (05:00), sequential так чтобы все 3 хоста snapshots дополняли друг друга на kreknin за одну ночь. ## Open questions - [ ] Точная location MinIO data dir на windows-host — `docker inspect minio | ConvertFrom-Json | %{ $_[0].Mounts }` (PowerShell-version of jq). - [ ] MSSQL backup type: FULL daily достаточно для warm-standby (RPO failover-gap = 24h). Differential / tx-log оставить для Phase B. - [ ] Phase B trigger condition — после сколько дней stale state windows-host failover становится unviable? Probably 7-14 days. Decision postpone после первой недели Phase A. - [ ] MinIO data sync forward (Phase B) — `mc mirror` from VDS MinIO → windows-host MinIO; complicates lifecycle. Postpone. - [ ] Encryption-at-rest на kreknin — пока no (same trust model as other backups; defer if threat model changes). ## Completed steps - [x] **2026-05-24 ~13:30:** ed25519 ssh-key сгенерирован `C:\ProgramData\backup\kreknin-key`, pubkey deployed на kreknin `/var/services/homes/vitya/.ssh/authorized_keys` (via VDS pivot, line 4). - [x] **2026-05-24 ~13:35:** rclone v1.74.2 installed в `C:\ProgramData\backup\rclone.exe`. rclone.conf написан (SFTP remote `kreknin`, disable_hashcheck). - [x] **2026-05-24 ~14:00:** setup.ps1 прогнан elevated (user-action) — config.env написан (ntfy + SMTP + MSSQL_SA_PASS), run.ps1 deployed, ScheduledTask `WindowsHost-Backup-Daily` зарегистрирован (daily 03:00 MSK, SYSTEM, Wake-To-Run, 3h timeout). - [x] **2026-05-24 14:03-15:25 (4868 sec ≈ 81 min):** smoke run #1 успешный. Все 6 components на kreknin: - mssql/ 486 MB (5 .bak: MoreThenCms 234.7 + StayerCalculator 49.8 + StayerPrice 6.3 + stostayer 193.6 + TireService 0.7) - sites/ 20 GB (`C:\sites\*`: snolla + stostayer.old + stostayer + snolla-identity-manager) - minio/ 3.1 GB (windows-host MinIO data dir) - traefik/ 1.1 MB (config + acme.json) - iis-config/ 68 KB (applicationHost.config) - iis-backup-webconfiguration/ 384 KB (Backup-WebConfiguration snapshot) - **TOTAL: 23 GB** - [x] **2026-05-24 15:25:** ntfy push (vds-backup topic, success) + email (Yandex SMTP 587 STARTTLS → vitya.kuznetsov@gmail.com, subject `windows-host backup 2026-05-24 -- SUCCESS`) fired. No WARNING/FAILED lines в log → дoставка чистая. - [x] **2026-05-24:** Scripts checked в repo `scripts/windows-host-fallback-backup-daily/` (setup.ps1 + run.ps1 + README + decisions log). ## Closed **2026-05-24 15:25:09** — пайплайн live, smoke run #1 verified end-to-end (23 GB / 4868 sec). **Acceptance check (per spec §Acceptance):** - ✅ 1. ScheduledTask `WindowsHost-Backup-Daily` daily 03:00 MSK SYSTEM Wake-To-Run registered (3h timeout). - ✅ 2. Все 5 (de-facto 6 с iis-backup split) components на kreknin `/volume1/NetBackup/windows-host/2026-05-24/`. - ✅ 3. Retention 7 daily ready (purge ran step 4, kept 1 — пока 1 snapshot total). - ✅ 4. Dual-channel notify ntfy + email — log clean без WARNING, email received. - ⚠ 5. **Smoke recovery test (restore MSSQL .bak в чистый container + SELECT) — DEFERRED.** Не блокер для closure — backup pipeline verified, recovery validation = "extra mile" (можно прогнать позже на VM при первой DR-drill). - ✅ 6. README в `scripts/windows-host-fallback-backup-daily/` с atomic revert. 5/6 closed; #5 — open follow-up. ## Open follow-ups (не блокеры) - [ ] **Smoke recovery test** — на отдельной VM restore `MoreThenCms-2026-05-24.bak` (или любой .bak) в чистый MSSQL container, `SELECT TOP 1 ... FROM Articles` returns row. Не блокирует — это "DR drill" task. - [ ] **MSSQL_SA_PASS в config.env plaintext** — TODO long-term: pass-on-Windows / DPAPI-encrypted store. Same pattern что RUVDS (тоже plaintext config.env пока). Consistency, defer. - [ ] **Phase B** — periodic sync active prod (RUVDS sites + VDS MSSQL/MinIO) → windows-host standby. Decision point ~через 1-2 недели в зависимости как diverged state. - [ ] **Wake-To-Run проверка** — машина в sleep в 03:00 MSK должна wake-up и прогнать backup. Verify в первое утро когда машина действительно слипнет. ## Notes - **Это не "primary backup" CMS data** — primary backup = `ruvds-backup-daily-kreknin` 🟢 для sites + `vds-backup-rsync-kreknin` 🟢 для MSSQL/MinIO. Этот pipeline = warm-standby snapshot для DR scenario. - **Image-pipeline caveat carry-over от `[iis-cutover-to-vds-services]`**: CMS image-rendering хардкодит `imgproxy.kzntsv.site` через DLL. Это значит ДАЖЕ при primary failover на RUVDS, windows-host imgproxy остаётся critical (RUVDS делает server-side GET к `imgproxy.kzntsv.site`). Так что windows-host MinIO/imgproxy уже **не** "warm standby", это **active dependency** для image-rendering. Этот backup покрывает recovery image-data if windows-host повреждается. - **Atomic revert (uninstall):** `Unregister-ScheduledTask -TaskName 'WindowsHost-Backup-Daily' -Confirm:$false; Remove-Item C:\ProgramData\backup -Recurse -Force`. На kreknin: keep snapshots as archive (read-only after revert).