15-hour cross-hypervisor recovery from WD40EFAX SMR RAID5 cascade failure. 5 entities + 7 concepts + 1 source documenting: - Root cause: WD40EFAX SMR cascade in 3-disk RAID 5 - Hyper Backup .hbk structure + SFTP-jail / ACL workarounds - OVA from Synology VMM (KVM) → VirtualBox: SCSI→SATA, Hyper-V driver disable, paravirt=kvm, GA install, NAT switch - MSSQL restore via named volume + chown, sqlcmd -x, mssql-conf - Web.config UTF-16 vs UTF-8 BOM IIS 500.19 trap - Traefik on Windows DD: configFile, named volume for acme.json, file-provider as docker.sock workaround - Snapshot of current recovery architecture + SPOF list - Placeholder for future resilient-architecture work Plus .tasks/nas-recovery.md and STATUS.md updates closing the task. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9.6 KiB
title, type, tags, ingested, raw_path, updated
| title | type | tags | ingested | raw_path | updated | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| NAS Recovery Session 2026-05-18/19 | source |
|
2026-05-19 | ../../.tasks/nas-recovery.md | 2026-05-19 |
NAS Recovery Session 2026-05-18/19
15-часовая сессия восстановления клиентских сайтов после краха NAS Synology, на котором они хостились. Источник истины — лог переписки восстановления + .tasks/nas-recovery.md. Здесь сжатая хронология; конкретные паттерны и решения распилены по concepts/, инфраструктурные сущности — по entities/.
Контекст до краха
- Source NAS (теперь мёртвый): Synology DiskStation на XPEnology (самосборное x86 железо + DSM через community-loader). На нём:
- VMM (Virtual Machine Manager) → Windows-VM snolla с IIS + .NET Framework 4.8 CMS snolla-recovery-vm
- Container Manager → docker-стек: MSSQL Server 2019, MinIO 2020-07-13, Elasticsearch 7.10.1, imgproxy+nginx, traefik 2.6.6, gitea, и др.
- 11 клиентских сайтов под одной VM (snolla.com + 10 client TLDs: rimiz.ru, labtools.pro/ru, pilorama98.ru, tandemmebel.ru, emspb.ru, kupimknigi.spb.ru, maljarka.tandemmebel.ru, sestech.ru, ics-artmaterials.com)
- Backup target NAS (живой): kreknin-synology на 195.19.90.188 / kreknin.site, держит Hyper Backup репо.
- Бэкап-задача: "rsync Server 1", последняя успешная — 2026-05-09 05:06 (за 9 дней до краха).
См. также: dead-synology-diskstation, wd40efax-smr-cascade.
Хронология
2026-05-18 ~17:00 MSK: инцидент — второй из 3 дисков RAID 5 на mёртвой синке вышел из строя. Пул past redundancy. Diagnose см. wd40efax-smr-cascade.
~17:30: оценка вариантов. Выбран маршрут "восстановление на локальной Windows-машине пользователя" (windows-recovery-host) с гибридной архитектурой: VM для CMS (из OVA-экспорта) + docker-контейнеры для backend-сервисов.
~18:00: SSH-доступ к kreknin-synology (изначально по паролю, потом через ssh-ключ). Разбор структуры .hbk репо. См. hyper-backup-structure-and-recovery.
~19:00: старт Hyper Backup restore через DSM UI на удалённой синке во временную папку /volume1/restore-tmp/. Restore инициировал также создание новых шар backup/, docker/, work/ на root уровне /volume1/. Длительность ~3 часа на 277 GB selective набор.
~21:00 — параллельно:
- SFTP-pull
snolla.ova(42.5 GB) на Windows — через FileZilla (SFTP сервис DSM требовалось включить отдельно, ACL/chroot нюансы). - Локальная подготовка: установлены IIS, VirtualBox 7.2.8.
- На Windows запущен MSSQL контейнер 2019-latest пустым (для отладки compose).
- v2rayN на Windows: настроены routing rules "Bypass LAN" (
geoip:private→ direct), иначе VPN ловил inbound 80/443 traffic.
~22:00: найден MoreThenCms202605090301.zip — ежедневный .sql дамп БД (101 MB compressed, 547 MB unpacked). Попытка restore через sqlcmd -i — упала на строке 457k из-за $(function(){...}) в данных (jQuery JS в email-template таблицах). Sqlcmd интерпретировал $() как переменную. См. mssql-restore-pitfalls.
~23:00: повторный sqlcmd с флагом -x (disable var substitution). Параллельно pull /docker/personal/mssql/ (25 GB) как альтернатива — через ACL-fix chmod -R a+rX, потом scp -O (legacy SCP, обход chrooted SFTP).
2026-05-19 ночь (Claude автономно):
- OVA import в VirtualBox завершился (42.7 мин)
- sqlcmd v2 длился ~2.5 часа, тоже падал.
- Решение: bind-mount проблемы → named volume +
chown -R 10001:0через temp alpine container. Это сработало. См. mssql-container-data-restore. - Имя dead synology в БД-файлах было всё с одинаковым паролем
fXkH4@8O%3pc(production SA password из старогоdocker-compose.yml). Аккаунтsaоказался disabled, потребовалсяmssql-conf set-sa-passwordпод--user 0:0(root) → re-enable.
~02-08:00 утра: VM на VBox не загружалась. Кросс-гипервизорный crash. См. vbox-windows-stability-tuning — путь к стабильности через SCSI→SATA, отключение Hyper-V driver в Safe Mode, --paravirtprovider kvm, OS type Windows10_64, Guest Additions.
~09:30: VM стабилизирована. Network drama #1: bridged через WiFi нестабильно (promiscuous mode проблемы у WiFi-адаптера). Switched VM nic1 на NAT + port forwarding в VBoxManage: host:23389→VM:3389, host:8022→VM:22, host:18080→VM:80, host:18180→VM:8080, host:18181→VM:8081, host:18189→VM:8089.
~10:00: OpenSSH server установлен внутри VM. SSH-ключ для Claude в C:\ProgramData\ssh\administrators_authorized_keys (особая локация для admin-users, локализованная группа Администраторы через icacls). Default shell sshd переключен на PowerShell.
~10:30: Web.config-патч во всех 4 сайтах VM: Data Source=192.168.1.10 → Data Source=10.0.2.2 (VBox NAT gateway = host). Encoding ловушка: Set-Content без -Encoding utf8 записал UTF-16 LE — IIS вернул 500.19 invalid XML. Fix: [System.IO.File]::WriteAllText с UTF8Encoding($true) (BOM). См. cms-config-rewrite-pattern.
~11:00: Traefik 2.6.6 запущен на хосте. Полный цикл правок: --configFile=/traefik.yml явно (не находил автоматом), named volume для letsencrypt/ (bind-mount показывал 0777 Linux-side, traefik требует 0600), 13 custom yml файлов пропатчены 192.168.1.15 → host.docker.internal:18080. docker.sock провайдер не работал (Docker Desktop особенности) → minio/imgproxy/elasticsearch traefik-labels переписаны как file-provider в data/custom/. См. traefik-on-windows-docker-desktop.
~11:30: OpenWRT openwrt-router на 192.168.1.1: DHCP-резервация Windows-PC на 192.168.1.143 (его MAC 88:66:5A:2F:AA:68), port forwards 80→8000 и 443→4443 (host:8000/4443 ↔ traefik). VM получила старый MAC 02:11:32:2A:7C:B9 из DHCP-резервации snolla — IP 192.168.1.15 сохранился для совместимости с snolla.yml (но потом перешли на NAT, IP стал внутренним).
~12:00: Public test через домен/чужой WiFi: https://snolla.com, https://pilorama98.ru, https://labtools.ru, https://labtools.pro, https://tandemmebel.ru, https://emspb.ru, https://kupimknigi.spb.ru, https://maljarka.tandemmebel.ru отвечают 200 OK end-to-end. Recovery functionally complete.
После полного recovery — резервный pull
В фоне на Windows: tar+ssh stream C:\inetpub\wwwroot\ (8.9 GB) и C:\stayer\ (2.27 GB) из VM в C:\nas-recovery\vm-sites\ — как фолбэк если VM снова станет нестабильной (был один случай glitch network — лечился ipconfig /release /renew через VBoxManage guestcontrol).
Открытые вопросы / нюансы
- X-Forwarded-Proto/Host headers между traefik и CMS не настроены → CMS делает redirect с
:4443в URL. - MinIO / Azure storage в CMS: connection string использует Azure SDK (AccountName=snolla, AccountKey=...), но в production реально работало с MinIO. Точная схема "не так, как казалось" по словам пользователя — ждёт пояснения.
- acme.json renewal через HTTP-01 фейлится для доменов с DNS не на нашем IP. Решение — DNS-01 через REGRU (creds в
traefik/docker-compose.ymlenv уже, вtraefik.ymlзакомментировано). - VM long-term stability: один случай network glitch уже был. Возможна планка scheduled task внутри VM — auto release/renew при детекции downtime.
Архитектурное замечание
Сохранение работающей конфигурации не равно отказоустойчивости. Текущая инфраструктура recovery-architecture-snapshot сильнее, чем была (Hyper Backup проверен, восстановление практикой), но single-point-of-failure всё ещё есть: один Windows-PC, одна VM, один публичный IP, один роутер. Глобальная задача future-resilient-architecture-goals — на потом.