--- title: Recovery architecture — текущая инфраструктура (2026-05-19, attempt 2) type: concept tags: [architecture, current-state, snapshot, recovery] sources: [../sources/nas-recovery-session-2026-05-18.md, ../sources/iis-host-migration-2026-05-19.md] updated: 2026-05-19 --- # Recovery Architecture Snapshot Снимок production-инфраструктуры на конец **второй (успешной) попытки** миграции 2026-05-19. 14 cms hostnames теперь идут через native IIS на [[windows-recovery-host]] напрямую. VM `snolla-recovery` — **parallel-fallback**, running но больше не на prod-пути (24h+ soak, потом savestate). 2 stayer routes окончательно **disabled** через traefik (host IIS sites живут для прямого доступа). История: attempt 1 в этот же день сломал prod, был revert; recipe — в [[iis-migration-2026-05-19-postmortem]]. Attempt 2 выполнен по recipe — см. [[iis-host-migration-2026-05-19]] Phase 10. Это **рабочее, но всё ещё временное** состояние — single-point-of-failure на бытовом железе. Замечания по улучшению — [[future-resilient-architecture-goals]]. ## Цепочка запроса от клиента до CMS (host-IIS chain, attempt 2) ``` Клиент (browser) → DNS resolve (REGRU): *.snolla.com (включая on.snolla.com — default subdomain), labtools.ru/pro, pilorama98.ru, tandemmebel.ru, emspb.ru, kupimknigi.spb.ru, maljarka.tandemmebel.ru, sestech.ru, ics-artmaterials.com, rimiz.ru (404 CMS-side) → 94.19.247.14 (public IP, статический у провайдера) → router OpenWRT (192.168.1.1) [[openwrt-router]] → NAT 443 → 192.168.1.143:4443 → NAT 80 → 192.168.1.143:8000 → Windows-PC (192.168.1.143) [[windows-recovery-host]] → traefik 2.6.6 на 4443/8000 → TLS termination, certResolver=letsEncrypt из acme.json → match по Host header (file-provider rules в data/custom/*.yml) → backend = http://host.docker.internal:8089/ → host:8089 → IIS site `snolla` (binding *:8089) → IIS native на хосте → site `snolla`, .NET Framework 4.8.1, AppPoolIdentity → C:\sites\snolla\, sitePath patched, conn → localhost → ASP.NET CMS code (.NET Framework 4.8) → Connection strings: → MSSQL: Data Source=localhost,1433 (host:1433 = MSSQL container) → MinIO/storage: вопрос снят пользователем → Elasticsearch: не используется CMS → MSSQL container на host:1433 → 5 production DB (MoreThenCms, Stayer*, stostayer, TireService) ← HTTP response back through chain ``` **VM `snolla-recovery`:** running parallel, no traffic (24h+ soak fallback). NAT port forwards `:18080/:18180/:18181/:18189` холостые. Будет savestate'ena после стабильности → потом unregistervm для освобождения ~92 GB. ## Stayer chain — DISABLED через traefik ``` stostayer.snolla.com / old.stostayer.ru → DNS → 94.19.247.14 → router → traefik → match Host → нет routes (stostayer.yml.disabled, oldstostayer.yml.disabled) → traefik 404 "no route" ``` Host IIS sites `stostayer (:8090)` и `stostayer.old (:8091)` **живут** для прямого/локального доступа. Conn-strings: - `stostayer`: `Data Source=www.stostayer.ru,1433`, user `stayer_site`, password XML-escaped см. [[webconfig-password-xml-escape]] - `stostayer.old`: `Data Source=localhost` (наш MSSQL контейнер) ## Запущенные docker контейнеры на хосте | Container | Image | Port (host) | Volume | |---|---|---|---| | **traefik** | `traefik:v2.6.6` | 4443, 8000, 8080 | named: `traefik_traefik_letsencrypt`; bind: `data/traefik.yml`, `data/custom/` | | **mssql** | `mcr.microsoft.com/mssql/server:2019-latest` | 1433 | named: `mssql_mssql_data` (filled from production tar) | | **minio** | `minio/minio:RELEASE.2020-07-13T18-09-56Z` | 9000 | bind: `./data` | | **imgproxy** | `darthsim/imgproxy:latest` | 8787 | (нет state) | | **imgproxy-nginx** | `nginx:alpine` | 8788 | bind: `./nginx/cache`, `./nginx/nginx.conf` | | **elasticsearch** | `elasticsearch:7.10.1` | 9200 | bind: `./data` | Все на docker network `proxy` (external). ## Traefik routes (после attempt 2) 11 cms yml репойнтены на host IIS:8089. 2 stayer yml — `.disabled`. | File | Hosts | Backend | Статус | |---|---|---|---| | snolla.yml | snolla.com + 10 *.snolla.com subdomains (rule explicit) | host.docker.internal:8089 | active → host IIS | | rimiz.yml | rimiz.ru, www.rimiz.ru | host.docker.internal:8089 | active (но CMS-side 404 — known) | | labtools.yml | labtools.ru, www.labtools.ru | host.docker.internal:8089 | active → host IIS | | labtoolspro.yml | labtools.pro, www.labtools.pro | host.docker.internal:8089 | active → host IIS | | pilorama98.yml | pilorama98.ru, www.pilorama98.ru | host.docker.internal:8089 | active → host IIS | | tandemmebel.yml | tandemmebel.ru, www.tandemmebel.ru | host.docker.internal:8089 | active → host IIS | | emspb.yml | emspb.ru, www.emspb.ru | host.docker.internal:8089 | active → host IIS (canary 1, phone-test ✅) | | kupimknigi.yml | kupimknigi.spb.ru | host.docker.internal:8089 | active → host IIS | | maljarka.yml | maljarka.tandemmebel.ru | host.docker.internal:8089 | active → host IIS | | sestech.yml | sestech.ru, www.sestech.ru | host.docker.internal:8089 | active → host IIS | | isc-artmaterials.yml | ics-artmaterials.com, www.ics-artmaterials.com | host.docker.internal:8089 | active → host IIS (CMS-side 404 — known) | | **stostayer.yml.disabled** | stostayer.snolla.com | (n/a, route disabled) | **DISABLED**, host IIS :8090 локально | | **oldstostayer.yml.disabled** | old.stostayer.ru | (n/a, route disabled) | **DISABLED**, host IIS :8091 локально | **Backup-stamp файлы** (накопились за обе попытки): - `*.yml.bak-2026-05-19` — самый ранний backup (до session). - `*.yml.bak-phase3-2026-05-19` — rollback baseline (attempt 1 → revert state, всё на VM `:18080`). - `*.yml.bak-hostip-2026-05-19` — failed attempt 1 (host.docker.internal:80 ⇒ Docker NAT loop). - `*.yml.bak-stayer-switch-2026-05-19` — stayer switch attempt artefact (Phase 5/6 prev session). - **`*.yml.bak-pre-attempt2-2026-05-19`** — текущая live conf attempt 2 (host:8089 backend). Это baseline для **atomic revert** этой попытки. Плюс file-provider маршруты для инфраструктурных хостов: | File | Host | Backend | |---|---|---| | elasticsearch.yml | elasticold.kzntsv.site | http://elasticsearch:9200 + basicAuth `books:...` | | minio.yml | minio.kzntsv.site | http://minio:9000 | | imgproxy.yml | imgproxy.kzntsv.site | http://imgproxy-nginx:80 | И мёртвые (не отключены, но смотрят в никуда): - `disk.yml` → 192.168.1.10:5005 (Synology disk на мёртвой синке) - `dsm.yml` → 192.168.1.10:5000 (DSM мёртвой синки) ## Host IIS configuration (active prod) | Site | Bindings | Physical path | Pool identity | Прим. | |---|---|---|---|---| | **snolla** | `*:80`, `*:8089` | `C:\sites\snolla` | `ApplicationPoolIdentity` (.NET v4.0 Integrated) | **active prod** — catch-all для 11 cms hosts, traefik backend `:8089` | | **stostayer** | `*:8090` | `C:\sites\stostayer` | `ApplicationPoolIdentity` | local-only (traefik route disabled), conn → `www.stostayer.ru,1433` | | **stostayer.old** | `*:8091` | `C:\sites\stostayer.old` | `ApplicationPoolIdentity` | local-only (traefik route disabled), conn → `localhost,1433` | | Default Web Site | (stopped, autoStart=false) | — | — | — | ACL: `IIS AppPool\:(OI)(CI)M` рекурсивно на каждом site root. ## DNS Все домены остались указывать на **94.19.247.14** (public IP, статический). REGRU как registrar/DNS. ## Backup инфраструктура Текущая (на момент 2026-05-19, после attempt 2): - [[kreknin-synology]] держит Hyper Backup репо мёртвой синки (~430 GB). Новых бэкапов с recovered Windows-PC **НЕТ**. - Локально на Windows-PC: `C:\nas-recovery\vm-sites\` (~11 GB, дамп IIS sites из VM до patches) — резерв если host-IIS сломается катастрофически. После 48h+ uptime можно почистить. - `C:\nas-recovery\backup\snolla\snolla.ova` (42.5 GB) — оригинал OVA. После cleanup VM можно удалить. **Дыра:** если Windows-PC сгорит — всё ляжет. Никакой репликации, никакого off-site backup для нового рабочего состояния. ## SSH ключи и доступ - [[windows-recovery-host]] → [[kreknin-synology]]: `id_ed25519_kreknin` (vitya@195.19.90.188) - [[windows-recovery-host]] → [[openwrt-router]]: `id_ed25519_openwrt` (root@192.168.1.1) - [[windows-recovery-host]] → [[snolla-recovery-vm]]: `id_ed25519_snolla_vm` (vitya@127.0.0.1:8022) После recovery — отозвать публичные ключи Claude из этих 3 машин (`~/.ssh/authorized_keys` или эквивалент). См. соответствующие entity-страницы. ## Известные открытые баги 1. ~~**X-Forwarded headers** не передаются от traefik в IIS → CMS делает redirect с `:4443` в URL.~~ → **RESOLVED 2026-05-19 вечер** через URL Rewrite 2.1 + `` rule на host IIS. Также закрыл утечку `:8089` в admin SPA после attempt 2 миграции. См. [[cms-server-port-leak-fix]]. 2. **rimiz.ru → 404**. CMS-side, не инфра. 3. **ics-artmaterials.com → 404**. Аналогично — CMS-side (`www.ics-artmaterials.com → 301 → ics-artmaterials.com → 404`). 8. ~~**emspb.snolla.com `/admin/assets//getList` → 500 NullReferenceException**.~~ → **RESOLVED 2026-05-19 вечер** через DB seed root AssetsFolder rows для 15 sites без них (включая emspb, pilorama98, и др.). Симптом был НЕ site-specific — общий для всех sites которые никогда не использовали admin assets UI. См. [[cms-admin-assets-root-folder-seed]]. Долгосрочный TODO — null-guard в `AssetsJsonViewModelBuilder.Build` (требует recompile DLL, отложено до восстановления build env). 4. **acme.json HTTP-01 renewal** будет фейлить для доменов с DNS не на нашем IP → переезд на DNS-01 через REGRU до истечения сертификатов (~3 месяца). 5. **C:\inetpub\logs\** растёт — нужна ротация. 6. **docker.sock provider в traefik** не работает — но не блокирует (всё через file-provider). См. [[traefik-on-windows-docker-desktop]] Pitfall 3. 7. **WinHTTP proxy на хосте strips response headers** для `curl.exe http://localhost:...` — для loop-detect/IIS confirmation использовать `docker exec traefik wget` или `Invoke-WebRequest`. См. [[docker-host-loopback-detect]]. ## Single Points of Failure - Один Windows-PC (если сгорит — всё ляжет) - Один публичный IP / провайдер - Один WiFi-канал - Один OpenWRT-роутер - Один **host IIS instance** обслуживает весь cms-трафик (VM остаётся parallel fallback ещё 24-48h) - Один MSSQL контейнер (single primary, нет replica) - Один MinIO (single drive, не distributed) Каждый SPOF — кандидат на улучшение в [[future-resilient-architecture-goals]].