Files
admin/.wiki/concepts/snolla-local-admin-and-on-snolla-migration-design.md
vitya b1b0092cdc design(snolla): local .NET admin restore + on.snolla.com VDS migration
Two linked tasks, spec in .wiki/concepts/ per project-discipline.

Task A — snolla-local-admin-restore: восстановить локальный catch-all IIS-сайт
`snolla` (снесён 2026-06-08) копированием C:\sites\snolla\ с RUVDS (прод-админ
с MinIO drop-in), conn → mssql.kzntsv.site MoreThenCms. Доступ
<alias>.snolla.com/admin через hosts-override, один AppPool. Адреса + siteIds
извлечены из MoreThenCms DB read-only.

Task B — on-snolla-vds-migration (blocked by A): on.snolla.com (siteId
B9ECDB50…, alias on, "Internal Site", culture en) с RUVDS IIS → VDS Node
snolla-app 0.42.1, реконструкция Liquid-шаблонов из боевого сайта+админки
(исходников нет). По рецепту tandemmebel-vds-deploy-runbook.

Board entries: .tasks/STATUS.md + per-task files.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-20 09:45:06 +03:00

92 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: SNOLLA local .NET admin restore + on.snolla.com VDS migration — design
type: concept
tags: [snolla, morethencms, iis, admin, minio, vds, migration, on-snolla, design]
related: [[../entities/windows-recovery-host]], [[../entities/ruvds-iis-host]], [[../entities/vds-kzntsv]], [[tandemmebel-vds-deploy-runbook]], [[snolla-live-prod-inplace-image-bump]], [[portainer-stack-management-vds]], [[filestorage-s3-provider@MoreThenCms]]
updated: 2026-07-20
---
# SNOLLA local .NET admin restore + on.snolla.com → VDS migration
Две связанные задачи. **Task A** восстанавливает локальный .NET-админ (чтобы редактировать контент всех сайтов тиража + on.snolla.com). **Task B** мигрирует посадочную `on.snolla.com` с RUVDS на VDS как Node snolla-app, реконструируя отсутствующие исходники из боевого сайта + админки. Task A → питает Task B (без рабочего админа не увидеть контент/структуру on.snolla.com).
## Контекст
- **Тираж SNOLLA** (5 сайтов) уже на VDS как Node snolla-app `@snollajs/snolla` 0.42.1, читают контент из общей MSSQL `MoreThenCms` на `mssql.kzntsv.site:1433` + ассеты из MinIO `minio.kzntsv.site`. Стеки Portainer: labtools.ru(17), emspb.ru(18), labtools.pro(19), tandemmebel(20), kupimknigi(21). Публичный snolla-app **без админки** (`apps/web` не несёт admin-роутов).
- **На RUVDS IIS** (`80.64.31.36`, Windows Server 2025 Core) остались: catch-all IIS-сайт `snolla` (MoreThenCms .NET 4.8, `/admin` для всех `*.snolla.com`) + посадочная `on.snolla.com`. МинIO-поддержка в .NET-админ добавлена (drop-in `MoreThenCms.FileStorage.S3`, см. MoreThenCms `.wiki/concepts/filestorage-s3-provider.md`).
- **Локальный админ-хост** = этот рабочий PC (`windows-recovery-host`, DESKTOP-NSEF0UK). IIS-сайт `snolla` + `C:\sites\snolla\` были снесены 2026-06-08 (RUVDS забрал прод-админ). Живой локальный аналог остался: `stostayer`(:8090)/`stostayer.old`(:8091) — тот же движок MoreThenCms, `/admin`, conn → `mssql.kzntsv.site,1433`. Это рабочий шаблон конфига.
- **on.snolla.com** — `dbo.Sites`: `SiteId=B9ECDB50-2B93-4CE5-B238-A9918B3F9CF7`, `Alias=on`, `Title="Internal Site"`, `Culture=en`, `Live=1, Production=1`. Лендинг самого SNOLLA. Отдельного репо/исходников нет.
## Task A — восстановить локальный .NET-админ (catch-all IIS `snolla`)
### Адресация (confirmed оператором)
Catch-all IIS-сайт `snolla`, binding `*:80` (локально — `127.0.0.1:80` или `*:80` без публикации наружу), **один AppPool `snolla`**. Доступ через `hosts`-override: `127.0.0.1 <alias>.snolla.com` на каждый таргет. Multi-tenant routing в CMS по Host-header → siteId из `dbo.Sites`.
**Адреса админок** = `<Alias>.snolla.com/admin`:
| Адрес | PrimaryDomain | siteId |
|---|---|---|
| `tandemmebel.snolla.com/admin` | tandemmebel.ru | 78080707-F6E0-4330-BA30-7922354C2CEF |
| `labtools.snolla.com/admin` | labtools.ru | D375C419-D787-4FCC-8934-A3B9DC951006 |
| `labtoolspro.snolla.com/admin` | labtools.pro | 663F9410-A6CC-4651-9A5C-62844A313957 |
| `emspb.snolla.com/admin` | emspb.ru | 96EBC481-D26A-47BE-B660-13D49E7D0A61 |
| `kupimknigi.snolla.com/admin` | kupimknigi.spb.ru | E924A354-0377-4E1E-80C6-2EB0194AA55F |
| `on.snolla.com/admin` | on.snolla.com | B9ECDB50-2B93-4CE5-B238-A9918B3F9CF7 |
Catch-all обслужит `/admin` для любого сайта из DB при добавлении `127.0.0.1 <alias>.snolla.com` в hosts — тираж = 5 + on.snolla.com минимум, при желании все ~60.
### Источник `C:\sites\snolla\`
**Рекомендация — копировать с RUVDS** (`scp`/`rclone`): RUVDS держит `C:\sites\snolla\` (8.66 GB) = текущий прод-админ **с уже применённым MinIO drop-in**. Копируем → получаем админ с MinIO из коробки, без пересборки solution и без ручного патча DLL. Альтернативы (build из MoreThenCms source + применить S3 drop-in вручную; restore с kreknin-backup) дольше и требуют повторной MinIO-настройки.
### Шаги
1. **Verify source (read-only SSH RUVDS, креды `pass show ruvds-iis/full-env`):** `C:\sites\snolla\` есть; `Web.config` несёт `storageType="MoreThenCms.FileStorage.S3.*"` + endpoint `minio.kzntsv.site`; IIS site `snolla` жив. Если MinIO НЕ применён — fallback: build из source + drop-in из `MoreThenCms.FileStorage.S3/deploy/` (3 DLL + `fileStorageClients-s3.sample.config`).
2. **Копировать `C:\sites\snolla\`** RUVDS → локально `C:\sites\snolla\` (~8.66 GB; rsync недоступен на Core — `scp -r` или `rclone copy`, resume через rclone).
3. **Репойнт conn-string** в локальном `Web.config``Data Source=mssql.kzntsv.site,1433;Initial Catalog=MoreThenCms;User ID=<snolla-db-user>;Password=<...>;MultipleActiveResultSets=True;TrustServerCertificate=True` (паттерн из `stostayer.old/Web.config`). DB-креды — из `pass` (MoreThenCms DB user; тот же, что tandemmebel production.json `DB_USER`/`DB_PASSWORD`).
4. **MinIO-ключи** в `<fileStorageClients>`: endpoint `https://minio.kzntsv.site`, бакеты `assets`/`galleries`/`themes`, `accessKey`/`secretKey` — из `pass show minio-vds/full-env`. Если в скопированном Web.config ключи плейсхолдеры `__SET_ON_DEPLOY__` — подставить реальные. Кэши (`imageCache`/`uploadCache`/`contentCache`/`sessionFiles`) оставить `Local`.
5. **IIS-сайт `snolla`** воссоздать: AppPool `snolla` (.NET v4.0 Integrated, `ApplicationPoolIdentity`), binding `*:80` catch-all (как на проде). Локальный доступ гарантируется FW-блоком inbound 80 + `hosts`-override → 127.0.0.1 (внешние не достучатся). Multi-tenant по Host-header.
6. **ACL**: `icacls C:\sites\snolla /grant "IIS AppPool\snolla:(OI)(CI)(M)" /T` (паттерн `snolla-admin-appdata-acl-500`).
7. **hosts-override**: добавить `127.0.0.1 tandemmebel.snolla.com labtools.snolla.com labtoolspro.snolla.com emspb.snolla.com kupimknigi.snolla.com on.snolla.com` в `C:\Windows\System32\drivers\etc\hosts` (нужен elevation).
8. **URL Rewrite rule** (X-Forwarded-Proto→HTTPS server-vars) — **НЕ ставить** локально (нет traefik; ходим по http, иначе `:port` leak как в `cms-server-port-leak-fix`).
9. **Firewall**: НЕ открывать 80/443 inbound — локальный только.
10. **Smoke**: `curl -H "Host: tandemmebel.snolla.com" http://127.0.0.1/admin/account/login` → 200 логин-форма; аналогично для on.snolla.com. MinIO: залить тестовый ассет через админку → виден через `minio.kzntsv.site`/фронтом (приёмка #5 drop-in'а).
### Гочи (специфичные)
- **`appSettings/sitePath`** в catch-all `Web.config``C:\sites\snolla\` (multi-tenant; siteId резолвится из Host-header, не из appSettings — в отличие от per-site stostayer.old где `siteId` в appSettings).
- **machineKey** — оставить из скопированного Web.config (общий для всех tenant'ов админ-сессий).
- **`customErrors mode="Off"`** — обязательно (иначе fatal config error после ASP.NET reload, см. `cms-server-port-leak-fix` side-regression).
- **MSSQL-коннект с workstation** — уже работает (stostayer.old его использует); `TrustServerCertificate=True` обязательно (mssql.kzntsv.site cert self-signed/не-Microsoft).
## Task B — on.snolla.com → VDS (Node snolla-app, реконструкция)
on.snolla.com = MoreThenCms-сайт на RUVDS (посадочная). На VDS (Linux) .NET Framework не бежит → становится Node snolla-app по образцу `victor/tandemmebel.ru`. Контент (DB-строки + ассеты) уже на vds-kzntsv (общая `MoreThenCms` DB + MinIO). Нет репозитория шаблонов+конфига — собираю из боевого сайта + админки.
### Реконструкция
1. **siteId найден**: `B9ECDB50-2B93-4CE5-B238-A9918B3F9CF7` (alias `on`, culture `en`).
2. **Новый репо** `victor/on-snolla` (имя уточнить у оператора) — структура как `tandemmebel.ru`: `apps/web/{server.js,index.js,config/,views/,package.json}`, `deploy/Dockerfile` (multi-stage node:22-slim, `yarn install --immutable`, non-root, healthcheck `/robots.txt`). `apps/web/package.json` пин `@snollajs/snolla` 0.42.1 (parity с тиражом).
3. **production.json**: `siteId=B9ECDB50…`, `siteUrl=https://on.snolla.com`, `data.sequelize``MoreThenCms` DB `mssql.kzntsv.site:1433` (Catalog `MoreThenCms`), `s3``minio.kzntsv.site`, `imgproxy``imgproxy.kzntsv.site`, `media` sharp serve-bytes, `mailSettings`. Секреты в runtime-env стека (Portainer), НЕ в образе/гите — как tandemmebel (8 секретов).
4. **Liquid-шаблоны (views/)** — реверс-инжиниринг с боевого `https://on.snolla.com/`: для каждой страницы смотрим HTML, сопоставляем с DB-контент-структурой (секции/блоки через локальный админ из Task A), пишем `layout.liquid` + page/partials. Содержимое (текст/картинки) идёт из DB; шаблоны = layout + разметка. Итеративно: пиши шаблон → рендерь на staging → сверяй с боевым HTML (byte/structure parity).
5. **Build на VDS** (обход traefik-499), **throwaway-staging `:50XX`**, **completeness-gate** (sitemap parity vs прод-on.snolla.com — page-locs NEW==PROD, self-consistency), **stack** за traefik (`Host(on.snolla.com)`), **DNS-flip** reg.ru→89.253.255.94. По рецепту `tandemmebel-vds-deploy-runbook` (cutover) + `snolla-live-prod-inplace-image-bump` (gate). `mem_limit 512m`.
### Trade-off реверс-инжиниринга
Боевой HTML даёт вёрстку, но Liquid-примитивы snolla (sections/blocks/feeds) надо сопоставить с DB-структурой — итеративно. Риск: сложная посадочная с нестандартными блоками = больше итераций. Митигация: on.snolla.com Title="Internal Site" culture `en` — вероятно простой лендинг, объём шаблонов ограничен.
## Последовательность и зависимости
1. **Task A** — восстановить локальный админ (RUVDS→scp→IIS→MinIO→smoke). Блокирует Task B (нужен админ для контент-инспекции).
2. **Task B** — через локальный админ + боевой HTML собрать on.snolla.com snolla-app → build на VDS → cutover.
## Load-bearing допущения (verify в плане)
- RUVDS `C:\sites\snolla\` несёт MinIO drop-in (SSH read-only — первый шаг Task A). Если нет — fallback на build+drop-in.
- MinIO-ключи в RUVDS Web.config — реальные, не `__SET_ON_DEPLOY__` (иначе подтянуть из `pass`).
- MoreThenCms DB-креды (snolla-user) в `pass` — найти путь (кандидаты: `mssql-vds/...`, общий env). SA-доступ есть (`pass show mssql-vds/sa-password`) — но админ использует app-аккаунт, не SA; уточнить у оператора.
- on.snolla.com siteId/контент доступны в общей `MoreThenCms` DB (подтверждено: строка в `dbo.Sites` есть).
- `hosts`-override + IIS-воссоздание требуют elevation (admin-сессия на workstation).
## Rollback
- **Task A:** удалить IIS-сайт `snolla` + `C:\sites\snolla\` + откатать hosts-записи. Прод на RUVDS не тронут — rollback = просто не пользоваться локальным админом.
- **Task B:** образ предыдущего тега в registry (или RUVDS IIS жив для on.snolla.com пока DNS не флипнут — revert DNS→80.64.31.36).
## Open questions (для оператора)
- Имя нового репо для on.snolla.com (`victor/on-snolla`? `victor/on.snolla.com`?).
- MoreThenCms DB-креды: app-аккаунт + путь в `pass` (или использовать SA локально / завести отдельный read-write аккаунт).
- Включать ли в локальный админ ВСЕ сайты (~60) или только тираж(5)+on.snolla.com — catch-all даёт все бесплатно, решает hosts-список.