wiki(ingest): RUVDS IIS migration + daily backup pipeline

- entities/ruvds-iis-host (NEW) — 80.64.31.36, Win Server 2025 Core,
  25 SNI HTTPS bindings, 2/24 hostnames DNS-flipped
- sources/iis-migration-to-ruvds-2026-05-23 (NEW) — chronology,
  SSH/scp pivot после home-ISP outbound 445 block
- sources/ruvds-backup-daily-kreknin-2026-05-24 (NEW) — rclone+SFTP
  SYSTEM task daily 04:30, ntfy общий канал
- concepts/traefik-acme-json-to-iis-cert-import (NEW) — PFX + SNI
  recipe
- concepts/windows-server-2025-core-bootstrap — SMB deprecate,
  HTTP middlebox warning, HTTP/2 note; backup/cert open-Qs закрыты
- entities/windows-recovery-host — partial-cutover state,
  imgproxy SPOF carve-out, tandemmebel indefinitely здесь
- overview / index / log — catalog refresh

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-24 23:31:14 +03:00
parent b7b8e27a27
commit 22786e1865
9 changed files with 492 additions and 8 deletions

View File

@@ -0,0 +1,124 @@
---
title: Экспорт LE certs из traefik acme.json в IIS (PFX + SNI bindings)
type: concept
tags: [traefik, iis, letsencrypt, certs, pfx, sni, windows]
sources: [../sources/iis-migration-to-ruvds-2026-05-23.md]
updated: 2026-05-24
---
# traefik `acme.json` → IIS cert import
Recipe для one-shot переноса Let's Encrypt certs из traefik `acme.json` (single-file ACME store) в IIS на Windows host с SNI multi-binding'ами. Использован при миграции [[../entities/ruvds-iis-host]] 2026-05-23 для 14 LE certs → 25 HTTPS hostnames bound via SNI. **Это не renewal pipeline**, а bootstrap-перенос — для long-term renewal recommend `win-acme` standalone на IIS host'е (см. footnote).
## Когда применять
- Migration: traefik-on-A → IIS-on-B, certs нужны до того как ACME-validation с нового host'а станет возможной (DNS ещё указывает на старый host, HTTP-01 challenge bounce'нется).
- Bootstrap пилотного IIS-сервера с готовыми certs для smoke testing **до** DNS swap'а.
**Не применять для regular renewal** — каждый renewal цикл traefik будет генерировать новый cert, и manual re-export не масштабируется. После full DNS swap → `win-acme` HTTP-01 на IIS-side directly.
## Входные данные
- `acme.json` — обычно в `<traefik-data>/letsencrypt/acme.json`. Содержит JSON с массивом `Certificates[].domain.main`, `.sans`, `.certificate` (base64 PEM bundle), `.key` (base64 PEM private key).
- Target IIS host с PowerShell + OpenSSL (для cert conversion) + access to `Cert:\LocalMachine\My` store.
## Recipe (per cert)
### 1. Распаковать пару PEM из acme.json
```powershell
$acme = Get-Content C:\path\to\acme.json | ConvertFrom-Json
# Resolver key — обычно "letsencrypt" или имя из traefik.yml
$resolver = $acme.letsencrypt
foreach ($cert in $resolver.Certificates) {
$domain = $cert.domain.main
$sans = $cert.domain.sans # может быть $null
$safeName = $domain -replace '\*','wildcard'
[System.Convert]::FromBase64String($cert.certificate) | Set-Content "C:\temp\$safeName.crt" -AsByteStream
[System.Convert]::FromBase64String($cert.key) | Set-Content "C:\temp\$safeName.key" -AsByteStream
}
```
### 2. Convert PEM pair → PFX (OpenSSL)
```powershell
$pfxPass = 'pfximport' # temp passphrase, only for Import step
& openssl pkcs12 -export `
-inkey "C:\temp\$safeName.key" `
-in "C:\temp\$safeName.crt" `
-out "C:\temp\$safeName.pfx" `
-name $domain `
-password "pass:$pfxPass"
```
### 3. Import PFX → `Cert:\LocalMachine\My`
```powershell
$securePass = ConvertTo-SecureString $pfxPass -AsPlainText -Force
$imported = Import-PfxCertificate `
-FilePath "C:\temp\$safeName.pfx" `
-CertStoreLocation 'Cert:\LocalMachine\My' `
-Password $securePass
# $imported.Thumbprint — нужен для следующего шага
```
### 4. SNI binding в IIS (per hostname)
Один cert может покрывать несколько SANs — для каждого hostname создать **separate binding** с **SslFlags=1 (SNI)**:
```powershell
$allHosts = @($domain) + @($sans | Where-Object { $_ })
foreach ($hostname in $allHosts) {
# 4a. Create binding without cert
New-WebBinding -Name 'snolla' `
-IPAddress '*' -Port 443 -Protocol 'https' `
-HostHeader $hostname -SslFlags 1 # 1 = SNI
# 4b. Attach cert via thumbprint (нужен netsh-стиль через IIS:\)
$binding = Get-WebBinding -Name 'snolla' -Port 443 -HostHeader $hostname
$binding.AddSslCertificate($imported.Thumbprint, 'My')
}
```
> **SslFlags=1 обязателен.** Без SNI один port 443 = один cert per IP — Windows откажется bind'ить второй cert на тот же `*:443`. С SNI можно навесить ~unlimited hostnames на один `*:443`.
## Verification
```powershell
# Список bindings:
Get-WebBinding -Port 443 | Format-Table protocol, bindingInformation, sslFlags
# Сертификат за binding:
$binding.attributes['certificateHash'].Value # thumbprint
$binding.attributes['certificateStoreName'].Value # "My"
# External smoke (с другого host'а — home middlebox может mangle Host header):
curl -k --resolve "$hostname:443:80.64.31.36" "https://$hostname/" -I
# Должен вернуть chain LE R13 + correct Subject CN
```
HTTP/2 negotiate'ится auto (IIS 10 + Windows Server 2019+ → ALPN supported из коробки).
## Gotchas
- **`acme.json` permission** на Linux: `chmod 600`, traefik не запустится с другим. На Windows copy-out для conversion'а — нужны Admin perms.
- **PEM bundle order** в acme.json: `certificate` поле содержит leaf + chain (Let's Encrypt R13 + ISRG Root X1). OpenSSL pkcs12 импортит весь bundle корректно — IIS отдаст полный chain.
- **PFX password** — только для transit между PEM и cert store, после import не используется. `pfximport` (или любой placeholder) — OK; не путать с pass для encrypted PFX-on-disk storage.
- **HostHeader case-sensitivity** в `New-WebBinding`: IIS lowercase'ит автоматически, но скрипт принимай canonical lowercase.
- **Wildcard SANs:** если cert `*.example.com` — нужно отдельный binding для каждого конкретного subdomain'а (Windows не делает wildcard matching на binding'ах автоматически). Либо использовать default-cert на listener'е (`netsh http add sslcert`) — но это break'нет multi-cert SNI scenario.
- **Cert duplicates:** повторный import того же cert'а создаёт duplicate в `Cert:\LocalMachine\My`. Idempotency — check thumbprint exists перед import'ом.
- **`netsh http show sslcert`** — для low-level audit что binding'и реально привязаны (PowerShell `Get-WebBinding` иногда показывает stale state после ручных правок IIS Manager'ом).
## Limits / когда recipe мал
- **>30 hostnames** — `Import-PfxCertificate` + `New-WebBinding` цикл становится медленным (~5 sec/cert). Batch'ить через `appcmd add binding /commit:apphost`.
- **TLS 1.3** — IIS 10 на Server 2022+ supports; на Server 2019 — Edge case. Не зависит от recipe — от Windows feature.
- **Renewal** — этот recipe **не покрывает**. Variant A (win-acme HTTP-01 standalone) предпочтительнее, см. [[../sources/iis-migration-to-ruvds-2026-05-23]] Outstanding (post-soak).
## Cross-refs
- Use case: [[../sources/iis-migration-to-ruvds-2026-05-23]] Phase 6
- Source acme.json расположение: traefik-on-windows-host setup, см. [[traefik-on-windows-docker-desktop]]
- Long-term replacement: `win-acme` (wacs.exe) standalone — пока не documented as concept; reference https://www.win-acme.com/
- Bootstrap-host где recipe был применён: [[../entities/ruvds-iis-host]]

View File

@@ -9,6 +9,8 @@ related: [[iis-migration-2026-05-19-postmortem]], [[recovery-architecture-snapsh
Из коробки на RUVDS (2GB RAM, 30GB HDD, Win Server 2025 Core, RDP-only) машина **не готова** ни принимать файлы по SMB, ни хостить IIS — стандартный сценарий «купил, RDP'нулся, robocopy'нул» не работает. Документ фиксирует дефолтное состояние, default-blockers, и матрицу transfer-методов для переноса content'а с windows-recovery-host.
> **Update 2026-05-24 (post-migration):** SMB transfer-метод **deprecated** — outbound TCP/445 блокирует residential RU ISP (стандартная анти-worm политика). Canonical transfer-метод = **SSH/scp** (см. §«Update 2026-05-24» ниже). HTTP smoke с home-network также unreliable — DPI/transparent proxy mangles Host header.
## Дефолтное состояние fresh Win Server 2025 Core
| Компонент | Дефолт | Нужно для IIS-host'инга |
@@ -48,7 +50,7 @@ Test-NetConnection -ComputerName <ruvds-ip> -Port 445
| **SFTP** (OpenSSH server feature) | `Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0` + start sshd + FW 22 | works с любого Linux/Mac source; ключи безопасно | extra service surface; sshd default config иногда permissive |
| **HTTP PUT через временный traefik+webdav** | overkill для bootstrap | reusable для последующих deploy'ев | сначала нужен IIS/nginx running — но IIS ещё не deployed → chicken-and-egg |
**Recommendation для IIS migration:** SMB inbound с source-IP whitelist. Самый быстрый для 11 sites × ~1 GB; native robocopy /Z поддерживает interrupt-resume; FW rule убирается после migration cutover.
**~~Recommendation для IIS migration: SMB inbound с source-IP whitelist~~** — **deprecated 2026-05-24**, см. §«Update 2026-05-24» ниже. Текущий canonical — **SSH/scp**.
```powershell
# На RUVDS (RDP-сессия, PowerShell):
@@ -96,9 +98,68 @@ net use \\<ruvds-ip>\sites /delete
- **LE certs:** если IIS будет terminate'ить TLS напрямую — `win-acme` (wacs.exe) standalone-friendly на Core. Альтернатива — traefik-on-RUVDS перед IIS, но это лишняя layer для 11 sites.
- **Backup strategy для RUVDS:** unsolved — RUVDS native snapshots = VDS-snapshot-level, не file-level. Daily rsync sites+IIS config → kreknin (расширить `vds-backup-rsync-kreknin` на источник RUVDS) — отдельная chore-task после успешного cutover.
## Update 2026-05-24 — SMB deprecate + HTTP middlebox + HTTP/2
### SMB deprecated — home-ISP блокирует outbound 445
После выполнения bootstrap-чеклиста выше (FW 445 + SMB share созданы на RUVDS) **TCP/445 всё равно не reachable с source**. Root cause — residential RU ISP блокируют outbound 445 (стандартная анти-worm политика). FW scoping на RUVDS-стороне корректен, проблема на source side и **не fixable** без VPN.
> **Canonical transfer-метод теперь — SSH/scp.** Pivot zaprotokolirovan в [[../sources/iis-migration-to-ruvds-2026-05-23]] Phase 2-3.
Setup (на RUVDS):
```powershell
# OpenSSH server feature (если ещё не установлен):
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd
Set-Service -Name sshd -StartupType Automatic
# FW 22 scoped к source IP (не глобально):
New-NetFirewallRule -DisplayName "ssh-from-source" -Direction Inbound `
-Protocol TCP -LocalPort 22 -RemoteAddress <source-public-ip> -Action Allow
# Deploy pubkey для administrators (правильный ACL обязателен):
$pub = "ssh-ed25519 AAAA... source-comment"
Set-Content C:\ProgramData\ssh\administrators_authorized_keys $pub
icacls C:\ProgramData\ssh\administrators_authorized_keys /inheritance:r `
/grant 'SYSTEM:(F)' /grant 'BUILTIN\Administrators:(F)'
```
Source-side transfer:
```powershell
scp -i ~/.ssh/<key> -r C:\sites\snolla `
Administrator@<ruvds-ip>:C:/sites/
```
8.66 GB / 44725 files за ~25 мин на 5 MB/s home uplink. Не parallel, но resume через `scp -r` после прерывания не работает — нужен `rsync` (нет на Core) или restart с нуля. Для production cutover это OK; для multi-GB content с unreliable link — `rclone copy` (см. [[../sources/ruvds-backup-daily-kreknin-2026-05-24]]).
После cutover — `Remove-NetFirewallRule -DisplayName 'ssh-from-source'`, `Remove-Item C:\ProgramData\ssh\administrators_authorized_keys`.
### HTTP middlebox в home network mangles Host header
Local smoke testing с home network через external IP `curl -H "Host: real-hostname.example" http://<ruvds-ip>/` **возвращает default catch-all content**, не per-tenant. Inside RUVDS (loopback) — корректно. С другой сети (VDS, mobile uplink) — корректно. SSH tunnel `localhost:N → ruvds:80` — корректно.
> **Conclusion:** home-ISP / OpenWRT DPI / transparent proxy mangles Host header для **direct external HTTP**. Real end-users из других сетей не affected. Для smoke testing — обязательно SSH tunnel либо smoke с VDS/mobile.
### HTTP/2 auto-negotiates на IIS 10 + Server 2022/2025
ALPN supported из коробки; `curl --http2 https://...` → `HTTP/2 200`. Не требует config'а.
### Backup pipeline — закрыт
`Backup strategy для RUVDS` в исходном «Gotcha-fineprint» — **закрыт** 2026-05-24: rclone + SFTP → kreknin daily 04:30 MSK. См. [[../sources/ruvds-backup-daily-kreknin-2026-05-24]] для recipe + scripts.
### Cert import recipe — закрыт
Перенос LE certs из traefik `acme.json` → IIS PFX → SNI bindings вынесен в отдельный recipe-концепт: [[traefik-acme-json-to-iis-cert-import]].
## Cross-refs
- Driver для миграции: [[future-resilient-architecture-goals]] §Workshop pass 1 → IIS-track «вынести IIS с windows-recovery-host чтобы убрать SPOF домашней машины».
- Vendor selection: `.tasks/windows-hosting-vendor-research.md` (🟢 closed 2026-05-22 — RUVDS выбран).
- Mid-impl task: `.tasks/iis-migration-to-ruvds.md` (🟡 paused 2026-05-23 — этот концепт зафиксирован после failed-robocopy инцидента).
- Live RUVDS host: [[../entities/ruvds-iis-host]].
- Migration chronology: [[../sources/iis-migration-to-ruvds-2026-05-23]].
- Backup chronology: [[../sources/ruvds-backup-daily-kreknin-2026-05-24]].
- Cert import recipe: [[traefik-acme-json-to-iis-cert-import]].
- Source-host postmortem: [[iis-migration-2026-05-19-postmortem]] — что было при первой миграции снолла-recovery → нативный IIS.

View File

@@ -0,0 +1,82 @@
---
title: RUVDS IIS Host (Windows Server 2025 Core) — 80.64.31.36
type: entity
tags: [hardware, vds, ruvds, windows, iis, cms, snolla, kupimknigi]
sources: [../sources/iis-migration-to-ruvds-2026-05-23.md, ../sources/ruvds-backup-daily-kreknin-2026-05-24.md]
updated: 2026-05-24
---
# RUVDS IIS Host
Облачный Windows-VDS у [RUVDS](https://ruvds.com), DC Королёв. Куплен 2026-05-23 как destination для миграции IIS-хостинга с [[windows-recovery-host]] — closing SPOF домашней машины для prod CMS сайтов (snolla CMS multi-tenant). Это **отдельный VDS** от [[vds-kzntsv]] (Rusonyx Linux, инфра-стек): RUVDS = только IIS catch-all для CMS hostnames, Rusonyx VDS = gitea/verdaccio/registry/DB park.
## Hardware / tariff
- **Vendor:** RUVDS (https://ruvds.com)
- **Tariff:** Windows Server 2025 Core, 2 GB RAM, 30 GB HDD, 1 IPv4 (DC Королёв)
- **OS:** Windows Server 2025 Core (GUI-less, RDP-only management)
- **IPv4:** `80.64.31.36`
- **Activated:** 2026-05-23
## Доступ
- **RDP:** `mstsc /admin``80.64.31.36:3389` (открыт из коробки)
- **SSH:** `ssh -i <key> Administrator@80.64.31.36` (OpenSSH.Server enabled; FW 22 был scoped к source IP на время migration, после cutover — cleanup pending)
- **Креды:** `pass show ruvds-iis/full-env` (canonical secret store; раньше лежали plaintext в `.secrets/ruvds-iis.env` — вынесены ретроспективно, см. [[../sources/iis-migration-to-ruvds-2026-05-23]] Decisions log 2026-05-23 09:37)
## Установленный стек
- **IIS 10** (`Web-Server` + sub-features + management tools)
- **.NET Framework 4.8** (verified ≥ 528040)
- **URL Rewrite Module 2.1** (msiexec offline)
- **OpenSSH.Server** (Windows capability; sshd running; FW 22 source-scoped)
- **rclone v1.74.2** (`C:\Program Files\rclone\rclone.exe`) — backup pipeline
- **Defender FW:** inbound 80/443 (Any), 22 (source-IP), 3389 (Any); 445 закрыт (SMB transfer-метод deprecated, см. [[../concepts/windows-server-2025-core-bootstrap]])
## Что хостит
| Site | physicalPath | Bindings | Notes |
|---|---|---|---|
| `snolla` (AppPool `snolla`, .NET v4.0 Integrated, ApplicationPoolIdentity) | `C:\sites\snolla\` (8.66 GB / 44725 files, copied 2026-05-23 via SSH/scp) | `*:80:` catch-all HTTP + 25× `*:443:<hostname>` HTTPS SNI | catch-all для всех CMS hostnames через multi-tenant routing в самом CMS |
**25 HTTPS hostnames bound via SNI** (LE certs imported from traefik `acme.json`, valid до 2026-07-22, R13):
-`emspb.ru` / `www.emspb.ru` — DNS flipped 2026-05-24 ~12:00
-`kupimknigi.spb.ru` — DNS flipped 2026-05-24 ~00:00 (pilot)
- ⏳ 22 more in queue (`pilorama98.ru`/www, `labtools.ru`/www, `labtools.pro`/www, 12× `*.snolla.com`, `rimiz.ru`/www, `maljarka.tandemmebel.ru`, etc.) — pending DNS TTL drop в reg.ru (TTL=86400 пока)
-`tandemmebel.ru` / `www.tandemmebel.ru` — scope-narrowed 2026-05-24, остаются на windows-IIS на неопределённый срок
**Degraded (CMS-side, не migration defect):** `maljarka.tandemmebel.ru`, `rimiz.ru`/www, `rimiz.snolla.com` — возвращают 502/404 (pre-existing dead-routes от [[../sources/iis-host-migration-2026-05-19]] cleanup; на source IIS:8089 тоже не работают).
## Ключевые папки
- `C:\sites\snolla\` — IIS site content (8.66 GB)
- `C:\Windows\System32\inetsrv\config\applicationHost.config` — IIS config
- `C:\ProgramData\backup\` — backup pipeline (rclone.conf, kreknin-key, run.ps1, ntfy-token.txt) — ACL: SYSTEM + Administrators only
- `C:\ProgramData\ssh\administrators_authorized_keys` — temp pubkey для migration scp; **cleanup pending** post full cutover
- `scripts/iis-migration-to-ruvds/01-ruvds-bootstrap.ps1` (в admin repo) — idempotent bootstrap скрипт
## Backup
Daily 04:30 MSK → [[kreknin-synology]] via rclone+SFTP. Снимаются: `C:\sites\snolla\`, `applicationHost.config`, `Backup-WebConfiguration` snapshot, exported PFX certs, `C:\ProgramData\ssh\`. Retention 7 daily. ntfy `vds-backup` topic (общий с VDS backup). Smoke run #1 (2026-05-24 11:46:51) — green. См. [[../sources/ruvds-backup-daily-kreknin-2026-05-24]].
## Известные риски / SPOF
- **Image-pipeline SPOF:** RUVDS IIS вызывает `imgproxy.kzntsv.site` который **всё ещё** на [[windows-recovery-host]] — если домашняя машина гаснет, картинки rendering падает (HTML отдаётся OK с RUVDS). Verified post-migration `Test-NetConnection imgproxy.kzntsv.site -Port 443` = OK. Не closing полный SPOF — defer (Option B local nginx-relay / Option D decompile DLL, см. [[../concepts/iis-cutover-to-vds-services]]).
- **2 GB RAM tight:** w3wp ~330 MB cold start. Monitor under prod load — возможно потребуется `RecyclingPeriodicRestartMemory 200MB` per pool.
- **LE renewal pipeline отсутствует:** certs истекают 2026-07-22 (~60 дней window). Pending — `win-acme` standalone с HTTP-01 после full DNS swap (см. [[../sources/iis-migration-to-ruvds-2026-05-23]] Open questions).
- **Home-network HTTP middlebox** (DPI/transparent proxy в OpenWRT/ISP) — mangles Host header для direct external HTTP smoke testing. Real end-users из других сетей не affected. См. [[../concepts/windows-server-2025-core-bootstrap]] Update 2026-05-24.
## Vendor onboarding
В отличие от [[../concepts/rusonyx-vps-onboarding-quirks]] (VNC console, dpkg prompts) — RUVDS Windows из коробки RDP-ready, VPN/VNC quirks не зафиксировано. Bootstrap-recipe в [[../concepts/windows-server-2025-core-bootstrap]].
## Cross-refs
- Source-host (где IIS был раньше): [[windows-recovery-host]]
- VDS со shared DBs / MSSQL backend для IIS: [[vds-kzntsv]]
- Backup target: [[kreknin-synology]]
- Migration chronology: [[../sources/iis-migration-to-ruvds-2026-05-23]]
- Backup chronology: [[../sources/ruvds-backup-daily-kreknin-2026-05-24]]
- Bootstrap recipe: [[../concepts/windows-server-2025-core-bootstrap]]
- Cert import recipe: [[../concepts/traefik-acme-json-to-iis-cert-import]]
- Driver / SPOF rationale: [[../concepts/future-resilient-architecture-goals]]

View File

@@ -1,9 +1,9 @@
---
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
tags: [hardware, windows, docker, virtualbox, iis, recovery, imgproxy]
sources: [../sources/nas-recovery-session-2026-05-18.md, ../sources/iis-migration-to-ruvds-2026-05-23.md]
updated: 2026-05-24
---
# Windows Recovery Host
@@ -88,4 +88,19 @@ updated: 2026-05-19
## Что должно случиться, если этот PC погаснет
- **Всё** — все сайты лягут. **Single point of failure** — главное замечание для [[future-resilient-architecture-goals]].
- **Image-pipeline (imgproxy) ляжет для всех сайтов** — RUVDS IIS rendering'ит HTML самостоятельно, но картинки идут через `imgproxy.kzntsv.site` который **всё ещё** на этой машине. Partial SPOF после миграции IIS.
- **`tandemmebel.ru` + www** — лежат полностью (scope-narrowed 2026-05-24, остаются здесь indefinitely).
- **Остальные ~24 CMS hostnames** — degrade gracefully после full DNS swap на RUVDS (HTML работает, картинки нет). Pre-swap — DNS всё ещё указывает сюда → полный outage до swap'а.
- **MSSQL / MinIO** — уже мигрированы на [[vds-kzntsv]] (2026-05-22), здесь только containers running в idle (могут быть decommission'ed).
- Long-term goal — closing image-pipeline SPOF (Option B local nginx-relay / Option D decompile DLL), см. [[future-resilient-architecture-goals]] + [[../concepts/iis-cutover-to-vds-services]].
## IIS partial-cutover на RUVDS (2026-05-24)
IIS site `snolla` **частично мигрирован** на [[ruvds-iis-host]] (`80.64.31.36`). State 2026-05-24:
- ✅ DNS flipped: `kupimknigi.spb.ru` (~00:00), `emspb.ru` + `www.emspb.ru` (~12:00). Public resolver cache держит старое до TTL=86400 expiry.
-В очереди (pending TTL drop до 300s в reg.ru): 22 hostnames — pilorama98/www, labtools.ru/www, labtools.pro/www, 12× *.snolla.com, rimiz.ru/www, maljarka.tandemmebel.ru, etc.
- ⛔ Останутся здесь indefinitely: `tandemmebel.ru` + `www.tandemmebel.ru` (scope narrow).
- ⚠ Source IIS:8089 + traefik routes для CMS-hostnames **всё ещё running** — rollback path на ~1 неделю soak. После — decommission (но не traefik сам, много других routes).
Подробная chronology — [[../sources/iis-migration-to-ruvds-2026-05-23]]. Driver: [[future-resilient-architecture-goals]].

View File

@@ -11,6 +11,7 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever
- [dead-synology-diskstation](entities/dead-synology-diskstation.md) — мёртвая Synology DiskStation (source NAS)
- [kreknin-synology](entities/kreknin-synology.md) — Kreknin Synology (backup target + DDNS)
- [openwrt-router](entities/openwrt-router.md) — OpenWRT Router (192.168.1.1)
- [ruvds-iis-host](entities/ruvds-iis-host.md) — RUVDS IIS Host (Win Server 2025 Core, 80.64.31.36) — CMS catch-all destination
- [snolla-recovery-vm](entities/snolla-recovery-vm.md) — Snolla Recovery VM (VirtualBox, savestate'нута 2026-05-21 после 36h soak)
- [vds-kzntsv](entities/vds-kzntsv.md) — VDS kzntsv (Rusonyx 160 NVMe cloud server)
- [windows-recovery-host](entities/windows-recovery-host.md) — Windows Recovery Host (рабочий PC пользователя)
@@ -34,6 +35,7 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever
- [recovery-architecture-snapshot](concepts/recovery-architecture-snapshot.md) — текущая recovery architecture (2026-05-19/21, attempt 2)
- [registry-gc-mount-and-modify-flag](concepts/registry-gc-mount-and-modify-flag.md) — Docker Registry GC mount layout + `-m` flag
- [rusonyx-vps-onboarding-quirks](concepts/rusonyx-vps-onboarding-quirks.md) — Rusonyx VPS onboarding quirks (Astra Облако / myvm.rusonyx.ru)
- [traefik-acme-json-to-iis-cert-import](concepts/traefik-acme-json-to-iis-cert-import.md) — Экспорт LE certs из traefik acme.json в IIS (PFX + SNI bindings)
- [traefik-file-watch-wsl2-broken](concepts/traefik-file-watch-wsl2-broken.md) — Traefik file-watch broken под Docker Desktop Windows (WSL2 9p mount)
- [traefik-on-windows-docker-desktop](concepts/traefik-on-windows-docker-desktop.md) — Traefik на Windows Docker Desktop — нюансы
- [traefik-tcp-passthrough-vs-starttls](concepts/traefik-tcp-passthrough-vs-starttls.md) — Traefik TCP passthrough vs STARTTLS-protocols
@@ -49,5 +51,7 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever
## Sources
- [iis-host-migration-2026-05-19](sources/iis-host-migration-2026-05-19.md) — IIS Host Migration Session 2026-05-19 chronology
- [iis-migration-to-ruvds-2026-05-23](sources/iis-migration-to-ruvds-2026-05-23.md) — IIS migration to RUVDS — session 2026-05-23/24 (SSH/scp pivot, 25 SNI bindings, partial DNS cutover)
- [nas-recovery-session-2026-05-18](sources/nas-recovery-session-2026-05-18.md) — NAS Recovery Session 2026-05-18/19 chronology
- [ruvds-backup-daily-kreknin-2026-05-24](sources/ruvds-backup-daily-kreknin-2026-05-24.md) — RUVDS daily backup → kreknin pipeline standup 2026-05-24 (rclone+SFTP, SYSTEM task)
- [vds-kzntsv-bootstrap-2026-05-20](sources/vds-kzntsv-bootstrap-2026-05-20.md) — VDS bootstrap session 2026-05-20 chronology

View File

@@ -21,3 +21,5 @@ Append-only log of wiki operations (ingests, promotions, lints, migrations).
## [2026-05-23] ingest | concepts/windows-server-2025-core-bootstrap — default-blockers (SMB closed, IIS/URL-Rewrite/.NET unverified) + transfer-методов матрица (RDP-redirect / SMB / WinRM / SFTP); recommendation = SMB inbound с source-IP whitelist на время migration. Source: failed-robocopy инцидент 2026-05-23 18:08 (.tasks/iis-migration-to-ruvds.md Decisions log).
## [2026-05-24] ingest | concepts/books-ssh-access — SSH access audit на shared VDS pre-cutover Фазы 3 tenant-split. Retained keys table (1 key, vitya core dev), removed cosmetic dead root key, sshd hardening verified via `sshd -T` (not raw config), fail2ban active 2670 failed/37 banned, only vitya@94.19.247.14 в access log last 7 days. Source: .tasks/books-ssh-audit-shared-vds.md.
## [2026-05-24] ingest | RUVDS IIS migration + backup pipeline — entities/ruvds-iis-host (NEW, 80.64.31.36 Win Server 2025 Core, 25 SNI bindings, 2/24 hostnames DNS-flipped) + sources/iis-migration-to-ruvds-2026-05-23 (NEW, SSH/scp pivot после SMB-block by home-ISP) + sources/ruvds-backup-daily-kreknin-2026-05-24 (NEW, rclone+SFTP SYSTEM task daily 04:30) + concepts/traefik-acme-json-to-iis-cert-import (NEW, PFX+SNI recipe) + UPDATE concepts/windows-server-2025-core-bootstrap (SMB deprecate, HTTP middlebox warning, HTTP/2 note, backup-strategy + cert-import закрыты) + UPDATE entities/windows-recovery-host (IIS partial-cutover state, imgproxy SPOF carve-out) + UPDATE overview (RUVDS line). Sources: .tasks/iis-migration-to-ruvds.md, .tasks/ruvds-backup-daily-kreknin.md.

View File

@@ -3,9 +3,10 @@
Operational + roadmap workspace for personal-and-client infrastructure stack:
- **VDS** (`vds.kzntsv.site`, Rusonyx) — gitea, verdaccio, registry, shared DB park, ntfy, traefik+portainer
- **RUVDS IIS host** (`80.64.31.36`, Win Server 2025 Core) — CMS multi-tenant IIS site `snolla` (catch-all для 24+ hostnames), partial-cutover idёт 2026-05-24
- **NAS** (`kreknin`, Synology DSM) — backup target, Hyper Backup repo, secondary services
- **Windows recovery host** — current CMS prod host (IIS + traefik + docker), to be replaced as part of fault-tolerance roadmap
- **OpenWRT router** — NAT 80/443 → traefik
- **Windows recovery host** — раньше CMS prod IIS (мигрирует на RUVDS), всё ещё хостит imgproxy + `tandemmebel.ru` + parallel running docker/traefik как rollback
- **OpenWRT router** — NAT 80/443 → traefik (на windows-recovery-host)
## Current state

View File

@@ -0,0 +1,114 @@
---
title: IIS migration to RUVDS — session 2026-05-23/24
type: source
tags: [iis, ruvds, migration, snolla, cms, ssh, scp, smb, dns, le-certs, sni]
ingested: 2026-05-24
raw_path: ../../.tasks/iis-migration-to-ruvds.md
updated: 2026-05-24
---
# IIS migration to RUVDS — 2026-05-23/24
Перенос IIS-хостинга CMS-сайтов с [[../entities/windows-recovery-host]] (DESKTOP-NSEF0UK, дом, SPOF) на [[../entities/ruvds-iis-host]] (Win Server 2025 Core, RUVDS, 80.64.31.36). Pre-req: MSSQL+MinIO уже мигрированы на [[../entities/vds-kzntsv]] (см. [[../concepts/mssql-on-vds]], [[../concepts/minio-imgproxy-on-vds]]).
Источник истины — `.tasks/iis-migration-to-ruvds.md`. Live state RUVDS-хоста — [[../entities/ruvds-iis-host]].
## Scope finalize (2026-05-24)
Только 1 IIS site `snolla` (catch-all для ~26 hostnames через CMS multi-tenant routing) — 8.66 GB. `stostayer` уже на external MSSQL (не наш scope), `stostayer.old` local-only (defer), `snolla-identity-manager` dead conn-string (defer). `tandemmebel.ru` + www — **остаются на windows-IIS** на неопределённый срок (scope-narrow 2026-05-24). Из 25 HTTPS bindings — 2 хоста уже DNS-flipped, 22 в очереди после снижения TTL.
## Хронология
### Phase 0 — vendor selection (2026-05-22)
Закрыт research-task `windows-hosting-vendor-research` 🟢 — RUVDS выбран. Сравнение: Rusonyx (Linux only для нужного формата), Selectel, FirstVDS, Beget. Critical constraints: RDP-доступ, .NET Framework 4.8 native, IIS 10, external MSSQL/MinIO connectivity (на VDS после Фазы 2).
### Phase 1 — purchase + secrets discipline (2026-05-23 09:37)
RUVDS активирован, RDP creds сохранены изначально plaintext в `.secrets/ruvds-iis.env` в repo tree → нарушение etap-2 secrets-discipline. **Ретроспективно вынесены** в `pass show ruvds-iis/full-env`, `.secrets/` + `*.env` + `*-log.txt` + `*-size.txt` добавлены в `.gitignore`.
### Phase 2 — failed-robocopy → SMB-block discovery (2026-05-23 18:08 → 22:30)
**18:08:** Попытка robocopy через UNC `\\80.64.31.36\sites\snolla\` упала exit 16. Initial diagnostics: SMB share не создан + FW 445 не открыт. Создан concept [[../concepts/windows-server-2025-core-bootstrap]] с default-blockers + transfer-методов матрицей.
**22:30 (session-recovery):** После выполнения bootstrap'а (FW+share созданы) SMB **всё равно** не reachable — TCP/445 не выходит **с home-ISP**. **Real root cause: outbound 445 блокирует ISP** (стандартная анти-worm политика residential провайдеров RU). FW scoping на RUVDS корректен.
> **Решение:** SMB recommendation в bootstrap-концепте **deprecated**. SSH/scp = canonical transfer-метод. Концепт обновлён, см. [[../concepts/windows-server-2025-core-bootstrap]] Update 2026-05-24.
### Phase 3 — SSH/scp transfer (2026-05-23 22:35 → 23:13)
OpenSSH.Server на RUVDS уже был установлен ранее (admin'ом), sshd running. Открыт FW 22 scoped к source IP, deployed ed25519 pubkey в `C:\ProgramData\ssh\administrators_authorized_keys` (правильный ACL — SYSTEM + Administrators only).
`scp -r C:\sites\snolla → C:/sites/`**~25 мин** (8.66 GB / 5 MB/s home uplink), exit 0, count+size MATCH (44725 files / 9 302 398 880 bytes).
### Phase 4 — IIS recreate (2026-05-23 23:18)
Default Web Site удалён. AppPool `snolla` (.NET v4.0, Integrated, ApplicationPoolIdentity), Website `snolla` с physicalPath `C:\sites\snolla` + catch-all binding `*:80:`. ACL — `IIS APPPOOL\snolla` + `IIS_IUSRS` Read на 46150 file entries. Local smoke (loopback + `Host: kupimknigi.spb.ru`) — 200 OK с правильным title.
### Phase 5 — HTTP middlebox surprise (2026-05-23 23:25)
External smoke через home network: все 8 hostnames вернули **`"SNOLLA | Cloud CMS" default`** (28 406 bytes), не per-tenant content. Внутри RUVDS (loopback) — корректно. SSH tunnel localhost:8888→RUVDS:80 → correct. Тест из VDS (другая сеть) → correct.
> **Conclusion: home-side outbound HTTP mutation** — DPI/transparent proxy в OpenWRT/ISP path mangles Host header. Real end-users из других сетей не пострадают. Affected — только local smoke testing.
Зафиксировано в [[../concepts/windows-server-2025-core-bootstrap]] Update 2026-05-24.
### Phase 6 — HTTPS SNI bindings (2026-05-23 23:30)
Извлечены 14 LE certs из traefik `acme.json` (`C:\Users\vitya\projects\docker\diskstation\traefik\letsencrypt\acme.json`):
```
acme.json → openssl pkcs12 -export → PFX → Import-PfxCertificate (RUVDS) →
New-WebBinding *:443:<hostname> SslFlags=1 (SNI) → AddSslCertificate by thumbprint
```
**25 HTTPS bindings live**. Cert chain valid (LE R13, до 2026-07-22). HTTP/2 auto-negotiated. Recipe вынесен в [[../concepts/traefik-acme-json-to-iis-cert-import]].
### Phase 7 — live smoke from VDS (2026-05-23 23:35)
7 prod hostnames → 200 OK + correct content; canonical bare→www 301s (CMS-side). 4 hostnames (`maljarka.tandemmebel.ru`, `rimiz.ru`/www, `rimiz.snolla.com`) → 502/404 — **CMS-internal tenant mismatch** (на source IIS:8089 они возвращают 200 default = тоже degraded pre-existing). Не блокирует cutover.
### Phase 8 — DNS partial-cutover (2026-05-24)
- **~00:00:** user flipped A `kupimknigi.spb.ru` в reg.ru. Сначала ошибочно на `89.253.255.94` (VDS Linux), потом исправлено на `80.64.31.36` (RUVDS). Authoritative `ns1.reg.ru` отдаёт правильное; public resolver-cache (8.8.8.8=6h, 1.1.1.1=24h, Yandex=2h) держат старое до TTL expiry.
- **~12:00:** `emspb.ru` + `www.emspb.ru` flipped (1.1.1.1 + Yandex + reg.ru уже отдают новое, 8.8.8.8 кешировал старое). Smoke `--resolve` + partially-cached real DNS → 200 OK + correct content.
> **TTL=86400 — слишком много.** Lower до 300s в reg.ru для всех hostnames ДО полного DNS swap'а.
### Phase 9 — scope narrow (2026-05-24)
User-decision: `tandemmebel.ru` + `www.tandemmebel.ru` ОСТАЮТСЯ на windows-IIS на неопределённый срок. Cert на RUVDS уже импортирован, HTTPS binding existing — но DNS не свапаем. Source IIS `snolla` site нельзя decommission'ить пока tandemmebel на нём же (catch-all binding). Migration делится: 24 hostnames мигрируют, 2 остаются.
## Decisions log (summary)
- **SMB → SSH/scp pivot** (22:30) — home-ISP блокирует outbound 445, deprecate SMB-метод глобально в bootstrap-концепте.
- **Tariff 2GB / 30GB** — minimum-viable для IIS+1 site catch-all; w3wp ~330 MB cold. Под load monitor.
- **Secrets canonical store** — `pass show ruvds-iis/full-env` после ретроактивной cleanup'а .gitignore.
- **CMS-side degraded** (4 hostnames 502/404) — accept, pre-existing on source, не блокер.
- **TTL не снижен заранее** — ошибка процесса, fix recommendation сделан в pre-swap list.
## Outstanding (post-soak)
- DNS TTL drop до 300s в reg.ru для 22 hostnames.
- Full DNS swap остальных 22 hostnames.
- 1-неделя soak с RUVDS как live prod.
- LE renewal pipeline (recommend: `win-acme` standalone + HTTP-01 после full cutover, ~95 days margin).
- Decommission source IIS:8089 + traefik routes (но не traefik сам).
- Cleanup: temp FW rules `ssh-from-source` + `smb-from-source` + удалить `~/.ssh/ruvds-iis-migration*` keys + `C:\ProgramData\ssh\administrators_authorized_keys`.
- Source-info commit — image-pipeline SPOF осталось (imgproxy на windows-host).
## MinIO/imgproxy caveat (carry-over)
RUVDS IIS coupled к windows-host imgproxy через DNS `imgproxy.kzntsv.site` — SPOF home machine **сохраняется** для image-rendering. HTML rendering работает с RUVDS independent. Verified post-migration: `Test-NetConnection imgproxy.kzntsv.site -Port 443` с RUVDS = OK. См. [[../concepts/iis-cutover-to-vds-services]] для long-term resolution.
## Cross-refs
- Live state: [[../entities/ruvds-iis-host]]
- Source-host (pre-migration): [[../entities/windows-recovery-host]]
- Vendor research: `.tasks/windows-hosting-vendor-research.md` (🟢 closed 2026-05-22)
- Pre-req migrations: [[../concepts/mssql-on-vds]] + [[../concepts/minio-imgproxy-on-vds]]
- Bootstrap recipe (updated 2026-05-24): [[../concepts/windows-server-2025-core-bootstrap]]
- Cert-import recipe: [[../concepts/traefik-acme-json-to-iis-cert-import]]
- Backup pipeline: [[ruvds-backup-daily-kreknin-2026-05-24]]
- Driver (SPOF rationale): [[../concepts/future-resilient-architecture-goals]]
- Pre-existing degraded routes: [[../concepts/iis-migration-2026-05-19-postmortem]] + [[iis-host-migration-2026-05-19]]

View File

@@ -0,0 +1,81 @@
---
title: RUVDS daily backup → kreknin — pipeline standup 2026-05-24
type: source
tags: [backup, ruvds, kreknin, rclone, sftp, ntfy, schedtask]
ingested: 2026-05-24
raw_path: ../../.tasks/ruvds-backup-daily-kreknin.md
updated: 2026-05-24
---
# RUVDS daily backup → kreknin
Поднят ежедневный backup pipeline с [[../entities/ruvds-iis-host]] (`80.64.31.36`, Win Server 2025 Core) → [[../entities/kreknin-synology]] (`195.19.90.188 / kreknin.site`) в **04:30 MSK** (за 30 мин до VDS backup'а в 05:00, чтобы не пересекать uplink). После каждого прохода — ntfy push на общий topic `vds-backup` (одно phone-channel для всех backup events). Параллель [[vds-kzntsv-bootstrap-2026-05-20]] §backup, но source = Windows Core → cron нет (Task Scheduler), rsync нет (rclone), root-cron нет (SYSTEM scheduled task).
Источник истины — `.tasks/ruvds-backup-daily-kreknin.md`.
## Scope
| Path on RUVDS | Reason | Size |
|---|---|---|
| `C:\sites\snolla\` | CMS site content + Web.config + media | 8.66 GB |
| `C:\Windows\System32\inetsrv\config\applicationHost.config` | IIS site/binding/apppool config | <1 MB |
| `Backup-WebConfiguration` snapshot → `%SystemRoot%\System32\inetsrv\backup\` | IIS native config snapshot | <5 MB |
| `C:\ProgramData\ssh\` | sshd_config + authorized_keys | <50 KB |
| Exported PFX из `Cert:\LocalMachine\My` | LE certs для restore без re-extract из traefik | <1 MB |
Не бэкапятся: `C:\Windows\`, `C:\Program Files\`, IIS logs.
## Decisions log
- **Tool = rclone (SFTP)**. Не robocopy-over-SMB (SMB через home-ISP блокируется, см. [[iis-migration-to-ruvds-2026-05-23]] Phase 2), не rsync (нет cygwin/WSL на Core, лишний security surface), не restic (encrypted dedupe overkill пока link trusted; defer like VDS).
- **Run as SYSTEM**, не user account — full доступ к `C:\sites\` + `inetsrv\` + cert store, не требует stored-password в Task Scheduler. Pattern matches VDS root-cron decision.
- **PFX export pass = `pfximport` plaintext в run.ps1** — temporary, migrate to pass-equivalent на Windows (DPAPI или gpg4win+bash-pass) когда migration cutover'нется полностью.
- **Retention 7 daily snapshots, без hardlink dedup** — 8.66 GB × 7 = ~60 GB на kreknin (5.7T free). Per-day dirs `/volume1/NetBackup/ruvds-iis/YYYY-MM-DD/`.
- **ntfy topic `vds-backup`** — reuse общего канала, Title включает source-host чтобы phone-side отличать VDS-backup от RUVDS-backup.
## Хронология standup'а (2026-05-24)
- **~10:18:** rclone v1.74.2 installed на RUVDS (`C:\Program Files\rclone\rclone.exe`).
- **~10:18:** ed25519 SSH key `C:\ProgramData\backup\kreknin-key` сгенерирован, pubkey deployed в kreknin `/var/services/homes/vitya/.ssh/authorized_keys` **через VDS pivot** (source machine не имеет direct SSH к kreknin).
- **~10:19:** Deployed `rclone.conf` (SFTP remote `kreknin`, `disable_hashcheck=true`), `config.env` (ntfy creds), `run.ps1`. ACL = SYSTEM + Administrators.
- **10:19:47:** Зарегистрирован ScheduledTask `RUVDS-Backup-Daily` (daily 04:30 MSK, SYSTEM, 2h timeout).
- **10:21:13 — 11:42:57:** Initial full sync 8.66 GB snolla + 4 small components → kreknin. **~82 мин** из-за home-uplink throttling (production cron не affected — RUVDS uplink direct).
- **11:46:51:** Run #1 incremental smoke ✓ **20 sec** — все 5 components OK, retention prune OK (1 snapshot kept, ничего пока удалять), ntfy success sent.
- Scripts checked-in: `scripts/ruvds-backup-daily-kreknin/` (setup.ps1 + run.ps1 + README).
## Bugs fixed during smoke
- `Backup-WebConfiguration -Force` параметра нет на этом IIS — используем `Get-WebConfigurationBackup + Remove-WebConfigurationBackup` если exists + plain `Backup-WebConfiguration`.
- rclone `--log-file` указывал на тот же путь что и `Start-Transcript` → file lock. Убран `--log-file`, transcript captures всё.
- rclone NOTICE на stderr + `$ErrorActionPreference='Stop'` = PS terminating error даже c `2>$null`. Wrapper `Invoke-Rclone` temporarily switches к `ErrorActionPreference='Continue'`.
- ssh-keyscan'енный `known_hosts` не проходит rclone go-sftp library (key mismatch). Убран `known_hosts_file` из rclone.conf, key-auth достаточно.
## Pipeline state
- **Live**: ScheduledTask `RUVDS-Backup-Daily`, daily 04:30 MSK, SYSTEM.
- **Verified**: run #1 end-to-end (20 sec incremental, ntfy push received).
- **Retention day-8 verify**: pending — retention prune не triggered'илась (только 1 snapshot < 7).
- **Phone-side ntfy verify**: pending — user должен подтвердить что push с title `RUVDS backup OK` приходит на ntfy app (common channel с VDS backup).
## Open follow-ups (не блокер)
- PFX export passphrase в plaintext — migrate to DPAPI/pass-equivalent.
- Backup `C:\sites\snolla` size growth (CMS uploads через админку) — quarterly disk-usage check на kreknin.
## Атомарный revert
```powershell
# На RUVDS:
Unregister-ScheduledTask -TaskName 'RUVDS-Backup-Daily' -Confirm:$false
Remove-Item C:\ProgramData\backup -Recurse -Force
# На kreknin (через SSH):
ssh vitya@195.19.90.188 'rm -rf /volume1/NetBackup/ruvds-iis'
```
## Cross-refs
- Source host: [[../entities/ruvds-iis-host]]
- Backup target: [[../entities/kreknin-synology]]
- Driver: open question "Backup strategy для RUVDS" из [[iis-migration-to-ruvds-2026-05-23]] — closed by этой задачей.
- Parallel pipeline: VDS Ubuntu → kreknin rsync `--link-dest` (см. [[vds-kzntsv-bootstrap-2026-05-20]] §backup).
- Notification: общий ntfy topic `vds-backup` на `ntfy.vds.kzntsv.site` (см. [[../entities/vds-kzntsv]] §стек).