Files
admin/scripts/windows-host-fallback-backup-daily
vitya 73ad6dd06a scripts(backup-notifications): unify push + email format across VDS/RUVDS/windows-host
3 host-pipelines (VDS bash, RUVDS+windows-host ps1) had drifted formats:
ntfy title `VDS backup OK $D` vs `RUVDS backup OK ($D)`, tags
`white_check_mark` vs `green_circle`, email subject `[VDS] backup OK` vs
`RUVDS backup -- SUCCESS`. Phone-side фильтрация и desktop reading
ломались за счёт inconsistency.

Unified to:
- ntfy push: title `<HOST> backup OK <date>`, body
  `<duration_human>, size=<>, snapshots=<>, dest=kreknin:<>`,
  tags `green_circle` (OK) / `red_circle` (FAILED).
- email: subject `[<HOST>] backup <STATUS> <date>` (STATUS=OK|FAILED),
  body — structured Date/Duration/Size/Snapshots/Source/Dest/Components/Log.
  Failure body extends with `Tail (last 40 lines)`.

Also imports VDS `run.sh` into repo as `scripts/vds-backup-rsync-kreknin/`
— closes drift из общего `scripts/<slug>/` pattern (RUVDS+windows-host
уже жили там; VDS жил только на /opt/stacks/backup/scripts/).

Deploy status:
- VDS: deployed via scp + sudo install, sha256=27b09ca272bb, smoke ntfy+email ✓
- RUVDS: deployed via scp + Move-Item, sha256=f3bb57a86af5, smoke ntfy+email ✓
- windows-host: deploy.ps1 + smoke-notify.ps1 готовы в scripts/, **pending
  elevated PS у user'а** (ACL=SYSTEM+Administrators, не пишется без UAC).

Spec + decisions + completed: .tasks/unify-backup-notifications.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 07:19:15 +03:00
..

windows-host-fallback-backup-daily — scripts

Daily backup windows-host (DESKTOP-NSEF0UK) → kreknin Synology (/volume1/NetBackup/windows-host/<date>/) via rclone SFTP.

Purpose: держать windows-host warm-standby state свежим для DR failover (см. .tasks/windows-host-fallback-backup-daily.md §Goal).

Schedule: daily 03:00 MSK (раньше RUVDS 04:30 + VDS 05:00 — sequential snapshots). Task name: WindowsHost-Backup-Daily. Wake-To-Run enabled чтобы машина просыпалась на backup даже в sleep state.

Files

  • setup.ps1 — one-time install: SSH key, rclone (в C:\ProgramData\backup\rclone.exe), configs, ScheduledTask. Требует elevated PowerShell (для ScheduledTask SYSTEM + icacls). Параметры -SmtpPass <yandex-pass> + -MssqlSaPass <mssql-sa-pass>.
  • run.ps1 — backup logic (deployed by setup.ps1 to C:\ProgramData\backup\run.ps1). rclone берёт из $base\rclone.exe, ssh key из $base\kreknin-key.

What's backed up (5 components)

Component Source on windows-host Remote path on kreknin
MSSQL container docker exec BACKUP DATABASE × 5 DBs → docker cp → sync NetBackup/windows-host/<date>/mssql/
Sites C:\sites\ (snolla 8.66 GB + stostayer + .old + identity-manager) NetBackup/windows-host/<date>/sites/
MinIO data C:\Users\vitya\projects\docker\diskstation\minio\data\ NetBackup/windows-host/<date>/minio/
Traefik C:\Users\vitya\projects\docker\diskstation\traefik\ (config + acme.json) NetBackup/windows-host/<date>/traefik/
IIS config applicationHost.config + Backup-WebConfiguration snapshot NetBackup/windows-host/<date>/iis-config/ + iis-backup-webconfiguration/

MSSQL DBs: MoreThenCms, StayerCalculator, StayerPrice, stostayer, TireService. Backup type: FULL daily, WITH COMPRESSION, INIT. Backups создаются внутри контейнера в /var/opt/mssql/backup/, потом docker cp на host в temp dir, потом rclone sync.

Retention: 7 daily snapshots, prune step 4.

Notifications

Dual-channel (oба после каждого run):

  • ntfy topic vds-backup (shared с VDS+RUVDS backups) — phone push через ntfy mobile app
  • Email via Yandex SMTP 587 STARTTLS — noreply@snolla.comvitya.kuznetsov@gmail.com

Subject formatting: windows-host backup <date> -- SUCCESS / FAILED.

Notify-functions wrapped в try/catch — backup itself не fail'ит при notify сбое.

Initial install

# На windows-host, PowerShell as Administrator
# (этот repo уже здесь)
cd C:\Users\vitya\projects\.admin\scripts\windows-host-fallback-backup-daily

# Pull SMTP + SA creds из pass (или передать вручную)
$smtpPass = bash -lc 'pass show snolla-smtp/full-env' | Select-String 'SMTP_PASS=' | %{ ($_ -split '=', 2)[1] }
$saPass   = docker inspect mssql --format '{{range .Config.Env}}{{println .}}{{end}}' | Select-String '^MSSQL_SA_PASSWORD=' | %{ ($_ -split '=', 2)[1] }

.\setup.ps1 -SmtpPass $smtpPass -MssqlSaPass $saPass

Между шагом 1 и 6 setup паузится — нужно добавить kreknin-key.pub в /var/services/homes/vitya/.ssh/authorized_keys на kreknin (через File Station UI, SSH, или VDS pivot if local SSH к kreknin не setup):

# VDS pivot (если нет direct SSH с этой машины к kreknin):
PUBKEY='<paste content of C:\ProgramData\backup\kreknin-key.pub>'
ssh vitya@89.253.255.94 "ssh -i ~/.ssh/id_ed25519_kreknin vitya@195.19.90.188 'echo \"$PUBKEY\" >> ~/.ssh/authorized_keys'"

После этого Enter в setup.ps1 → продолжается.

Manual smoke run

Start-ScheduledTask -TaskName 'WindowsHost-Backup-Daily'
Get-Content "C:\ProgramData\backup\logs\$(Get-Date -Format yyyy-MM-dd).log" -Wait

Verify on kreknin (via VDS pivot):

ssh vitya@89.253.255.94 'ssh -i ~/.ssh/id_ed25519_kreknin vitya@195.19.90.188 "ls -la /volume1/NetBackup/windows-host/$(date +%Y-%m-%d)/; du -sh /volume1/NetBackup/windows-host/$(date +%Y-%m-%d)/*"'

Decisions log

  • rclone, not rsync — нет cygwin/WSL зависимости, single .exe. Same pattern что VDS msmtp/rsync, RUVDS rclone — proven.
  • Wake-To-Run-WakeToRun flag на ScheduledTask. windows-host может быть в sleep когда RUVDS уже принимает live traffic; backup всё равно поднимет машину в 03:00 MSK. Critical для warm-standby use-case.
  • MSSQL backup via docker execsqlcmd -C (trust cert; sqlcmd 18 enforces TLS даже на localhost) с BACKUP DATABASE WITH COMPRESSION, INIT, FORMAT для consistency. Backup .bak пишется в volume mssql_mssql_data (/var/opt/mssql/backup/), затем docker cp на host temp dir → rclone sync → cleanup container .bak.
  • MinIO data bind-mount pathC:\Users\vitya\projects\docker\diskstation\minio\data (verified via docker inspect minio). Backup читает напрямую с file system, без MinIO API calls — proven safe для standby (no live mutations).
  • MSSQL_SA_PASS в config.env, не в pass — windows-host не имеет pass-store setup. ACL config.env = SYSTEM + Administrators only. TODO: setup pass на windows-host для DPAPI-equivalent (long-term).
  • Schedule 03:00 MSK — sequential с RUVDS (04:30) + VDS (05:00). Все 3 backups на kreknin аккумулируются за одну ночь.

Atomic revert (uninstall)

# На windows-host:
Unregister-ScheduledTask -TaskName 'WindowsHost-Backup-Daily' -Confirm:$false
Remove-Item C:\ProgramData\backup -Recurse -Force
# Optionally: Remove-Item 'C:\Program Files\rclone' -Recurse -Force

# На kreknin (via VDS pivot):
ssh vitya@89.253.255.94 'ssh -i ~/.ssh/id_ed25519_kreknin vitya@195.19.90.188 "rm -rf /volume1/NetBackup/windows-host"'
# Удалить windows-host pubkey-line (с `windows-host-backup` comment) из ~/.ssh/authorized_keys на kreknin.