Files
admin/.wiki/concepts/snolla-local-admin-https-binding.md
vitya 5a93ac780c wiki(snolla): ingest local admin HTTPS binding — self-signed wildcard *.snolla.com on IIS :443
Локальный .NET-админ snolla на HTTPS: pilorama98.snolla.com/admin 404 (не в hosts → VDS)
→ ERR_CONNECTION_CLOSED (HSTS upgrade, нет 443). Fix: IIS-native self-signed wildcard
*.snolla.com на :443 + Trusted Root (без traefik — acme.json пуст, лишний слой). Рабочий
entry-point /admin/account/login (голый /admin → canonical на public — предсуществующее
поведение CMS). +index.md (2 строки, design-док ранее не индексирован) + log.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-29 09:14:29 +03:00

6.5 KiB
Raw Blame History

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). На практике браузер апгрейдил httphttps (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://<alias>.snolla.com/admin/account/login → 200, форма входа SNOLLA (title SNOLLA, password-поле, <form action="/admin/login">). Покрытие верифицировано: pilorama98, kupimknigi, internal, tandemmebel → 200.
  • Голый /admin → 302 /login → 301 https://www.<PrimaryDomain>/ (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'ы.

Связано