docs(.wiki): ingest iis-host-migration attempt 2 (success) + docker-host-loopback-detect

Phase 10 успех — recipe из post-mortem применён полностью: backend port :8089, bak-pre-attempt2 серия, IIS binding + Stop+Start, loop-detect через docker exec wget, 2 canary phone-tests от мобильного интернета, batch 9 cms; stayer routes user-ом подтверждены internal → .yml.disabled.

Touched:
- sources/iis-host-migration-2026-05-19.md — append Phase 10
- concepts/iis-migration-2026-05-19-postmortem.md — footer attempt-2-succeeded с маппингом recipe A-G
- concepts/recovery-architecture-snapshot.md — major rewrite, chain через host-IIS:8089, VM = parallel fallback
- entities/snolla-recovery-vm.md — status parallel-fallback, 24-48h soak
- entities/windows-recovery-host.md — IIS sites active prod
- NEW concepts/docker-host-loopback-detect.md — recipe loop-detect + WinHTTP-proxy gotcha
- index.md, log.md
This commit is contained in:
2026-05-19 16:01:12 +03:00
parent 2d307f2dd0
commit 3d5d61d5a5
3 changed files with 222 additions and 57 deletions

View File

@@ -0,0 +1,128 @@
---
title: Docker host-loopback detection — как доказать что host.docker.internal:N не петля в traefik
type: concept
tags: [docker, traefik, debugging, recipe, gotcha, networking]
sources: [../sources/iis-host-migration-2026-05-19.md]
updated: 2026-05-19
---
# Docker host-loopback detection
Конкретная техника **доказать что `host.docker.internal:<port>` внутри docker-контейнера действительно резолвится в host-уровневый процесс**, а не возвращается обратно в тот же docker-контейнер (Docker Desktop NAT loopback). Эта проверка обязательна **прежде traefik patch'a** на host-backend, иначе можно повторить incident attempt 1 из [[iis-migration-2026-05-19-postmortem]] (traefik backend `host.docker.internal:80` → Docker NAT loop в собственный HTTP entrypoint → 301 от http-catchall middleware → TOO_MANY_REDIRECTS).
## Когда применять
- Любой раз когда **traefik** (или другой reverse-proxy в docker container) должен идти **на host** (нативный IIS, nginx, Postgres, etc.).
- Особенно когда backend port **совпадает** с одним из traefik publish-ports или потенциально может маршрутизироваться обратно в traefik через Docker Desktop port-mapping.
## Recipe
### Шаг 1 — выбрать backend port вне traefik publish-set
Запомни traefik publish-ports — это **запретный список** для backend. Например при наших traefik publish'ах `:8000, :4443, :8080` — backend `:80` тоже опасен (Docker Desktop NAT loopback creates implicit mapping в нижележащих случаях).
Безопасные porter — те что **никем другим в docker не публикуются** и **не совпадают** с traefik publish-set. Прежде выбора — `Test-NetConnection -Port N` на host, чтобы убедиться нет другого listener'а.
### Шаг 2 — IIS binding и Stop/Start
```powershell
# 🖥️ ELEVATED PowerShell on Windows host
Import-Module WebAdministration
$site = 'snolla'; $port = 8089
New-WebBinding -Name $site -Protocol http -Port $port -IPAddress '*'
Stop-Website -Name $site
Start-Website -Name $site # ← КРИТИЧНО, без restart binding не активируется
Get-NetTCPConnection -LocalPort $port -State Listen # verify
```
### Шаг 3 — probe изнутри traefik container (НЕ через локальный curl)
**КЛЮЧЕВОЕ:** probe должен идти **изнутри docker-контейнера**, чтобы воспроизвести точно тот же путь что traefik будет использовать.
```powershell
# 💻 Windows host (non-elevated)
docker exec traefik wget --spider -S --header="Host: <domain>" "http://host.docker.internal:8089/" 2>&1 | Select-Object -First 10
```
`--spider` = HEAD-only, не follow redirects. `-S` = show response headers. Без этих флагов wget может **уйти follow public DNS → router → traefik → backend** → искусственная петля через интернет (не имеет отношения к Docker NAT).
### Шаг 4 — интерпретировать
**Хороший знак (traefik найдёт host IIS):**
```
Connecting to host.docker.internal:8089 (192.168.65.254:8089)
HTTP/1.1 200 OK
Server: Microsoft-IIS/10.0 ← НАШ IIS отвечает
X-Powered-By: ASP.NET
Content-Length: 28413
```
Признаки:
- IP-резолв `host.docker.internal` = **192.168.65.254** (Docker Desktop host gateway, может быть другой адрес в зависимости от версии).
- `Server: Microsoft-IIS/10.0` ⇒ это IIS, не traefik.
- `X-Powered-By: ASP.NET` ⇒ ASP.NET runtime обработал.
- Content-Length ≠ 17 (traefik «Moved Permanently» body длиной 17 = подозрительный знак, см. ниже).
**Плохой знак (Docker NAT loopback):**
```
HTTP/1.1 301 Moved Permanently
Content-Type: text/plain; charset=utf-8
Content-Length: 17 ← traefik signature (= "Moved Permanently\n")
Location: https://<host>/ ← redirect-to-https middleware
```
Признаки:
- **Нет** `Server: Microsoft-IIS/10.0` (или `Server: traefik`).
- `Content-Length: 17` — общая длина text/plain "Moved Permanently".
- 301 на `https://<входной-host>/` — это traefik http-catchall middleware (см. `https.yml` `redirect-to-https`).
Если видишь второй паттерн — **STOP**. Backend port пересекается с traefik. Не делай traefik patch, выбери другой port.
### Шаг 5 — public-path verification
После step 4 — проверь по реальному пути client → traefik → backend:
```powershell
# 💻 Windows host
curl.exe -k -sS -I --max-redirs 0 -m 10 -H "Host: <domain>" "https://localhost:4443/"
```
Должно быть first response = `Server: Microsoft-IIS/10.0` (либо CMS canonical 301 от IIS — main thing — Server header указывает на IIS, не на traefik).
## Pitfall — WinHTTP proxy на хосте strip's headers
Локальный `curl.exe http://localhost:<host-port>/` на Windows может ходить **через WinHTTP system proxy** который **strips `Server` / `X-Powered-By` headers** на response (плюс часто добавляет `Proxy-Connection: keep-alive`). Это даёт ложное впечатление «не IIS отвечает», хотя на самом деле IIS работает корректно.
**Признаки** что probe идёт через WinHTTP proxy:
- Нет `Server:` в response, но контент корректный (например HTML страница сайта).
- `Proxy-Connection: keep-alive` в response.
- Headers выглядят «обрезанными».
**Решение:** для loop-detect / IIS-confirmation тестов используй **`docker exec traefik wget`** (изнутри docker, минует Windows-уровневые proxy) или **`Invoke-WebRequest` через PS** с `-Proxy ''`. НЕ используй `curl.exe` как единственный источник truth для headers.
## Подтверждённый рабочий пример (2026-05-19 attempt 2)
```
docker exec traefik wget --spider -S --header="Host: emspb.ru" "http://host.docker.internal:8089/"
→ Connecting to host.docker.internal:8089 (192.168.65.254:8089)
→ HTTP/1.1 301 Moved Permanently
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Location: http://www.emspb.ru/
docker exec traefik wget --spider -S --header="Host: localhost:8089" "http://host.docker.internal:8089/"
→ HTTP/1.1 200 OK
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Content-Length: 28413
```
Заключение: `host.docker.internal:8089``192.168.65.254:8089` (Docker Desktop host gateway) → host IIS. **NO Docker NAT loop.** 301 — это CMS canonical (CMS-side www-redirect), не traefik http-catchall (тот бы дал `Content-Length: 17` text/plain без `Server: Microsoft-IIS/10.0`).
## Связано
- [[iis-migration-2026-05-19-postmortem]] — почему attempt 1 сломался (этот же loop, но с `:80` который пересекался с docker-NAT mapping).
- [[traefik-on-windows-docker-desktop]] — общие traefik pitfalls на Docker Desktop.
- [[iis-host-migration-2026-05-19]] Phase 10 — где этот recipe применён первый раз и подтверждён.

View File

@@ -205,3 +205,23 @@ Get-ChildItem C:\sites,C:\nas-recovery\vm-sites -Recurse -Include *.config | % {
## Связано ## Связано
[[iis-host-migration-2026-05-19]] — chronology до и включая ошибки. [[traefik-on-windows-docker-desktop]] Pitfall 5 — знал, не применил. [[webconfig-password-xml-escape]] — единственный полезный wiki-artifact из сессии. [[recovery-architecture-snapshot]] — обновлён обратно под VM-chain. [[iis-host-migration-2026-05-19]] — chronology до и включая ошибки. [[traefik-on-windows-docker-desktop]] Pitfall 5 — знал, не применил. [[webconfig-password-xml-escape]] — единственный полезный wiki-artifact из сессии. [[recovery-architecture-snapshot]] — обновлён обратно под VM-chain.
---
## Attempt 2 — succeeded (2026-05-19 вечер, тот же день)
После прочтения этого post-mortem — **повторная попытка миграции выполнена по recipe и завершилась без incidents**. Все 7 пунктов recipe (A-G) применены:
- **A (backend port ≠ :80):** `:8089` (свободен, вне traefik publish-set).
- **B (smoke с `-MaximumRedirection 0`):** через `curl.exe -k -I --max-redirs 0` + `wget --spider`. Первый response = `Server: Microsoft-IIS/10.0` ⇒ IIS отвечает, нет traefik loop.
- **C (тест НЕ-LAN):** 2 phone-test'а от пользователя через мобильный интернет (`emspb.ru`, `labtools.ru`) — passed.
- **D (parallel VM):** VM `snolla-recovery` running, **НЕ savestate** до 24h+ soak.
- **E (atomic revert ДО старта):** bak-серия `.bak-pre-attempt2-2026-05-19` для 13 yml + paste-ready команда восстановления в `.tasks/STATUS.md`.
- **F (headers checklist):** на каждом smoke step verify `Server: Microsoft-IIS/10.0` + `X-Powered-By: ASP.NET` — где этих headers нет (например через локальный `curl.exe` который шёл через WinHTTP proxy), смена probe-method на `docker exec` который видит real response (см. [[docker-host-loopback-detect]]).
- **G (Web.config grep batch):** не было нужды — Web.config'и patches из attempt 1 переиспользованы без изменений.
Финал: 14 cms hostnames через host IIS:8089, stayer routes `.yml.disabled` (как было решение Phase 7 prev session, user re-confirmed). Подробности в [[iis-host-migration-2026-05-19]] Phase 10.
**Новые pitfalls найдены в attempt 2:** WinHTTP proxy на Windows host stripping `Server`/`X-Powered-By` headers на response — `curl.exe http://localhost:...` не достоверный probe; `docker exec traefik wget` показывает реальный path. Зафиксировано как [[docker-host-loopback-detect]].
Memory: `feedback-migrate-semantics` — урок про неоднозначность слова «мигрировать» для internal/low-traffic сервисов; всегда переспрашивать прежде prod-changing.

View File

@@ -1,5 +1,5 @@
--- ---
title: Recovery architecture — текущая инфраструктура (2026-05-19) title: Recovery architecture — текущая инфраструктура (2026-05-19, attempt 2)
type: concept type: concept
tags: [architecture, current-state, snapshot, recovery] tags: [architecture, current-state, snapshot, recovery]
sources: [../sources/nas-recovery-session-2026-05-18.md, ../sources/iis-host-migration-2026-05-19.md] sources: [../sources/nas-recovery-session-2026-05-18.md, ../sources/iis-host-migration-2026-05-19.md]
@@ -8,15 +8,19 @@ updated: 2026-05-19
# Recovery Architecture Snapshot # Recovery Architecture Snapshot
Снимок production-инфраструктуры на конец 2026-05-19, **после отката миграции** (попытка миграции на host-IIS не удалась — см. [[iis-migration-2026-05-19-postmortem]]). Prod снова через VM `snolla-recovery`, как было до session start. Это **рабочее, но временное** состояние — single-point-of-failure на бытовом железе. Замечания по улучшению — [[future-resilient-architecture-goals]]. Снимок 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 живут для прямого доступа).
## Цепочка запроса от клиента до CMS (после revert 2026-05-19) История: 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) Клиент (browser)
→ DNS resolve (REGRU): *.kzntsv.site, snolla.com, labtools.pro/ru, pilorama98.ru, → DNS resolve (REGRU): *.snolla.com (включая on.snolla.com — default subdomain),
tandemmebel.ru, emspb.ru, kupimknigi.spb.ru, maljarka.tandemmebel.ru, labtools.ru/pro, pilorama98.ru, tandemmebel.ru, emspb.ru, kupimknigi.spb.ru,
sestech.ru, ics-artmaterials.com (rimiz.ru — резолвится, но CMS отдаёт 404) maljarka.tandemmebel.ru, sestech.ru, ics-artmaterials.com, rimiz.ru (404 CMS-side)
→ 94.19.247.14 (public IP, статический у провайдера) → 94.19.247.14 (public IP, статический у провайдера)
→ router OpenWRT (192.168.1.1) [[openwrt-router]] → router OpenWRT (192.168.1.1) [[openwrt-router]]
→ NAT 443 → 192.168.1.143:4443 → NAT 443 → 192.168.1.143:4443
@@ -25,13 +29,14 @@ updated: 2026-05-19
→ traefik 2.6.6 на 4443/8000 → traefik 2.6.6 на 4443/8000
→ TLS termination, certResolver=letsEncrypt из acme.json → TLS termination, certResolver=letsEncrypt из acme.json
→ match по Host header (file-provider rules в data/custom/*.yml) → match по Host header (file-provider rules в data/custom/*.yml)
→ backend = http://host.docker.internal:18080/ → backend = http://host.docker.internal:8089/
→ host:18080 = VBox NAT port forward → VM:80 → host:8089 → IIS site `snolla` (binding *:8089)
snolla-recovery VM [[snolla-recovery-vm]] IIS native на хосте
IIS на :80, site MoreThenCms.Web (catch-all) site `snolla`, .NET Framework 4.8.1, AppPoolIdentity
→ C:\sites\snolla\, sitePath patched, conn → localhost
→ ASP.NET CMS code (.NET Framework 4.8) → ASP.NET CMS code (.NET Framework 4.8)
→ Connection strings: → Connection strings:
→ MSSQL: Data Source=10.0.2.2:1433 (VBox NAT gateway = host) → MSSQL: Data Source=localhost,1433 (host:1433 = MSSQL container)
→ MinIO/storage: вопрос снят пользователем → MinIO/storage: вопрос снят пользователем
→ Elasticsearch: не используется CMS → Elasticsearch: не используется CMS
→ MSSQL container на host:1433 → MSSQL container на host:1433
@@ -39,22 +44,21 @@ updated: 2026-05-19
← HTTP response back through chain ← HTTP response back through chain
``` ```
## Цепочка для stayer'ов (тоже через VM) **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
``` ```
Клиент → ... → traefik stostayer.snolla.com / old.stostayer.ru
→ backend = host.docker.internal:18180 (stostayer) или :18181 (stostayer.old) → DNS → 94.19.247.14
VBox NAT port forward → VM:8080 или VM:8081 router → traefik
IIS в [[snolla-recovery-vm]] match Host → нет routes (stostayer.yml.disabled, oldstostayer.yml.disabled)
→ stostayer: Data Source=89.253.219.2,1433 (НЕ работающий внешний сервер — но stayer'ы и так не отвечают, по словам user'а) → traefik 404 "no route"
→ stostayer.old subapps (calc/price/tireService) — отдельные pools
``` ```
**Внимание:** stostayer-DB на `89.253.219.2` мёртвая. В host-копии (`C:\sites\stostayer\Web.config`) уже patched на новый `www.stostayer.ru,1433` (user `stayer_site`) с XML-escape `&amp;` в password — но это inert. При следующей попытке миграции — этот патч уже готов. 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]]
## На хосте параллельно (inert, не на prod-пути) - `stostayer.old`: `Data Source=localhost` (наш MSSQL контейнер)
См. [[windows-recovery-host]] "Inert" — `C:\sites\{snolla, stostayer, stostayer.old, snolla-identity-manager}` + IIS sites/pools `snolla, stostayer, stostayer.old` готовы к переключению traefik, но не активны.
## Запущенные docker контейнеры на хосте ## Запущенные docker контейнеры на хосте
@@ -67,32 +71,34 @@ updated: 2026-05-19
| **imgproxy-nginx** | `nginx:alpine` | 8788 | bind: `./nginx/cache`, `./nginx/nginx.conf` | | **imgproxy-nginx** | `nginx:alpine` | 8788 | bind: `./nginx/cache`, `./nginx/nginx.conf` |
| **elasticsearch** | `elasticsearch:7.10.1` | 9200 | bind: `./data` | | **elasticsearch** | `elasticsearch:7.10.1` | 9200 | bind: `./data` |
Все на docker network `proxy` (external) — это позволяет traefik резолвить `minio`, `elasticsearch`, `imgproxy-nginx` напрямую по docker DNS. Все на docker network `proxy` (external).
## Traefik routes (после revert 2026-05-19) ## Traefik routes (после attempt 2)
Все активные routes снова указывают на VM (как было до session). Backups сохранены для следующей попытки миграции. 11 cms yml репойнтены на host IIS:8089. 2 stayer yml — `.disabled`.
| File | Hosts | Backend | Статус | | File | Hosts | Backend | Статус |
|---|---|---|---| |---|---|---|---|
| snolla.yml | snolla.com + 10 subdomains | host.docker.internal:18080 → VM | active | | 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:18080 → VM | active (но CMS отдаёт 404 — известное) | | 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:18080 → VM | active | | labtools.yml | labtools.ru, www.labtools.ru | host.docker.internal:8089 | active → host IIS |
| labtoolspro.yml | labtools.pro, www.labtools.pro | host.docker.internal:18080 → VM | active | | labtoolspro.yml | labtools.pro, www.labtools.pro | host.docker.internal:8089 | active → host IIS |
| pilorama98.yml | pilorama98.ru, www.pilorama98.ru | host.docker.internal:18080 → VM | active | | pilorama98.yml | pilorama98.ru, www.pilorama98.ru | host.docker.internal:8089 | active → host IIS |
| tandemmebel.yml | tandemmebel.ru, www.tandemmebel.ru | host.docker.internal:18080 → VM | active | | tandemmebel.yml | tandemmebel.ru, www.tandemmebel.ru | host.docker.internal:8089 | active → host IIS |
| emspb.yml | emspb.ru, www.emspb.ru | host.docker.internal:18080 → VM | active | | 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:18080 → VM | active | | kupimknigi.yml | kupimknigi.spb.ru | host.docker.internal:8089 | active → host IIS |
| maljarka.yml | maljarka.tandemmebel.ru | host.docker.internal:18080 → VM | active | | maljarka.yml | maljarka.tandemmebel.ru | host.docker.internal:8089 | active → host IIS |
| sestech.yml | sestech.ru, www.sestech.ru | host.docker.internal:18080 → VM | active | | 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:18080 → VM | active | | isc-artmaterials.yml | ics-artmaterials.com, www.ics-artmaterials.com | host.docker.internal:8089 | active → host IIS (CMS-side 404 — known) |
| stostayer.yml | stostayer.snolla.com | host.docker.internal:18180 → VM:8080 | active | | **stostayer.yml.disabled** | stostayer.snolla.com | (n/a, route disabled) | **DISABLED**, host IIS :8090 локально |
| oldstostayer.yml | old.stostayer.ru | host.docker.internal:18181 → VM:8081 | active | | **oldstostayer.yml.disabled** | old.stostayer.ru | (n/a, route disabled) | **DISABLED**, host IIS :8091 локально |
**Backup-stamp файлы** (накопились — для следующей попытки): **Backup-stamp файлы** (накопились за обе попытки):
- `*.yml.bak-phase3-2026-05-19`original state до Phase 3 (всё указывает на VM). Это **именно та конфигурация что сейчас live** (свежескопировано в active). - `*.yml.bak-2026-05-19`самый ранний backup (до session).
- `*.yml.bak-hostip-2026-05-19`попытка переключения на `host.docker.internal:80` (создала loop, см. [[iis-migration-2026-05-19-postmortem]]). - `*.yml.bak-phase3-2026-05-19`rollback baseline (attempt 1 → revert state, всё на VM `:18080`).
- `stostayer.yml.bak-stayer-switch-2026-05-19`, `oldstostayer.yml.bak-stayer-switch-2026-05-19` — попытка stayer'ов на host :8090/:8091 (live теперь снова на VM). - `*.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-provider маршруты для инфраструктурных хостов:
@@ -106,18 +112,30 @@ updated: 2026-05-19
- `disk.yml` → 192.168.1.10:5005 (Synology disk на мёртвой синке) - `disk.yml` → 192.168.1.10:5005 (Synology disk на мёртвой синке)
- `dsm.yml` → 192.168.1.10:5000 (DSM мёртвой синки) - `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\<site>:(OI)(CI)M` рекурсивно на каждом site root.
## DNS ## DNS
Все домены остались указывать на **94.19.247.14** (public IP, статический). REGRU как registrar/DNS. Никаких DNS-изменений во время recovery не требовалось — only router NAT перенастроен. Все домены остались указывать на **94.19.247.14** (public IP, статический). REGRU как registrar/DNS.
## Backup инфраструктура ## Backup инфраструктура
Текущая (на момент 2026-05-19): Текущая (на момент 2026-05-19, после attempt 2):
- [[kreknin-synology]] держит Hyper Backup репо мёртвой синки (~430 GB). Новых бэкапов с recovered Windows-PC **НЕТ** — рабочее состояние на Windows-PC не бэкапится никуда. - [[kreknin-synology]] держит Hyper Backup репо мёртвой синки (~430 GB). Новых бэкапов с recovered Windows-PC **НЕТ**.
- Локально на Windows-PC: `C:\nas-recovery\vm-sites\` (~11 GB, дамп IIS sites из VM) — резерв если VM полностью умрёт. - Локально на 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 для нового рабочего состояния. **Дыра:** если Windows-PC сгорит — всё ляжет. Никакой репликации, никакого off-site backup для нового рабочего состояния.
## SSH ключи и доступ ## SSH ключи и доступ
@@ -129,14 +147,13 @@ updated: 2026-05-19
## Известные открытые баги ## Известные открытые баги
1. **X-Forwarded headers** не передаются от traefik в IIS → CMS делает редирект с `:4443` в URL. См. [[traefik-on-windows-docker-desktop]] Pitfall 5. 1. **X-Forwarded headers** не передаются от traefik в IIS → CMS делает redirect с `:4443` в URL. См. [[traefik-on-windows-docker-desktop]] Pitfall 5.
2. **rimiz.ru → 404**. CMS-side, не инфра — mapping host header → CMS-сайт в БД. 2. **rimiz.ru → 404**. CMS-side, не инфра.
3. **acme.json HTTP-01 renewal** будет фейлить для доменов с DNS не на нашем IP — нужен переезд на DNS-01 через REGRU до истечения сертификатов (~3 месяца). 3. **ics-artmaterials.com → 404**. Аналогично — CMS-side (`www.ics-artmaterials.com → 301 → ics-artmaterials.com → 404`).
4. **C:\inetpub\logs\** в VM растёт (6+ GB к recovery). На хосте та же беда если когда-то переключимся. 4. **acme.json HTTP-01 renewal** будет фейлить для доменов с DNS не на нашем IP → переезд на DNS-01 через REGRU до истечения сертификатов (~3 месяца).
5. **docker.sock provider в traefik** не работает — но не блокирует (всё через file-provider). См. [[traefik-on-windows-docker-desktop]] Pitfall 3. 5. **C:\inetpub\logs\** растёт — нужна ротация.
6. **stostayer DB в VM указывает на мёртвый 89.253.219.2** — stayer'ы публично возможно не работают полноценно (user сказал "стайеры и на VM не работает" — подтвердил). Host-копия уже patched на новый `www.stostayer.ru,1433`, в VM не правили. 6. **docker.sock provider в traefik** не работает — но не блокирует (всё через file-provider). См. [[traefik-on-windows-docker-desktop]] Pitfall 3.
7. **MinIO/Azure storage** в CMS — вопрос пользователем снят, оставлено как есть. 7. **WinHTTP proxy на хосте strips response headers** для `curl.exe http://localhost:...` — для loop-detect/IIS confirmation использовать `docker exec traefik wget` или `Invoke-WebRequest`. См. [[docker-host-loopback-detect]].
8. **VM network adapter "виснет"** периодически (recipe `ipconfig /release /renew` через guestcontrol в [[vbox-windows-stability-tuning]]). Подтверждено ещё раз в сессии 2026-05-19.
## Single Points of Failure ## Single Points of Failure
@@ -144,7 +161,7 @@ updated: 2026-05-19
- Один публичный IP / провайдер - Один публичный IP / провайдер
- Один WiFi-канал - Один WiFi-канал
- Один OpenWRT-роутер - Один OpenWRT-роутер
- **Одна VBox VM `snolla-recovery`** — single instance, обслуживает весь CMS-трафик (после revert) - Один **host IIS instance** обслуживает весь cms-трафик (VM остаётся parallel fallback ещё 24-48h)
- Один MSSQL контейнер (single primary, нет replica) - Один MSSQL контейнер (single primary, нет replica)
- Один MinIO (single drive, не distributed) - Один MinIO (single drive, не distributed)