From c86750b75db081a07741a36f76655820041c8747 Mon Sep 17 00:00:00 2001 From: vitya Date: Tue, 19 May 2026 11:07:38 +0300 Subject: [PATCH] docs(.wiki): ingest NAS recovery session 2026-05-18/19 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- dead-synology-diskstation.md | 70 ++++++++++++++++++++++++++++++ kreknin-synology.md | 47 +++++++++++++++++++++ openwrt-router.md | 62 +++++++++++++++++++++++++++ snolla-recovery-vm.md | 82 ++++++++++++++++++++++++++++++++++++ windows-recovery-host.md | 69 ++++++++++++++++++++++++++++++ 5 files changed, 330 insertions(+) create mode 100644 dead-synology-diskstation.md create mode 100644 kreknin-synology.md create mode 100644 openwrt-router.md create mode 100644 snolla-recovery-vm.md create mode 100644 windows-recovery-host.md diff --git a/dead-synology-diskstation.md b/dead-synology-diskstation.md new file mode 100644 index 0000000..0c2391b --- /dev/null +++ b/dead-synology-diskstation.md @@ -0,0 +1,70 @@ +--- +title: Мёртвая Synology DiskStation (source NAS) +type: entity +tags: [hardware, nas, xpenology, raid, dead] +sources: [../sources/nas-recovery-session-2026-05-18.md] +updated: 2026-05-19 +--- + +# Dead Synology DiskStation + +Source NAS, на котором хостились клиентские сайты MoreThenCms до 2026-05-18. **Сейчас off / data unrecoverable средствами DSM.** + +## Hardware + +- **Тип:** XPEnology (DSM 7 на самосборном x86, community-loader) +- **Шасси:** 6 HDD bay +- **Hostname:** `diskstation` +- **Bootloader:** USB-флешка (внешняя относительно дисков) +- **System SSD:** Netac SSD 120 GB (отдельный) — "Отказ системного раздела" к моменту инцидента +- **DSM hostname в сети:** `diskstation` (LAN), без публичного DDNS (доступ через клиентские домены через traefik) + +## Storage pool + +- **RAID 5** на **3 дисках** WD Red **WD40EFAX-68JH4N1 / 68JN4N0** (3.6 TB каждый) +- ~7 TB usable (`/dev/mapper/cachedev_0` 7.0T) +- ⚠️ **WD40EFAX = SMR** — см. [[wd40efax-smr-cascade]] для механики краха. + +## Что было на NAS + +### VMM +- **snolla VM:** Windows-VM с IIS + .NET Framework 4.8 + CMS [[snolla-recovery-vm]] +- MAC: `02:11:32:2A:7C:B9`, IP `192.168.1.15` (DHCP-резервация на роутере) +- OVA-экспорт от 2024-10-27 включён в Hyper Backup → теперь работает на VirtualBox на [[windows-recovery-host]]. + +### Container Manager (docker) +- **mssql:** Server 2019, 5 БД (`MoreThenCms`, `StayerCalculator`, `StayerPrice`, `stostayer`, `TireService`) +- **minio:** RELEASE.2020-07-13T18-09-56Z, 9 бакетов (artmone 2.5 GB, pilorama98 120 MB, books 5 MB, и др.) +- **elasticsearch:** 7.10.1, 3 индекса (для books-стека, не MoreThenCms) +- **imgproxy + nginx-cache** +- **traefik:** 2.6.6, 13 client routes, 40 Let's Encrypt сертификатов +- **gitea:** 2.6 GB +- Прочее: jellyfin, mongo, owncloud, navidrome, mariadb, и т.д. + +### Shares +- `/docker/` — docker-стеки +- `/docker/personal/` — большая часть production-сервисов +- `/backup/` — куда писались ежедневные дампы: + - `/backup/snolla/SQLServer/MoreThenCms.zip` — ежедневный sql-script (101 MB compressed) + - `/backup/snolla/snolla.ova` — 42.5 GB, экспорт VM (последний 2024-10-27) +- `/work/` — рабочая папка разработчика (в восстановление не брали по решению пользователя) + +## Что произошло 2026-05-18 + +См. [[wd40efax-smr-cascade]]. Кратко: первый диск умер в начале мая, ~2 недели пул жил degraded, second disk вылетел 2026-05-18 → RAID 5 за пределами redundancy → пул "Сбой сборки" в DSM. + +## Что НЕ делать с этой коробкой + +- ❌ Repair / Online Assembly в DSM на этом пуле — бесполезно. +- ❌ Вытаскивать оставшиеся 2 диска до решения "нужно ли pro data recovery". +- ❌ Пересоздавать пул на тех же дисках. +- ❌ Ставить новые WD40EFAX (если будут запасные) — же баг останется. + +## План восстановления железа (после ремонта инфраструктуры) + +- Заменить все WD40EFAX на CMR-диски (WD Red **Plus** / Seagate IronWolf / WD Red Pro / HGST Ultrastar). +- Заменить Netac SSD на нормальный consumer SSD (Samsung 870 EVO / WD Red SA500). +- Конфигурация: + - **3 CMR в RAID 5** + ежедневный Hyper Backup + дисциплина replace failed disk в течение 24-48 часов + - **или 4 CMR в RAID 6** (или SHR-2) — толерирует 2 отказа, рекомендуется после такого опыта +- Тест восстановления раз в квартал. diff --git a/kreknin-synology.md b/kreknin-synology.md new file mode 100644 index 0000000..a4fdc30 --- /dev/null +++ b/kreknin-synology.md @@ -0,0 +1,47 @@ +--- +title: Kreknin Synology (backup target + DDNS) +type: entity +tags: [hardware, nas, synology, backup, hyperbackup] +sources: [../sources/nas-recovery-session-2026-05-18.md] +updated: 2026-05-19 +--- + +# Kreknin Synology + +Удалённая (географически в другом месте) Synology, которая держит Hyper Backup-репо мёртвой синки и сама работает как живой сервер. + +## Доступ + +- **Public IP:** 195.19.90.188 +- **DDNS:** kreknin.site (резолвится на 195.19.90.188) +- **DSM web:** http://kreknin.site:5000 (HTTP; HTTPS 5001 наружу НЕ проброшен) +- **SSH:** vitya@195.19.90.188:22 (был пароль, сейчас SSH-ключ установлен — `id_ed25519_kreknin`) +- **Канал:** "не очень надёжный" по словам пользователя — поэтому неудобно держать там production-сайты. + +## Ограничения SFTP + +- **SFTP-подсистема DSM запускается отдельно от SSH** — Control Panel → File Services → FTP → SFTP. Изначально не была включена. +- **После включения SFTP — DSM jail-chroot'ит подсистему в home юзера.** То есть `vitya` через SFTP видит только `/volume1/homes/vitya/`, не `/volume1/backup/...`. +- **Обход:** `scp -O` (legacy SCP протокол) использует чистый SSH-channel мимо SFTP-subsystem → даёт доступ ко всему, что shell-пользователь видит. + +## Структура + +- **Volume:** один том `/volume1`, 7.0 TB, ~1.2 TB used до восстановления. +- **/volume1/NetBackup/diskstation_1.hbk** — Hyper Backup репо с мёртвой синки. 430 GB compressed (deduplicated), последняя успешная backup-версия 2026-05-09 05:06. +- **Hyper Backup Vault** установлен как пакет на этой синке (см. [[hyper-backup-structure-and-recovery]]). +- Owner данных в репо — `vitya:users` (POSIX) с ACL под `+`. ACL даёт vitya read, но individual файлы `.bak`/`.acme.json` могут иметь `-rw-------` — для них нужен `chmod -R a+rX` из root SSH. + +## VMM статус + +- Установлен (виден `@SavedVM` в `/volume1/`). +- В сессии 2026-05-18 рассматривался вариант поднять `snolla.ova` прямо здесь через VMM как альтернатива переезду на Windows — отвергнут потому что канал не надёжный. + +## Роль в recovery + +- **Источник всех данных:** OVA, sql дампы, docker volumes (mssql, minio, elasticsearch, imgproxy/nginx) — всё тащилось отсюда. +- **Не было записи на этот NAS** во время recovery — только чтение / Hyper Backup restore во временную папку `/volume1/NetBackup/restore-tmp/`, потом backup-shares `/volume1/backup/`, `/volume1/docker/`, `/volume1/work/`. + +## Гипотеза по будущему backup pipeline + +- Эта синка остаётся как backup target, на ней нет SMR-дисков (тип неизвестен на момент сессии, но кратко проверить через `ls /dev/sd*` + smartctl до тяжёлой нагрузки). +- Будущая [[future-resilient-architecture-goals]]: добавить второй backup target (или облачный — Backblaze B2 / S3 Glacier), чтобы не зависеть от одной коробки. diff --git a/openwrt-router.md b/openwrt-router.md new file mode 100644 index 0000000..5742a45 --- /dev/null +++ b/openwrt-router.md @@ -0,0 +1,62 @@ +--- +title: OpenWRT Router (192.168.1.1) +type: entity +tags: [hardware, networking, openwrt, nat, dhcp] +sources: [../sources/nas-recovery-session-2026-05-18.md] +updated: 2026-05-19 +--- + +# OpenWRT Router + +Домашний роутер, через который идёт весь публичный трафик к клиентским сайтам. + +## Hardware / OS + +- **Hardware:** MediaTek MT7622 (aarch64), 6 disk-bay шасси (с роутером не связано) +- **OS:** OpenWRT 23.05.4 (r24012-d8dd03c46f) +- **Uptime:** 13+ дней на момент recovery +- **LAN-IP:** 192.168.1.1 +- **LAN-subnet:** 192.168.1.0/24 +- **WAN-public:** 94.19.247.14 + +## Access + +- SSH: `root@192.168.1.1:22` — ssh-key `id_ed25519_openwrt` установлен в `/etc/dropbear/authorized_keys` +- LuCI web: http://192.168.1.1 +- Конфиг через `uci` (UCI infrastructure) + +## Текущий port forwarding setup (после recovery patch) + +Активные: +- `firewall.@redirect[0]` (SSL): WAN **443** → 192.168.1.143:**4443** (Windows-PC, где traefik) +- `firewall.@redirect[1]` (HTTP): WAN **80** → 192.168.1.143:**8000** (Windows-PC, где traefik) +- `firewall.@redirect[9]` (Wireguard): WAN 48820 → 192.168.1.239 (отдельный хост, не трогали) + +Старые (всё ещё активны, но смотрят на мёртвую синку 192.168.1.10 — на которой ничего нет): +- DSM 5000 → 192.168.1.10:5000 +- FTP 21, SFTP 22, MariaDB 36063, SQLServer 23056, PassiveFTP 55536-55899, Cloud Station 6690, SSH 1322 + +В рамках recovery эти **не отключали** (по решению пользователя). Можно отключить через `uci set firewall.@redirect[N].enabled='0'` для снижения шума атак. + +## DHCP-резервации (актуальные) + +| Хост | IP | MAC | Назначение | +|---|---|---|---| +| `windows-recovery-pc` | 192.168.1.143 | 88:66:5A:2F:AA:68 | [[windows-recovery-host]] | +| `snolla` (исторически) | 192.168.1.15 | 02:11:32:2A:7C:B9 | Раньше — VM мёртвой синки. Сейчас MAC присвоен новой [[snolla-recovery-vm]], но VM в NAT-режиме и LAN-IP не получает. | +| `diskstation` | 192.168.1.10 | 22:06:7C:32:00:6F (+ ...:70) | Мёртвая синка [[dead-synology-diskstation]] | +| Прочие | разное | разное | wled-1, hifiberry, и т.д. — не трогаем | + +## Firewall zones + +- **lan:** input=ACCEPT, output=ACCEPT, forward=ACCEPT (внутри LAN всё открыто) +- **wan:** input=REJECT, output=ACCEPT, forward=REJECT, masq=1 (стандарт) +- LAN→WAN forwarding: ALLOW + +Дополнительные input rules для wan (стандартные OpenWRT): Allow-DHCP-Renew, Allow-Ping, Allow-IGMP, Allow-DHCPv6, Allow-MLD, Allow-ICMPv6-*, Allow-IPSec-ESP. + +## Что bgужно сделать (на потом) + +- Отключить устаревшие redirects на 192.168.1.10 (DSM/FTP/SQL/Cloud Station) — снижает attack surface. +- Запланировать DDNS для случая смены публичного IP (REGRU domains всё ещё указывают на 94.19.247.14). +- При планировании [[future-resilient-architecture-goals]] — добавить **second WAN** (3G/4G/LTE через USB-modem) на роутер? OpenWRT поддерживает multi-WAN. diff --git a/snolla-recovery-vm.md b/snolla-recovery-vm.md new file mode 100644 index 0000000..5940d8c --- /dev/null +++ b/snolla-recovery-vm.md @@ -0,0 +1,82 @@ +--- +title: Snolla Recovery VM (VirtualBox) +type: entity +tags: [vm, virtualbox, windows, iis, cms, recovery] +sources: [../sources/nas-recovery-session-2026-05-18.md] +updated: 2026-05-19 +--- + +# Snolla Recovery VM + +VirtualBox-VM на [[windows-recovery-host]], в которой работает CMS-стек (IIS + .NET + код CMS). Импортирован из OVA-снапшота 2024-10-27, который лежал в Hyper Backup репо. + +## Параметры + +- **VBox name:** `snolla-recovery` +- **UUID:** `66aac8bb-fe70-4ced-87f6-2291cd0e8b74` +- **Расположение:** `C:\Users\vitya\VirtualBox VMs\snolla-recovery\` +- **OS внутри:** Windows (вероятно Server 2016/2019, hostname `SNOLLA`) +- **RAM:** 4096 MB +- **vCPU:** 2 (после оптимизации [[vbox-windows-stability-tuning]] — было 4) +- **Disk:** `snolla-disk1.vmdk`, max 120 GB, реально ~92 GB на хосте +- **Storage controller:** SATA AHCI (после миграции с SCSI LsiLogic, см. [[vbox-windows-stability-tuning]]) +- **Network:** NAT (после миграции с bridged WiFi из-за нестабильности) +- **Paravirt:** `kvm` (matching исходному гипервизору Synology VMM) +- **OS type:** Windows10_64 (исходно был `Other_64`, поправили для оптимальных дефолтов) +- **Guest Additions:** 7.2.8 r173730, RunLevel=3 (полностью активны) + +## NAT Port Forwards + +| Host port | VM port | Назначение | +|---|---|---| +| 13389 | (console) | **VRDE** (VBox Remote Display) — для отладки, не зависит от Windows RDP | +| 23389 | 3389 | RDP внутри VM (Windows Remote Desktop) | +| 8022 | 22 | SSH (OpenSSH Server в VM) | +| 18080 | 80 | IIS Default — основной HTTP CMS | +| 18180 | 8080 | IIS site `stostayer` | +| 18181 | 8081 | IIS site `stostayer.old` | +| 18189 | 8089 | (запасной) | + +## Учётка + +- **Admin:** vitya (домен SNOLLA) +- **Default shell для sshd:** PowerShell (зарегистрирован в `HKLM:\SOFTWARE\OpenSSH` → `DefaultShell`) +- **Authorized SSH key для admin-users:** `C:\ProgramData\ssh\administrators_authorized_keys` (особое место для admin Windows OpenSSH; permissions через `icacls`, group `Администраторы:F` + `СИСТЕМА:F`) + +## IIS-сайты + +| Site | Path | Bindings | +|---|---|---| +| **MoreThenCms.Web** | `C:\inetpub\wwwroot\MoreThenCms.Web` | `*:80` | +| **Snolla.IdentityManager** | `C:\inetpub\wwwroot\Snolla.IdentityManager` | `*:80` | +| **stostayer** | `C:\stayer\MoreThenCms.Web` | `*:8080` | +| **stostayer.old** | `C:\stayer\stostayer.old` | `*:8081` | +| (default) | | `*:8089` | + +CMS распознаёт клиента по **Host header** — все 11 клиентских доменов идут на 80 и роутятся внутри CMS-кода. + +## Web.config — критичные настройки (после recovery patch) + +- **Connection string:** `Data Source=10.0.2.2;Initial Catalog=MoreThenCms;User Id=snolla;Password=fXkH4@8O%3pc;...` + - `10.0.2.2` = NAT gateway в VBox = адрес хоста [[windows-recovery-host]] изнутри VM + - До патча было `Data Source=192.168.1.10` (старая мёртвая синка) + - Тот же пароль `fXkH4@8O%3pc` совпадает с SA-паролем MSSQL контейнера (production password из старого compose) +- **Encoding файла:** UTF-8 with BOM (важно — см. [[cms-config-rewrite-pattern]]) +- 4 файла пропатчены аналогично: `MoreThenCms.Web/Web.config`, `Snolla.IdentityManager/Web.config`, `stostayer.old/web.config`, и stayer-проектов (если применимо) + +## Связь со внешним миром + +- VM в NAT-режиме → не имеет LAN-IP +- Из traefik (на хосте) достижима по `host.docker.internal:18080` → NAT-форвард в Windows → VM:80 +- Раньше (когда было bridged) — VM имела IP `192.168.1.15` с MAC `02:11:32:2A:7C:B9`. snolla.yml в traefik/data/custom/ исходно ссылался на `http://192.168.1.15/` — пропатчен на `host.docker.internal:18080/`. + +## Стабильность + +- Нестабильна на bridged-WiFi → переведена в NAT (стало лучше, но всё равно требует осторожности). +- Один случай (после нескольких часов uptime): network adapter в VM "повис" — все TCP-handshake проходили, но через них трафик не шёл. Лечится `ipconfig /release && /renew` внутри VM через VBoxManage guestcontrol. +- **Долгосрочно**: пора планировать scheduled task внутри VM, который при детекции downtime автоматически перезагружает network adapter / iisreset. Или вообще переезд на Hyper-V — рекомендация Microsoft для Windows-гостей. + +## Известные баги в текущей конфигурации + +- **X-Forwarded-Proto/Host headers** не передаются с traefik в IIS → CMS делает redirect на `http://www.:4443/` (mixing HTTP scheme with HTTPS port). Не критично, но требует фикса. +- **Логи в C:\inetpub\logs\** растут (~6 GB на момент recovery) — нужна ротация. diff --git a/windows-recovery-host.md b/windows-recovery-host.md new file mode 100644 index 0000000..6a17865 --- /dev/null +++ b/windows-recovery-host.md @@ -0,0 +1,69 @@ +--- +title: Windows Recovery Host (рабочий PC пользователя) +type: entity +tags: [hardware, windows, docker, virtualbox, iis, recovery] +sources: [../sources/nas-recovery-session-2026-05-18.md] +updated: 2026-05-19 +--- + +# Windows Recovery Host + +Личный Windows-PC пользователя, который во время recovery стал production-сервером для всех клиентских сайтов. + +## Hardware / OS + +- **Hostname:** DESKTOP-NSEF0UK +- **OS:** Windows 11 Pro (предположительно — поддерживает Hyper-V, IIS, .NET Framework) +- **LAN-MAC:** 88:66:5A:2F:AA:68 (Broadcom 802.11ac WiFi) +- **LAN-IP:** 192.168.1.143 (DHCP-резервация на [[openwrt-router]]) +- **Диск C:** ~700 GB total, на старте recovery ~352 GB free, после — ~150 GB free. +- **Юзер:** vitya (admin) + +## Установленный стек + +- **.NET Framework:** 4.8.1 +- **IIS** (W3SVC, на 80, мы планировали остановить — но не остановили, traefik на 8000/4443 не конфликтует) +- **Docker Engine 29.3.1** (Docker Desktop с WSL2 backend) +- **VirtualBox 7.2.8** (установлен в сессии 2026-05-18, через winget) +- **OpenSSH client** (для ssh/scp к kreknin и VM) +- **FileZilla client** (для пользовательских SFTP-перетаскиваний) + +## Сетевое положение + +- За **OpenWRT 23.05.4** [[openwrt-router]] +- Соединение с интернетом через **WiFi** (Broadcom 802.11ac, 288 Mbps) +- За **VLESS-клиентом v2rayN** (роутер default-route шёл через VPN, пришлось настроить **Bypass LAN** правило с `geoip:private` → direct, иначе входящие 80/443 терялись через asymmetric routing) + +## Что хостит сейчас (после recovery) + +| Что | Где | Порт (host) | +|---|---|---| +| **VirtualBox `snolla-recovery` VM** | C:\Users\vitya\VirtualBox VMs\snolla-recovery\ | VRDE 13389, NAT-RDP 23389, NAT-SSH 8022, NAT-HTTP 18080/18180/18181/18189 | +| **traefik 2.6.6** | Docker, network `proxy` | 8000 (http), 4443 (https), 8080 (dashboard) | +| **MSSQL 2019** | Docker, named volume `mssql_mssql_data` | 1433 | +| **MinIO** | Docker, bind-mount `./data` | 9000 | +| **Elasticsearch 7.10.1** | Docker, bind-mount `./data` | 9200 | +| **imgproxy** | Docker | 8787 | +| **imgproxy-nginx** | Docker | 8788 | + +Также установлен IIS, но Default Web Site пустой / неактивно используется. Должен быть остановлен в админ-PowerShell когда руки дойдут (для оптимизации; на 8000/4443 traefik не конфликтует с IIS на 80). + +## Ключевые папки + +- `C:\Users\vitya\projects\docker\diskstation\` — compose'ы и данные docker-стеков + - `mssql/`, `minio/`, `elasticsearch/`, `imgproxy/`, `traefik/` + - `traefik/data/custom/*.yml` — file-provider routes для всех 13 client доменов + ES/MinIO/imgproxy +- `C:\Users\vitya\VirtualBox VMs\snolla-recovery\` — VM home (VMDK на SATA controller, 42.5 GB extract из OVA) +- `C:\nas-recovery\backup\snolla\snolla.ova` — оригинал OVA (45.6 GB, для повторного импорта если что) +- `C:\nas-recovery\vm-sites\wwwroot\`, `C:\nas-recovery\vm-sites\stayer\` — резервная копия IIS-сайтов из VM (на случай дрожи VM) +- `C:\Users\vitya\projects\MoreThenCms\` — git-репо с исходниками CMS (важно — у нас есть и source code) + +## SSH-ключи на этой машине + +- `~/.ssh/id_ed25519_kreknin` — для [[kreknin-synology]] (vitya@195.19.90.188) +- `~/.ssh/id_ed25519_openwrt` — для [[openwrt-router]] (root@192.168.1.1) +- `~/.ssh/id_ed25519_snolla_vm` — для [[snolla-recovery-vm]] (vitya@127.0.0.1:8022, в admin-keys VM) + +## Что должно случиться, если этот PC погаснет + +- **Всё** — все сайты лягут. **Single point of failure** — главное замечание для [[future-resilient-architecture-goals]].