--- title: Локальный .NET-админ snolla — HTTPS на IIS :443 (self-signed wildcard) type: concept tags: [snolla, morethencms, iis, admin, https, self-signed, certificate, local, pilorama98] related: [[snolla-local-admin-and-on-snolla-migration-design]], [[traefik-on-windows-docker-desktop]], [[docker-host-loopback-detect]], [[stostayer-admin-minio-config]] updated: 2026-07-29 --- # Локальный .NET-админ snolla — HTTPS на IIS :443 (self-signed wildcard) Реализация 2026-07-29 поверх design-дока [[snolla-local-admin-and-on-snolla-migration-design]] (Task A). Design предполагал **http-only** локальную админку (нет traefik → без URL Rewrite → ходим по http). На практике браузер апгрейдил `http`→`https` (HSTS, закешированный с прошлых заходов на VDS, или Chrome/Edge «Always use secure connections») → локальный IIS без 443 → `ERR_CONNECTION_CLOSED`. Постановка wildcard self-signed прямо на IIS-сайт `snolla` :443 решает это без traefik. ## Решение: IIS-native HTTPS, НЕ traefik Рассматривали оживление локального traefik ([[traefik-on-windows-docker-desktop]]). Отклонено: - Локальный `acme.json` пуст — LE-сертификата на `snolla.com` нет → traefik ради self-signed не нужен (IIS умеет сам). - Traefik как TLS-терминатор перед локальным IIS = лишний слой со всеми готчами: NAT-loopback ([[docker-host-loopback-detect]]), сломанный docker.sock provider, file-provider не watch'ит, `SERVER_PORT` leak → нужен URL Rewrite, acme.json perms 0777. - Бэкенд теперь на том же хосте (локальный IIS), не в VBox-VM — reverse-proxy не несёт смысла. IIS сам терминирует TLS → `SERVER_PORT=443` чисто, X-Forwarded не нужен, port-leak'ов нет. ## Что сделано ### 1. hosts — добавлен pilorama98.snolla.com Symptom: `https://pilorama98.snolla.com/admin` → 404. Корень: `pilorama98.snolla.com` **не был в hosts-override** → реальный DNS → VDS `89.253.255.94` → traefik без роута → 404 (404 прилетал с VDS, не с локального). Системный прокси `127.0.0.1:10808` (xray) маскировал «server 127.0.0.1» в curl, но реальный backend был VDS. `pilorama98` — реальный сайт в `dbo.Sites` (Alias=`pilorama98`, PrimaryDomain=`pilorama98.ru`, Live=True, Production=False, SiteId `37e67fc4-…`), просто не входил в тираж-5 из design-дока. Catch-all обслужит любой сайт из DB при добавлении в hosts. Строка hosts теперь: ``` 127.0.0.1 tandemmebel.snolla.com labtools.snolla.com labtoolspro.snolla.com emspb.snolla.com kupimknigi.snolla.com internal.snolla.com pilorama98.snolla.com ``` (правка hosts требует elevation — через `Start-Process -Verb RunAs`; `Set-Content` из не-elevated шелла = `UnauthorizedAccess`; по памяти `Get-Content -Raw` мог опустошить файл → читаем по строкам). ### 2. Self-signed wildcard cert на IIS :443 Скрипт (elevated, UAC): - `New-SelfSignedCertificate -Subject '*.snolla.com' -DnsName '*.snolla.com','snolla.com' -CertStoreLocation Cert:\LocalMachine\My -NotAfter +10y -TextExtension @('2.5.29.37={text}1.3.6.1.5.5.7.3.1')` — гоча: `-DnsName` конфликтует с ручным SAN TextExtension `2.5.29.17` (параметр противоречит SAN) → SAN генерится через `-DnsName`, оставляем только EKU serverAuth. - Копия в `Cert:\LocalMachine\Root` (Trusted Root) через `X509Store('Root','LocalMachine')` → браузер доверяет, HSTS удовлетворён. - `New-WebBinding -Name snolla -Protocol https -Port 443 -IPAddress '*'` + `$bind.AddSslCertificate($thumb,'My')` + Stop/Start-Website (без restart binding не активируется). - Cert thumbprint: `6E2212B4C13BD28E2FF680322F11741193E8C619`, SAN `DNS:*.snolla.com, DNS:snolla.com`, 10 лет. Wildcard покрывает **все** alias'ы сразу — pilorama98, kupimknigi, internal, tandemmebel, labtools, labtoolspro, emspb и любой будущий. ### 3. Доступ - `https://.snolla.com/admin/account/login` → 200, форма входа SNOLLA (title `SNOLLA`, password-поле, `
`). Покрытие верифицировано: pilorama98, kupimknigi, internal, tandemmebel → 200. - **Голый `/admin` → 302 `/login` → 301 `https://www./`** (canonical на public-домен). Это **предсуществующее поведение CMS** (подтверждено оператором: «так и было» на RUVDS), не поломка миграции. Рабочий entry-point = `/admin/account/login` напрямую (закладка). - `on.snolla.com` → 404: в hosts стоит `internal.snolla.com` (реальный alias сайта `on` в DB = `internal`, Title="Internal Site"), не `on`. Design-док писал `on` — фактический alias `internal`. ## Trade-off Self-signed, не LE. Допустимо: админка локальная, FW inbound 80/443 закрыт, публично не торчит. Если позже нужен real-LE — traefik DNS-01 через REGRU (креды `OpeItcLoc03` в compose-env, см. [[traefik-on-windows-docker-desktop]] § DNS-01), но это отдельная задача и весь traefik-стек. ## Повторяемость Cert в Trusted Root переживает перезагрузку. При регенерации (например, истёк/потерян) — тот же скрипт: почистить старые `*.snolla.com` в My/Root, создать заново, бинд. `SslFlags=0` (без SNI) — один catch-all сайт, один wildcard cert на все Host-header'ы. ## Связано - [[snolla-local-admin-and-on-snolla-migration-design]] — исходный design (Task A http-only, Task B on.snolla.com→VDS). - [[stostayer-admin-minio-config]] — родственный локальный .NET-админ (:8090), тот же движок MoreThenCms. - [[traefik-on-windows-docker-desktop]] — почему traefik отклонён.