Compare commits
4 Commits
68706d0bee
...
adcd8bda1f
| Author | SHA1 | Date | |
|---|---|---|---|
| adcd8bda1f | |||
| 8a30696a45 | |||
| e17e8eb1c3 | |||
| 86a94d7f9d |
111
.tasks/STATUS.md
111
.tasks/STATUS.md
@@ -1,5 +1,5 @@
|
|||||||
# Admin Task Board
|
# Admin Task Board
|
||||||
_Updated: 2026-05-22 (owncloud-vds-deploy 🟢 — 25 044 объектов / 26 GB live, все 6 large-file холдауты залиты VDS-side curl loopback'ом; 60s upload-timeout finding закреплён в [`ocis-on-vds-deploy-recipe`](../.wiki/concepts/ocis-on-vds-deploy-recipe.md) §Gotcha 5)_
|
_Updated: 2026-05-22 (Сессия завершена. MSSQL Express 2022 live на `mssql.kzntsv.site:1433` с 5 restored DBs, IIS snolla site cutover ✓ — 8 prod hosts 200 OK. MinIO/imgproxy: VDS stack live as standby (3 GiB / 19324 obj mirrored, upgrade 2020→2025), но CMS image pipeline остаётся на windows-host — closed-source `MoreThenCms.Modules.Imgproxy.dll` hardcoded `https://imgproxy.kzntsv.site` URL. User decision Option C. 3 wiki concepts ingested. Decommission window-host MSSQL после 48ч soak 2026-05-24; MinIO/imgproxy/nginx на windows остаются indefinitely.)_
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Status legend:
|
Status legend:
|
||||||
@@ -517,17 +517,116 @@ User confirmed close by inspection: "Close review as no-new-findings (Recommende
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ⚪ [mssql-minio-migration-to-vds] — Фаза 2 CMS backup. Перенести MSSQL контейнер + MinIO с windows-recovery-host на vds-kzntsv. Achieves target RPO 1ч через интеграцию с существующим `vds-backup-rsync-kreknin` pipeline (tx log backups каждые 60 мин в существующий rsync→kreknin). Снимает SPOF с домашней машины для критических CMS-данных.
|
## 🟢 [mssql-minio-migration-to-vds] — декомпозирована 2026-05-22 на две независимые таски
|
||||||
|
|
||||||
После завершения — списать `cms-stopgap-backup-daily` cron на windows-host.
|
**Closed:** 2026-05-22 — Discovery prep сессия (windows-side docker ps + sizes + VDS docker ps + stats) выявила что MSSQL и MinIO имеют разные мигратные паттерны (BACKUP/RESTORE vs `mc mirror`), разные окна простоя, разные rollback, разный risk profile (Express edition limit check vs MinIO 5-year upgrade). User decided: split на две таски.
|
||||||
|
|
||||||
**Status:** ready
|
**Children:**
|
||||||
**Where I stopped:** (not started)
|
- `mssql-vds-migration` ⚪ — MSSQL only, Express edition prod, SHRINKFILE-cleanup → BACKUP/RESTORE → traefik TCP `mssql.kzntsv.site:1433`.
|
||||||
**Next action:** См. `mssql-minio-migration-to-vds.md` — full acceptance (8 items) + risks + open questions. Major task (1-2 недели realistic). Разбить на sub-phases: (a) MSSQL container deploy на VDS + restore from backup, (b) connection string change + smoke 8 hosts, (c) MinIO migration через `mc mirror`, (d) backup pipeline integration в `/opt/stacks/backup/scripts/run.sh`. **Pre-cutover benchmark обязателен** (admin assets UI / search / catalogs) — WAN latency 10-30ms vs localhost. Spawn'd by [resilience-roadmap-design] workshop pass 1 2026-05-21.
|
- `minio-imgproxy-vds-migration` ⚪ — MinIO upgrade `2020-07-13` → latest + imgproxy + imgproxy-nginx, `mc mirror`, traefik HTTPS `minio.vds.kzntsv.site` (+ console subdomain).
|
||||||
|
|
||||||
|
Original umbrella `.tasks/mssql-minio-migration-to-vds.md` сохранён для history (acceptance/decisions/risks merged в children).
|
||||||
**Branch:** n/a
|
**Branch:** n/a
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 🟢 [mssql-vds-migration] — DONE 2026-05-22: MSSQL Express 2022 live на `mssql.kzntsv.site:1433`, 5 DBs restored + IIS snolla site cutover ✓
|
||||||
|
|
||||||
|
**Closed:** 2026-05-22 — phase 1 (deploy + restore + cutover) complete; 8 prod hosts 200 OK через VDS MSSQL. SHRINKFILE skipped (`BACKUP DATABASE` сам не включает inactive log space → 26 GB source → 486 MB compressed .bak).
|
||||||
|
|
||||||
|
**Executed steps:**
|
||||||
|
1. `BACKUP DATABASE WITH COMPRESSION, COPY_ONLY, INIT` на source для 5 DBs (3.17 sec на 235 MB MoreThenCms, total 486 MB)
|
||||||
|
2. `docker cp` → `scp` → `/opt/stacks/databases/mssql/backups/` on VDS (chown 10001:0)
|
||||||
|
3. Traefik static config: добавлен `mssql` entrypoint :1433. **Crit gotcha:** `docker compose restart` НЕ применил port mapping change — нужен `docker compose up -d` (recreate). Симптом: port 1433 не listened.
|
||||||
|
4. ufw allow 1433/tcp
|
||||||
|
5. `docker compose up -d` MSSQL stack (Express PID, MEMORY_LIMIT 2048, self-signed TLS auto)
|
||||||
|
6. `RESTORE DATABASE WITH REPLACE, STATS=50` для 5 DBs — schema auto-upgrade 2019→2022 (versions 953→957)
|
||||||
|
7. `DBCC CHECKDB ... WITH NO_INFOMSGS, PHYSICAL_ONLY` — clean
|
||||||
|
8. **Crit fix:** server-level login `snolla` НЕ восстановился из .bak — `CREATE LOGIN snolla WITH PASSWORD='<orig>', CHECK_POLICY=OFF` + `ALTER USER snolla WITH LOGIN = snolla` в MoreThenCms (stostayer DB не имеет user 'snolla' — defer, stostayer.old site local-only).
|
||||||
|
9. Edit `C:\sites\snolla\Web.config`: `Data Source=localhost` → `Data Source=mssql.kzntsv.site,1433;...;TrustServerCertificate=True`. Backup в `.bak-pre-vds-cutover-20260522`.
|
||||||
|
10. IIS auto-recycle on web.config touch. **Smoke 8 hosts 200 OK ✓** (emspb/snolla.com→on.snolla/pilorama98/labtools.ru+pro/tandemmebel/kupimknigi).
|
||||||
|
|
||||||
|
**Findings закреплены в** [`mssql-on-vds`](../.wiki/concepts/mssql-on-vds.md) §Gotchas: (1) logins-vs-users orphan dance, (2) traefik recreate-not-restart для port mapping, (3) PowerShell не запускает `pass` bash-script → NULL pw + misleading "Login failed", (4) password generator excludeать `+/=` Base64 chars, (5) mssql uid 10001 ownership.
|
||||||
|
|
||||||
|
**Open follow-ups:**
|
||||||
|
- Backup pipeline integration (mssql_dump_full daily + mssql_tx_log_backup hourly → RPO 1ч) — отдельная chore-task после первого backup green.
|
||||||
|
- stostayer.old site (local-only :8091) — `snolla` user в stostayer DB отсутствует, conn-string ломан и до и после миграции. Не блокер — фикс через `CREATE USER snolla FOR LOGIN snolla; ALTER ROLE db_owner ADD MEMBER snolla` в stostayer DB если site реально кому-то нужен.
|
||||||
|
- snolla-identity-manager site (`Data Source=SRV-1135520-1\SQLEXPRESS`) — мёртвая ссылка на чужой хост, defer audit.
|
||||||
|
- 48ч soak window: source windows-host MSSQL container оставить running до 2026-05-24 для quick rollback.
|
||||||
|
|
||||||
|
**Atomic revert:** `Copy-Item C:\sites\snolla\Web.config.bak-pre-vds-cutover-20260522 C:\sites\snolla\Web.config -Force` → IIS auto-recycle.
|
||||||
|
**Branch:** master
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🟢 [minio-imgproxy-vds-migration] — Closed 2026-05-22 — VDS stack live as standby; CMS image pipeline остаётся на windows-host из-за hardcoded URL в closed-source DLL.
|
||||||
|
|
||||||
|
**Where I stopped:** Stack live на VDS (`minio.vds.kzntsv.site` + `minio-console.vds.kzntsv.site` + `imgproxy.vds.kzntsv.site` traefik routes ✓). Все buckets mirrored с format compat 2020→2025 verified (mc mirror through S3 API, не сырое filesystem). CMS image URLs пока рендерятся через windows-host imgproxy (DNS `imgproxy.kzntsv.site` всё ещё на windows IP).
|
||||||
|
|
||||||
|
**Executed steps:**
|
||||||
|
1. `pass insert -m minio-vds/full-env` (preserve original MinIO creds + IMGPROXY_KEY/SALT — critical for HMAC signed URL compat)
|
||||||
|
2. VDS: `/opt/stacks/storage/minio-imgproxy/` + scp nginx.conf + write .env from pass + compose (3 services in `proxy` network)
|
||||||
|
3. `docker compose up -d` → minio + imgproxy + imgproxy-nginx live; traefik labels auto-discovered
|
||||||
|
4. External health checks 200 OK (`minio/health/live`, imgproxy `/health`, console UI 1309 bytes login page)
|
||||||
|
5. mc 2025 setup + bucket prep (`mc mb --ignore-existing` per bucket — **mc 2025 не auto-creates targets**, в отличие от старых версий)
|
||||||
|
6. `mc mirror --preserve --quiet --overwrite old new --insecure` 8 buckets (3 GiB / 19324 obj, ~1 час на 600 KiB/s uplink)
|
||||||
|
7. Verify per-bucket — **3.0 GiB / 19324 obj match on both sides ✓**
|
||||||
|
8. **Crit finding:** один файл `Albrecht Dürer ...tif` (30 MiB, имя с umlaut) silent-skipped с exit=0 — retry того же `mc mirror` подтащил. Verify по count+size обязателен, не доверять exit code.
|
||||||
|
|
||||||
|
**Findings закреплены в** [`minio-imgproxy-on-vds`](../.wiki/concepts/minio-imgproxy-on-vds.md) §Gotchas: (1) MinIO upgrade 5y gap works via mc mirror (S3 API), не bind-swap (xl.meta format), (2) mc 2025 НЕ auto-creates buckets, (3) silent skip non-ASCII filename + slow uplink → verify по count, (4) IMGPROXY_KEY/SALT preserve обязательно (HMAC signed URLs), (5) MINIO_ROOT_USER/PASSWORD replace deprecated MINIO_ACCESS_KEY/SECRET — reuse same values.
|
||||||
|
|
||||||
|
**Resolution 2026-05-22:** `MoreThenCms.Modules.Imgproxy.dll` (closed-source, исходника в репо нет) содержит **hardcoded** `https://imgproxy.kzntsv.site` (decoded из DLL strings: `/imgproxy;https://imgproxy.kzntsv.site/-ImgproxyHandler_Invoke`). Архитектура: browser → traefik → IIS snolla → ImgproxyHandler → server-side GET к `imgproxy.kzntsv.site` → traefik windows-host → imgproxy-nginx → imgproxy → MinIO localhost:9000.
|
||||||
|
|
||||||
|
Sample URL (decoded): `https://www.pilorama98.ru/imgproxy/<sig>/.../czM6Ly9waWxvcmFtYTk4L3Byb2R1Y3RzL2wv...` → base64 = `s3://pilorama98/products/l/9d428089-...jpg` (MinIO bucket `pilorama98`).
|
||||||
|
|
||||||
|
Опции рассмотрены: A) hosts+cert trick + LE DNS-01 / B) local nginx-relay с self-signed + CallTrust unknown / C) keep as-is / D) decompile+recompile DLL. **User decision: Option C — оставить как есть.** Windows-host imgproxy/nginx/MinIO живут indefinitely; VDS stack — standby/backup target. Backup pipeline integration (rsync VDS MinIO → kreknin) — отдельная chore-task если понадобится.
|
||||||
|
|
||||||
|
**Windows-host MinIO/imgproxy/imgproxy-nginx остаются running** (не decommission). Decommission ALLOW только для windows-host MSSQL (см. iis-cutover-to-vds-services).
|
||||||
|
**Branch:** master
|
||||||
|
|
||||||
|
**Backup pipeline TODO:** `minio_mirror` daily в `/opt/stacks/backup/scripts/run.sh` — rsync `/opt/stacks/storage/minio-imgproxy/data` → kreknin.
|
||||||
|
|
||||||
|
**Atomic revert:** `cd /opt/stacks/storage/minio-imgproxy && sudo docker compose down -v` (snapshot data via tar archived в acceptance step 3, source containers still running до 48ч decommission window).
|
||||||
|
**Branch:** master
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🟢 [iis-cutover-to-vds-services] — Closed 2026-05-22 — MSSQL cutover live (8 hosts 200 OK ✓); MinIO image-pipeline остаётся на windows-host (user decision Option C — hardcoded URL в closed-source DLL).
|
||||||
|
|
||||||
|
**MSSQL phase complete:**
|
||||||
|
- Audit: `C:\sites\snolla\Web.config` обслуживает 11 CMS hosts (snolla catch-all `*:8089`). Только 1 conn-string на MoreThenCms DB, login `snolla` (не sa).
|
||||||
|
- `stostayer.old\web.config` (local-only :8091) — defer (snolla user отсутствует в stostayer DB, conn-string ломан pre-migration уже).
|
||||||
|
- `stostayer\web.config` уже на external `www.stostayer.ru,1433` — не наш scope (внешний MSSQL).
|
||||||
|
- `snolla-identity-manager\web.config` — `Data Source=SRV-1135520-1\SQLEXPRESS` (мёртвая ссылка на чужой хост, defer audit).
|
||||||
|
- Edit `Data Source=localhost` → `mssql.kzntsv.site,1433;TrustServerCertificate=True` + backup `.bak-pre-vds-cutover-20260522`
|
||||||
|
- IIS auto-recycle на web.config touch (без iisreset).
|
||||||
|
- Smoke 8 priority hosts: emspb/snolla.com→on.snolla/pilorama98/labtools.ru/labtools.pro/www.tandemmebel/kupimknigi — **все 200 OK**, latency 0.3-3.1s (tandemmebel самый медленный — большая страница).
|
||||||
|
|
||||||
|
**MinIO image-pipeline phase: NOT migrated (user decision Option C):**
|
||||||
|
- `MoreThenCms.Modules.Imgproxy.dll` hardcoded `https://imgproxy.kzntsv.site` (strings analysis 2026-05-22).
|
||||||
|
- DLL closed-source, исходника в репо нет; decompile+recompile = ad-hoc-fragile.
|
||||||
|
- **CMS image pipeline остаётся целиком на windows-host** (imgproxy/nginx/MinIO + traefik route `imgproxy.kzntsv.site` → imgproxy-nginx:80).
|
||||||
|
- VDS MinIO+imgproxy stack — standby / future use only. Backup target rsync — optional chore.
|
||||||
|
- Decommission windows-host: **TOLLY MSSQL container** (после 48ч soak). MinIO/imgproxy/imgproxy-nginx — остаются.
|
||||||
|
|
||||||
|
**48ч soak:** monitor через ntfy `vds-ops` + manual smoke 24h/48h marks. Source windows-host MSSQL container оставить running до 2026-05-24 для rollback.
|
||||||
|
|
||||||
|
**Decommission window (после 48ч green):**
|
||||||
|
1. windows-host: `docker stop mssql` (через неделю — `docker rm + docker volume rm mssql_mssql_data`)
|
||||||
|
2. После DNS swap MinIO: `docker stop minio imgproxy imgproxy-nginx`
|
||||||
|
3. Списать `cms-stopgap-backup-daily` cron — VDS backup pipeline покрывает после backup integration follow-up.
|
||||||
|
|
||||||
|
**Atomic revert (full):**
|
||||||
|
```powershell
|
||||||
|
Copy-Item C:\sites\snolla\Web.config.bak-pre-vds-cutover-20260522 C:\sites\snolla\Web.config -Force
|
||||||
|
# IIS auto-recycle (или iisreset /restart)
|
||||||
|
# Убедиться windows-host MSSQL container running (если decommissioned — docker start mssql)
|
||||||
|
```
|
||||||
|
**Status:** in_progress (MSSQL ✓, MinIO DNS swap pending)
|
||||||
|
**Branch:** master
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## ⚪ [windows-hosting-vendor-research] — Design-таска (1 день). Выбрать вендора managed Windows hosting для будущего переезда IIS с windows-recovery-host (домашней машины). Output: 1-pager с recommended vendor + cost estimate + migration recipe outline.
|
## ⚪ [windows-hosting-vendor-research] — Design-таска (1 день). Выбрать вендора managed Windows hosting для будущего переезда IIS с windows-recovery-host (домашней машины). Output: 1-pager с recommended vendor + cost estimate + migration recipe outline.
|
||||||
|
|
||||||
Это **переходный** трек до завершения snolla node-rewrite'а (после которого IIS не нужен вообще). Не файлим impl-таску миграции до этой research'и — vendor выбираем сначала.
|
Это **переходный** трек до завершения snolla node-rewrite'а (после которого IIS не нужен вообще). Не файлим impl-таску миграции до этой research'и — vendor выбираем сначала.
|
||||||
|
|||||||
91
.tasks/iis-cutover-to-vds-services.md
Normal file
91
.tasks/iis-cutover-to-vds-services.md
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
# iis-cutover-to-vds-services
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
Перенастроить IIS на [[../entities/windows-recovery-host]] так чтобы CMS sites обращались к **MSSQL/MinIO/imgproxy на VDS** вместо localhost-контейнеров. Это **финальный шаг** ради которого всё затевалось — миграция MSSQL/MinIO бессмысленна без репойнта IIS.
|
||||||
|
|
||||||
|
**Depends on:**
|
||||||
|
- `mssql-vds-migration` — MSSQL должен быть live на `mssql.kzntsv.site:1433` с restored DBs
|
||||||
|
- `minio-imgproxy-vds-migration` — MinIO + imgproxy live на `minio.vds.kzntsv.site` / `imgproxy.kzntsv.site`
|
||||||
|
|
||||||
|
Cutover атомарный: один web.config edit + iisreset = 11 хостов мигрируют разом. Rollback = revert backup.
|
||||||
|
|
||||||
|
## Key files / refs
|
||||||
|
- **Catch-all IIS site `snolla`** (`*:80` + `*:8089`, [[../.wiki/concepts/recovery-architecture-snapshot]] §"Host IIS configuration") — `C:\sites\snolla\web.config` обслуживает **11 CMS hosts** через traefik backend `host.docker.internal:8089`:
|
||||||
|
- snolla.com + 10 *.snolla.com subdomains
|
||||||
|
- labtools.ru / labtools.pro
|
||||||
|
- pilorama98.ru, tandemmebel.ru, emspb.ru, kupimknigi.spb.ru
|
||||||
|
- maljarka.tandemmebel.ru, sestech.ru, ics-artmaterials.com
|
||||||
|
- **Local-only IIS sites** (не через traefik, local-only):
|
||||||
|
- `stostayer` (`*:8090`) — `C:\sites\stostayer\web.config`, conn уже `www.stostayer.ru,1433` (external — может не требовать изменений)
|
||||||
|
- `stostayer.old` (`*:8091`) — `C:\sites\stostayer.old\web.config`, conn `localhost,1433` → требует repoint
|
||||||
|
- **Source MSSQL endpoint** (current): `Data Source=localhost,1433` (для snolla + stostayer.old)
|
||||||
|
- **Target MSSQL endpoint** (new): `Data Source=mssql.kzntsv.site,1433;TrustServerCertificate=true` (self-signed cert через traefik TCP passthrough)
|
||||||
|
- **MinIO/imgproxy CMS settings** — точное место в config TBD (audit step 1). Возможно `appSettings` в web.config или отдельный config-файл (CMS уровня).
|
||||||
|
- **Per-DB mapping** (какой site какую DB трогает — verify через `sp_helpdb` или audit web.config'ов):
|
||||||
|
- snolla → likely `MoreThenCms` + `stostayer` (один CMS на много sites)
|
||||||
|
- stayer sites → `StayerCalculator` / `StayerPrice` / `TireService`
|
||||||
|
|
||||||
|
## Acceptance
|
||||||
|
1. **Audit config locations:**
|
||||||
|
- `Get-ChildItem -Recurse C:\sites -Include web.config,appsettings.*.json,*.config | Select-String -Pattern 'localhost,1433|localhost:9000|localhost:8788|Data Source|connectionString'`
|
||||||
|
- Документировать в task'е (или в `.wiki/concepts/cms-config-locations.md`): какой site какой config trогает, какие conn-strings, какие MinIO/imgproxy refs.
|
||||||
|
2. **Pre-cutover benchmark** (mandatory, см. risks в `mssql-vds-migration`):
|
||||||
|
- Прогнать на каждом hot-path до cutover (LOCALHOST baseline): admin/assets/getList, search, каталоги. Сохранить в `.wiki/sources/iis-cutover-benchmark-<date>.md`.
|
||||||
|
- Pass criteria: после cutover degradation <2x. Если worse — discuss с user перед commit.
|
||||||
|
3. **Backup configs:**
|
||||||
|
```powershell
|
||||||
|
Get-ChildItem C:\sites\*\web.config | %{ Copy-Item $_ "$($_.FullName).bak-pre-vds-cutover-$(Get-Date -Format yyyyMMdd)" }
|
||||||
|
```
|
||||||
|
4. **Edit conn-strings** в `C:\sites\snolla\web.config` (catch-all для 11 хостов) + `C:\sites\stostayer.old\web.config`:
|
||||||
|
- `localhost,1433` → `mssql.kzntsv.site,1433`
|
||||||
|
- Добавить `;TrustServerCertificate=true` (self-signed TLS через traefik passthrough)
|
||||||
|
- Если `Encrypt=False` явно стоит — оставить (Encrypt=True + TrustServerCertificate ОК тоже, но fewer changes safer)
|
||||||
|
- `stostayer` (`www.stostayer.ru,1433`) — оставить как есть (уже external, не наш scope)
|
||||||
|
5. **Edit MinIO/imgproxy endpoints** (после step 1 audit точные места known):
|
||||||
|
- `localhost:9000` → `minio.vds.kzntsv.site` (HTTPS) для S3 calls из CMS
|
||||||
|
- `localhost:8788` → `imgproxy.kzntsv.site` для image-proxy URL'ов (если hardcoded; idealistic — через `IMGPROXY_BASE_URL` env)
|
||||||
|
6. **Cutover:**
|
||||||
|
- `iisreset /restart` (или `Restart-WebAppPool snolla` если selective).
|
||||||
|
- Smoke 8 priority hosts (verified live в `[iis-on-host-migration]` close-out): `emspb / snolla / on.snolla / pilorama98 / labtools.ru / labtools.pro / tandemmebel / kupimknigi` — каждый 200 OK + asset loading + admin login (если scope).
|
||||||
|
- admin/assets/getList на одном из них — hot-path verify.
|
||||||
|
7. **Post-cutover benchmark** — те же запросы что в step 2, сравнить latency. Documented в same `.wiki/sources/iis-cutover-benchmark-<date>.md`.
|
||||||
|
8. **MinIO write smoke** — загрузить тестовый asset через admin UI → verify в VDS MinIO (`mc ls new/<bucket>`), убедиться что imgproxy его рендерит через `imgproxy.kzntsv.site`.
|
||||||
|
9. **48ч soak**:
|
||||||
|
- Monitoring через existing `vds-ops` ntfy topic + manual phone check 8 hosts на 24ч / 48ч марках.
|
||||||
|
- Если regression — atomic revert (см. notes).
|
||||||
|
10. **Source decommission** (через 48ч green):
|
||||||
|
- На windows-host: `docker stop mssql minio imgproxy imgproxy-nginx` (через неделю → `docker rm + volume rm`).
|
||||||
|
- Списать `cms-stopgap-backup-daily` cron (теперь VDS backup pipeline покрывает).
|
||||||
|
11. **Documented** в [[../.wiki/concepts/iis-cutover-to-vds-services]] (создать): pre/post architecture diagrams, edit-diff'ы конфигов, benchmark numbers, rollback recipe.
|
||||||
|
|
||||||
|
## Decisions
|
||||||
|
- **Cutover style: atomic** (не gradual canary). 1 web.config edit → iisreset → 11 хостов мигрируют разом. Rationale: snolla catch-all = единая точка изменения, gradual невозможен без дублирования IIS sites (overkill).
|
||||||
|
- **TLS:** `TrustServerCertificate=true` в conn-string (self-signed cert через traefik passthrough). Permanent fix позже через LE-cert extract в DBs (см. [[vds-kzntsv-bootstrap]] Open questions).
|
||||||
|
- **stostayer site (external `www.stostayer.ru`)** не трогаем — уже external endpoint, отдельный scope.
|
||||||
|
- **maljarka.tandemmebel.ru 502 bug** не блокер этой таски (existing issue, [[../.tasks/iis-traefik-dead-routes-cleanup]] side-finding, отдельная CMS-task'а в MoreThenCms).
|
||||||
|
|
||||||
|
## Open questions (решаются audit step 1)
|
||||||
|
- [ ] **MinIO/imgproxy конфигурация** — где живёт endpoint config? В web.config `<appSettings>` или отдельный JSON / DLL config? Если hardcoded в скомпилированной DLL — рестарт CMS не поможет, нужен rebuild. См. [[../.wiki/concepts/cms-admin-assets-root-folder-seed]] §"Долгосрочный TODO" — это известная техдыра.
|
||||||
|
- [ ] **Per-site DB mapping** — какой web.config какую MSSQL DB указывает? Audit step 1 даст карту.
|
||||||
|
- [ ] **HTTPS для MSSQL conn-string** — `Encrypt=True;TrustServerCertificate=true` vs `Encrypt=False`? Текущие conn-strings в snolla web.config — unknown, audit показиет.
|
||||||
|
|
||||||
|
## Risks
|
||||||
|
- **Hardcoded DLL endpoints** — если MinIO/imgproxy URLs запечены в скомпилированных CMS DLL, repoint требует rebuild → build env вопрос. **Mitigation:** audit step 1 покажет; если hardcoded — fallback вариант: оставить imgproxy-nginx на windows-host, проксировать через него на VDS MinIO (transparent для CMS).
|
||||||
|
- **WAN latency** — admin/assets/getList sensitive (большие в-памяти выборки). 10-30ms vs localhost. Pre/post benchmark обязателен. Если degradation >2x — обсуждать query optimization vs retreat.
|
||||||
|
- **TLS chain** — self-signed cert через traefik passthrough требует `TrustServerCertificate=true` или import cert в Windows trust store. Первое проще, второе secure-er. Choose first для migration, secure-fix позже.
|
||||||
|
- **DNS propagation** — `mssql.kzntsv.site` DNS должен propagate ДО iisreset. User уже сделал A-record (2026-05-22). TTL 300s default REGRU → 5 min wait после propagate-check (`Resolve-DnsName mssql.kzntsv.site`).
|
||||||
|
- **MinIO bucket policy / CORS** — если CMS делает PUT через browser-direct upload → CORS policy на VDS MinIO должна включать domain'ы клиентских сайтов. Verify в smoke step 8.
|
||||||
|
- **Cutover failure rollback delay** — revert web.config + iisreset ~30 sec. Если windows-host MSSQL container остановлен — rollback fails. **Mitigation:** keep windows-host containers running 48ч (acceptance 10 это закладывает).
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
- **Branch:** master (per project-discipline rule 2 — no feature branches без user approval).
|
||||||
|
- **Atomic revert:**
|
||||||
|
```powershell
|
||||||
|
Get-ChildItem C:\sites\*\web.config.bak-pre-vds-cutover-* | %{
|
||||||
|
$orig = $_.FullName -replace '\.bak-pre-vds-cutover-\d+$',''
|
||||||
|
Copy-Item $_.FullName -Destination $orig -Force
|
||||||
|
}
|
||||||
|
iisreset /restart
|
||||||
|
```
|
||||||
|
Затем убедиться что windows-host MSSQL + MinIO + imgproxy containers всё ещё running. Если уже остановлены — `docker start mssql minio imgproxy imgproxy-nginx`.
|
||||||
|
- **Why this task exists separately from migrations:** разные skill-sets (migrations = Linux/docker/VDS; cutover = IIS/web.config/Windows), разные failure-modes, разные rollback-paths, разное окно работы (migrations можно делать в любое время; cutover = maintenance window). Splitting позволяет migrations завершиться + soak без давления на cutover-timing.
|
||||||
69
.tasks/minio-imgproxy-vds-migration.md
Normal file
69
.tasks/minio-imgproxy-vds-migration.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# minio-imgproxy-vds-migration
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
Перенести MinIO + imgproxy + imgproxy-nginx контейнеры с [[../entities/windows-recovery-host]] на [[../entities/vds-kzntsv]]. Заодно **upgrade MinIO** с `RELEASE.2020-07-13` (5 лет, куча CVE) на `minio/minio:latest`. Доступ снаружи через `minio.vds.kzntsv.site` (S3 API + console).
|
||||||
|
|
||||||
|
Это **MinIO+imgproxy половина** umbrella'ы `mssql-minio-migration-to-vds` (декомпозирована 2026-05-22). Вторая половина — `mssql-vds-migration`.
|
||||||
|
|
||||||
|
## Key files / refs
|
||||||
|
- **Source MinIO:** docker container `minio` на windows-recovery-host, image `minio/minio:RELEASE.2020-07-13T18-09-56Z`, bind `C:\Users\vitya\projects\docker\diskstation\minio\data` → `/data`, ~3 GB.
|
||||||
|
- **Source imgproxy:** docker container `imgproxy`, image `darthsim/imgproxy`, port 8787:8080. Зависит от MinIO как S3 backend.
|
||||||
|
- **Source imgproxy-nginx:** docker container `imgproxy-nginx`, image `nginx:alpine`, port 8788:80. Reverse-proxy перед imgproxy с caching.
|
||||||
|
- **Target stack:** `/opt/stacks/storage/minio-imgproxy/{docker-compose.yml,.env,data,nginx-cache,nginx.conf}` на VDS.
|
||||||
|
- **Target MinIO image:** `minio/minio:latest` (или pinned tag `RELEASE.2025-*`).
|
||||||
|
- **CMS endpoints:**
|
||||||
|
- MinIO S3: `localhost:9000` → `minio.vds.kzntsv.site` (HTTPS) для external, `http://minio:9000` для inter-container на VDS через `shared-dbs` network.
|
||||||
|
- imgproxy: `localhost:8788` → `imgproxy.kzntsv.site` (если CMS реверс-проксит) или прямо в CMS-template URL.
|
||||||
|
|
||||||
|
## Decisions
|
||||||
|
- **Upgrade MinIO** (user 2026-05-22, conditional «если ничего не сломает»). Migration via `mc mirror old-minio → new-minio`. Если совместимость bucket-format ломается → fallback `aws s3 sync`. **Rollback ready** через сохранённый snapshot bind-mount data.
|
||||||
|
- **imgproxy + imgproxy-nginx** едут вместе — `IMGPROXY_S3_ENDPOINT` поменять на `http://minio:9000` (internal через `shared-dbs`), не external — экономит latency и не гоняет S3 traffic через traefik.
|
||||||
|
- **Hostname: `minio.vds.kzntsv.site`** (user 2026-05-22). S3 API + Console на одном subdomain (MinIO 2022+ split на :9000 API + :9001 console — два под-роута через traefik PathPrefix или два subdomain).
|
||||||
|
|
||||||
|
## Acceptance
|
||||||
|
1. **Stack deployed на VDS:**
|
||||||
|
- `/opt/stacks/storage/minio-imgproxy/docker-compose.yml` — 3 сервиса: `minio`, `imgproxy`, `imgproxy-nginx`.
|
||||||
|
- `minio` — `minio/minio:latest`, bind `./data:/data`, env `MINIO_ROOT_USER`/`MINIO_ROOT_PASSWORD` из `pass show minio-vds/root-creds`.
|
||||||
|
- Networks `proxy` (для traefik) + `shared-dbs` (для inter-container).
|
||||||
|
2. **Traefik routing:**
|
||||||
|
- `minio.vds.kzntsv.site` → HTTPS → minio:9000 (S3 API).
|
||||||
|
- `minio-console.vds.kzntsv.site` → HTTPS → minio:9001 (web UI, basicAuth optional).
|
||||||
|
- LE certs auto-issued через existing acme.json.
|
||||||
|
3. **Data migration:**
|
||||||
|
- Snapshot: `tar czf minio-bind-snapshot-$(date +%Y%m%d).tar.gz C:\Users\vitya\projects\docker\diskstation\minio\data` (3 GB → ~3 GB compressed) — rollback insurance.
|
||||||
|
- Поднять new MinIO **пустой** на VDS, создать matching buckets.
|
||||||
|
- `mc alias set old http://localhost:9000 …` + `mc alias set new https://minio.vds.kzntsv.site …`.
|
||||||
|
- `mc mirror --preserve old/<bucket> new/<bucket>` для каждого bucket.
|
||||||
|
- **Verify:** `mc ls --recursive old/<b>` vs `mc ls --recursive new/<b>` — diff пустой, total size match (±0 bytes).
|
||||||
|
- **Fallback при ошибках mc mirror:** `aws s3 sync s3://old/<b> s3://new/<b> --endpoint-url=…`.
|
||||||
|
4. **imgproxy + imgproxy-nginx подняты на VDS:**
|
||||||
|
- `IMGPROXY_S3_ENDPOINT=http://minio:9000`, `IMGPROXY_USE_S3=true`, `AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY` из MinIO creds.
|
||||||
|
- `imgproxy-nginx` reverse-proxy с caching layer перед imgproxy.
|
||||||
|
- Сохранить cache path/sizing config с source (`/var/cache/nginx/imgproxy` или эквивалент).
|
||||||
|
5. **CMS endpoints repointed:**
|
||||||
|
- MinIO endpoint в CMS config → `minio.vds.kzntsv.site` (или прямо `http://minio:9000` если CMS migrate тоже на VDS позже).
|
||||||
|
- imgproxy URL pattern в CMS templates → новый адрес.
|
||||||
|
- Smoke: 8 sites загружают images через imgproxy (admin assets UI + клиентские thumbnails).
|
||||||
|
6. **Backup pipeline на VDS расширен** (`/opt/stacks/backup/scripts/run.sh`):
|
||||||
|
- `minio_mirror` ежедневно — либо `mc mirror local→backup-bucket-on-kreknin`, либо `rsync /opt/stacks/storage/minio-imgproxy/data → kreknin`. Recommend rsync — проще и hardlink-friendly.
|
||||||
|
7. **ntfy push verified** для расширенного pipeline (включает MinIO size/duration).
|
||||||
|
8. **Source windows-host:** после 48ч uptime на VDS — `docker stop minio imgproxy imgproxy-nginx`, через неделю `docker rm + docker volume rm` (minio bind-dir — оставить tar snapshot ещё месяц).
|
||||||
|
9. **Documented** в [[../.wiki/concepts/minio-imgproxy-on-vds]] (создать): architecture, MinIO upgrade notes (что сломалось при `mc mirror` если что-то), rollback recipe, migration runbook.
|
||||||
|
|
||||||
|
## Open questions
|
||||||
|
- [ ] **DNS A-records** `minio.vds.kzntsv.site` + `minio-console.vds.kzntsv.site` → VDS IP — REGRU API или manual?
|
||||||
|
- [ ] **MinIO upgrade compat** — есть ли в bucket'ах metadata format'ы которые новый MinIO не читает? `mc admin info` на source + dry-run `mc mirror --dry-run` для оценки. Если ругается → план B: запустить **тот же** старый MinIO image на VDS, мигрировать as-is, upgrade отдельной таской позже.
|
||||||
|
- [ ] **imgproxy version** — текущий `darthsim/imgproxy` (no tag = latest на момент pull). Upgrade сразу или сохранить same digest? Рекомендую pin digest sources → use same on VDS, separate upgrade task.
|
||||||
|
- [ ] **nginx cache size on VDS** — сколько диска готов выделить под `imgproxy-nginx` cache? Текущее consumption на windows — проверить через `du -sh` к bind-mount.
|
||||||
|
|
||||||
|
## Risks
|
||||||
|
- **MinIO format compat (5-year gap):** RELEASE.2020-07-13 → 2025+. `xl.meta` format и erasure-coding mode менялись. `mc mirror` обычно работает (read API stable), но edge-cases возможны. **Mitigation:** snapshot bind-mount + dry-run mirror + fallback aws-s3-sync.
|
||||||
|
- **imgproxy ENV vars** могли переименоваться между версиями (IMGPROXY_S3_* prefix vs IMGPROXY_OBJECT_STORAGE_*). Проверить current container env (`docker inspect imgproxy`) и сопоставить с current imgproxy docs.
|
||||||
|
- **External URL change** — клиентские sites которые ссылаются на `localhost:8788/...` или hardcoded image URLs ломаются. Audit обязателен (`grep -r '8788\|localhost:9000' web.config + appsettings`).
|
||||||
|
- **VDS RAM:** minio idle ~50 MB, imgproxy ~30 MB. Negligible.
|
||||||
|
- **VDS Disk:** ~3 GB MinIO + nginx cache (5-10 GB?) + imgproxy temp. Total ~15 GB. **Проверить `df -h /opt/stacks` перед стартом.**
|
||||||
|
- **DNS propagation:** A-record нужно ставить минимум за 1-2ч до cutover (TTL 300 sec default REGRU).
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
- **Зависит от:** `mssql-vds-migration` (нет — независимы).
|
||||||
|
- **Atomic revert (full):** revert CMS endpoints → windows-host MinIO; на VDS — `docker compose down -v` для minio-imgproxy stack; удалить minio nogi из `run.sh`; remove traefik routes. Snapshot tar — rollback source при необходимости.
|
||||||
77
.tasks/mssql-vds-migration.md
Normal file
77
.tasks/mssql-vds-migration.md
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# mssql-vds-migration
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
Перенести MSSQL контейнер с [[../entities/windows-recovery-host]] на [[../entities/vds-kzntsv]] (`/opt/stacks/databases/mssql/`), Express Edition для прода, доступ снаружи через `mssql.kzntsv.site:1433` (traefik TCP passthrough), интеграция в существующий `vds-backup-rsync-kreknin` pipeline.
|
||||||
|
|
||||||
|
Это **MSSQL-only половина** umbrella'ы `mssql-minio-migration-to-vds` (декомпозирована 2026-05-22). Вторая половина — `minio-imgproxy-vds-migration`.
|
||||||
|
|
||||||
|
## Key files / refs
|
||||||
|
- **Source:** docker container `mssql` на windows-recovery-host, image `mcr.microsoft.com/mssql/server:2019-latest`, volume `mssql_mssql_data` (26.6 GB total, real data ~2.4 GB, остальное .ldf logs).
|
||||||
|
- **Source DBs** (verified via `docker exec mssql ls /var/opt/mssql/data/`, 2026-05-22):
|
||||||
|
- `MoreThenCms.mdf` 867 MB + log 9.9 GB
|
||||||
|
- `StayerCalculator.mdf` 504 MB + log 1.2 GB
|
||||||
|
- `StayerPrice.mdf` 38 MB + log 215 MB
|
||||||
|
- `TireService.mdf` 8 MB + log 8 MB
|
||||||
|
- `stostayer.mdf` 968 MB + log 264 MB
|
||||||
|
- **Max .mdf 968 MB < 10 GB Express limit ✓ all fit**
|
||||||
|
- **Target:** `/opt/stacks/databases/mssql/{data,docker-compose.yml,.env}` на VDS, паттерн как у postgres (`/opt/stacks/databases/postgres/data` bind, network `proxy` + `shared-dbs`).
|
||||||
|
- **Image:** `mcr.microsoft.com/mssql/server:2022-latest` Express Edition (`MSSQL_PID=Express`).
|
||||||
|
- **CMS connection strings:** `Data Source=localhost,1433` → `Data Source=mssql.kzntsv.site,1433` в IIS web.config / appsettings.
|
||||||
|
- **TLS:** self-signed, traefik raw-TCP passthrough — pattern [[../.wiki/concepts/db-tls-self-signed-via-traefik-raw-tcp]] + [[../.wiki/concepts/traefik-tcp-passthrough-vs-starttls]].
|
||||||
|
- **Backup pipeline:** `/opt/stacks/backup/scripts/run.sh` на VDS — добавить новые ноги (см. acceptance 6).
|
||||||
|
|
||||||
|
## Decisions
|
||||||
|
- **Edition: Express** (user 2026-05-22). Max DB size 10 GB соблюдён всеми текущими базами. RAM cap Express = 1.4 GB built-in. Дополнительно `MSSQL_MEMORY_LIMIT_MB=2048` (user-confirmed), но Express всё равно сам зажмёт до 1410.
|
||||||
|
- **Method: BACKUP DATABASE … WITH COMPRESSION, COPY_ONLY** → scp `.bak` → RESTORE на VDS. Не detach/attach — кросс-edition (Developer → Express) supported только через backup/restore. Compression ≈ 80% reduction, ожидаемый transfer ~500 MB.
|
||||||
|
- **Pre-cutover SHRINKFILE на .ldf** — срежет 12 GB logs до минимума (не для transfer — для cleanup source перед миграцией; transfer идёт через .bak, который и так не включает inactive log space).
|
||||||
|
- **Hostname: `mssql.kzntsv.site`** (не `mssql.vds.kzntsv.site` — user decision 2026-05-22). DNS A-record указать на VDS IP.
|
||||||
|
|
||||||
|
## Acceptance
|
||||||
|
1. **Pre-cutover на source** (windows-host):
|
||||||
|
- `BACKUP LOG <db> WITH TRUNCATE_ONLY` + `CHECKPOINT` + `DBCC SHRINKFILE` для .ldf всех 5 prod DBs.
|
||||||
|
- Verify `du -sh /var/opt/mssql/data/*_log.ldf` → каждый < 100 MB.
|
||||||
|
- **WARNING:** SHRINKFILE с TRUNCATE_ONLY ломает log-chain → no point-in-time restore до следующего FULL backup. Делается **только** в migration window, новый FULL снимается сразу после RESTORE на VDS.
|
||||||
|
2. **MSSQL container на VDS** запущен:
|
||||||
|
- `mcr.microsoft.com/mssql/server:2022-latest`, `ACCEPT_EULA=Y`, `MSSQL_PID=Express`, `MSSQL_MEMORY_LIMIT_MB=2048`, `SA_PASSWORD` из `pass show mssql-vds/sa-password` (новый pass entry).
|
||||||
|
- Volume bind `/opt/stacks/databases/mssql/data:/var/opt/mssql:rw`.
|
||||||
|
- Networks `proxy` + `shared-dbs`. Traefik labels TCP entrypoint `mssql` :1433 → HostSNI(`*`).
|
||||||
|
3. **Traefik static config** (`/opt/stacks/proxy/traefik/traefik.yml`):
|
||||||
|
```yaml
|
||||||
|
entryPoints:
|
||||||
|
mssql:
|
||||||
|
address: ":1433"
|
||||||
|
```
|
||||||
|
+ ufw allow 1433/tcp.
|
||||||
|
4. **5 prod DBs restored** на VDS:
|
||||||
|
- `BACKUP DATABASE … WITH COMPRESSION, COPY_ONLY` на source → 5 `.bak` файлов.
|
||||||
|
- scp → `/opt/stacks/databases/mssql/data/backups/` на VDS.
|
||||||
|
- `RESTORE DATABASE … FROM DISK='/var/opt/mssql/backups/<db>.bak' WITH MOVE`.
|
||||||
|
- Verify `SELECT name, state_desc FROM sys.databases` → все 5 ONLINE, `DBCC CHECKDB('<db>')` → 0 errors на каждой.
|
||||||
|
5. **CMS connection strings updated** в web.config (или эквиваленте), 8 sites smoke:
|
||||||
|
- 200 OK + asset loading + admin/assets/getList (известный hot-path).
|
||||||
|
- **Pre-cutover benchmark обязателен** — admin assets UI / search / catalogs latency измерены до и после, **degradation <2x** target. Если worse — discuss перед commit'ом cutover (10-30ms WAN vs localhost).
|
||||||
|
6. **Backup pipeline на VDS расширен** (`/opt/stacks/backup/scripts/run.sh`):
|
||||||
|
- `mssql_dump_full` ежедневно (BACKUP DATABASE WITH COMPRESSION для каждой DB → tar.gz → rsync nightly).
|
||||||
|
- `mssql_tx_log_backup` ежечасно (BACKUP LOG для каждой DB через `docker exec mssql /opt/mssql-tools/bin/sqlcmd …`) → rsync hourly. **Достигает target RPO 1ч.**
|
||||||
|
7. **ntfy push verified** для расширенного pipeline (включает MSSQL dump size/duration).
|
||||||
|
8. **Source windows-host MSSQL** — после 48ч uptime на VDS: stop container (read-only fallback пропустить — pass), через неделю — `docker rm + docker volume rm mssql_mssql_data`.
|
||||||
|
9. **Documented** в [[../.wiki/concepts/mssql-on-vds]] (создать): architecture, rollback recipe (revert connection strings + start windows-host MSSQL container), migration runbook.
|
||||||
|
|
||||||
|
## Open questions
|
||||||
|
- [ ] **DNS A-record `mssql.kzntsv.site` → VDS IP** (89.253.255.94) — сделать через REGRU API или manual?
|
||||||
|
- [ ] **Hermes service на windows-host** — зависит от local MSSQL? Если да — мигрируется заодно или ломается. См. [[../.wiki/entities/vds-kzntsv]] Open issues.
|
||||||
|
- [ ] **CMS connection-string location** — web.config? appsettings? hardcoded в DLL? Если hardcoded — нужен rebuild (build env вопрос). См. note в [[../.wiki/concepts/cms-admin-assets-root-folder-seed]] §"Долгосрочный TODO".
|
||||||
|
|
||||||
|
## Risks
|
||||||
|
- **WAN latency IIS→MSSQL:** 10-30ms vs localhost. Большинство CMS-операций batchey, не latency-sensitive. **Pre-cutover benchmark обязателен** (acceptance 5).
|
||||||
|
- **Express Edition limits:** 10 GB/DB, 1.4 GB RAM, 1 socket / 4 cores. Max .mdf сейчас 968 MB — запас 10x. Если `stostayer` начнёт расти — early warning через monitoring (separate task).
|
||||||
|
- **MSSQL Linux compat:** некоторые edge-case T-SQL отличаются (CLR, FileStream, full-text). Smoke обязателен — `EXEC sp_helpdb` + проверить нет ли CLR assemblies / FileStream filegroups в prod DBs.
|
||||||
|
- **TLS overhead:** raw-TCP через traefik adds <1ms — negligible.
|
||||||
|
- **VDS RAM tight:** owncloud `anon` 282 MB + gitea 834 MB + verdaccio 226 MB + DBs 285 MB + traefik 52 MB + redis 6 MB = ~1.7 GB реально используется (page-cache reclaimable). MSSQL 2 GB влезает с запасом 4 GB до OOM.
|
||||||
|
- **Disk free на VDS не проверен** (ops-mcp read-only docker). Нужно ~3 GB MSSQL restored + ~5 GB free для backup'ов. **Проверить `df -h /opt/stacks` ssh'ем перед стартом.**
|
||||||
|
- **Cutover rollback:** revert возможен только если windows-host MSSQL container оставлен running (read-only желательно но не критично) 48ч после cutover. Acceptance 8 это закладывает.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
- **Зависит от:** `minio-imgproxy-vds-migration` (нет — независимы).
|
||||||
|
- **Зависимая follow-up:** списать `cms-stopgap-backup-daily` cron после успешного first VDS backup-pipeline run.
|
||||||
|
- **Atomic revert (full):** revert CMS web.config → windows-host MSSQL; восстановить cms-stopgap-backup-daily cron; на VDS — `docker compose down -v` для mssql stack; удалить mssql ноги из `run.sh`; remove traefik mssql entrypoint; ufw deny 1433/tcp.
|
||||||
122
.wiki/concepts/minio-imgproxy-on-vds.md
Normal file
122
.wiki/concepts/minio-imgproxy-on-vds.md
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
---
|
||||||
|
title: MinIO + imgproxy stack on vds-kzntsv
|
||||||
|
status: live as standby — CMS image pipeline остаётся на windows-host (closed-source DLL hardcoded URL)
|
||||||
|
tags: [vds, minio, imgproxy, migration, ops]
|
||||||
|
related: [[vds-kzntsv]], [[recovery-architecture-snapshot]], [[mssql-on-vds]]
|
||||||
|
---
|
||||||
|
|
||||||
|
# MinIO + imgproxy on vds-kzntsv
|
||||||
|
|
||||||
|
Запущен 2026-05-22 как часть `minio-imgproxy-vds-migration`. Заодно **upgrade MinIO** `RELEASE.2020-07-13` (5 лет, CVE-куча) → `RELEASE.2025-09-07`.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
CMS templates (URL pattern: imgproxy.kzntsv.site/<sig>/.../plain/s3://<bucket>/<path>)
|
||||||
|
→ traefik (windows-host) [пока, до DNS swap]
|
||||||
|
→ imgproxy-nginx (windows-host) [пока]
|
||||||
|
→ imgproxy (windows-host) [пока]
|
||||||
|
→ MinIO localhost:9000 (windows-host) [пока]
|
||||||
|
|
||||||
|
После DNS swap imgproxy.kzntsv.site → 89.253.255.94 (VDS):
|
||||||
|
→ VDS traefik (HTTPS, LE cert)
|
||||||
|
→ imgproxy-nginx (VDS, nginx:alpine, 10 GB cache)
|
||||||
|
→ imgproxy (VDS, darthsim/imgproxy:latest)
|
||||||
|
→ minio (VDS, RELEASE.2025-09-07, internal docker DNS через proxy network)
|
||||||
|
```
|
||||||
|
|
||||||
|
Stack: `/opt/stacks/storage/minio-imgproxy/{docker-compose.yml,.env,data,nginx.conf,nginx-cache}`. Все 3 контейнера в `proxy` network — service-name DNS работает.
|
||||||
|
|
||||||
|
**Traefik routes (live):**
|
||||||
|
- `minio.vds.kzntsv.site` → minio:9000 (S3 API)
|
||||||
|
- `minio-console.vds.kzntsv.site` → minio:9001 (web UI)
|
||||||
|
- `imgproxy.vds.kzntsv.site` → imgproxy-nginx:80 (test endpoint pre-cutover)
|
||||||
|
|
||||||
|
После DNS swap имя `imgproxy.kzntsv.site` (без `.vds.`) добавить в traefik label imgproxy-nginx сервиса.
|
||||||
|
|
||||||
|
## Migration recipe
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. pass insert (local) — preserve original IMGPROXY_KEY/SALT, reuse MinIO creds
|
||||||
|
pass insert -m minio-vds/full-env <<EOF
|
||||||
|
MINIO_ROOT_USER=<same-as-source>
|
||||||
|
MINIO_ROOT_PASSWORD=<same-as-source>
|
||||||
|
IMGPROXY_KEY=<same-as-source-128hex>
|
||||||
|
IMGPROXY_SALT=<same-as-source-128hex>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 2. VDS: create dir + scp nginx.conf + write .env from pass + write compose
|
||||||
|
ssh vitya@vds 'sudo mkdir -p /opt/stacks/storage/minio-imgproxy/{data,nginx-cache}
|
||||||
|
sudo chown -R vitya:vitya /opt/stacks/storage'
|
||||||
|
scp <source>/nginx.conf vitya@vds:/opt/stacks/storage/minio-imgproxy/
|
||||||
|
pass show minio-vds/full-env | ssh vitya@vds 'cat > /opt/stacks/storage/minio-imgproxy/.env
|
||||||
|
chmod 600 .env'
|
||||||
|
|
||||||
|
# 3. docker compose up -d (image pull + start all 3)
|
||||||
|
|
||||||
|
# 4. Local mc setup + bucket prep
|
||||||
|
mc alias set old http://localhost:9000 <creds>
|
||||||
|
mc alias set new https://minio.vds.kzntsv.site <creds> --insecure
|
||||||
|
for b in $(mc ls old | awk '{print $NF}' | tr -d /); do
|
||||||
|
mc mb --ignore-existing new/$b --insecure # mc 2025 не auto-creates на mirror
|
||||||
|
done
|
||||||
|
|
||||||
|
# 5. Mirror (background, ~1 час на 3 GB при 600 KiB/s)
|
||||||
|
mc mirror --preserve --quiet --overwrite old new --insecure
|
||||||
|
|
||||||
|
# 6. Verify per-bucket (size + object count)
|
||||||
|
for b in $(mc ls old | awk '{print $NF}' | tr -d /); do
|
||||||
|
echo "[$b]"; mc du old/$b; mc du new/$b --insecure
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gotchas
|
||||||
|
|
||||||
|
1. **MinIO upgrade 5-летний gap WORKS via mc mirror** — старый FS backend (2020) → новый erasure-coded single-drive (2025) совместим через S3 API copy. `mc mirror` reads через S3 API, не сырое filesystem. Бинарный bind-mount свопнуть НЕЛЬЗЯ — формат `xl.meta` разный, новый MinIO не поднимется на старых dirs.
|
||||||
|
2. **mc 2025 НЕ auto-creates target buckets** — old mc (<2023?) делало неявно. Симптом: `Failed to perform mirroring The specified bucket does not exist`. Fix: `mc mb --ignore-existing new/<b>` для каждого bucket заранее.
|
||||||
|
3. **Non-ASCII filenames + slow uplink → partial mirror failure**: один файл `Albrecht Dürer ...tif` (30 MiB) в `imgproxytest` bucket не доехал с первого `mc mirror` exit=0 — silent skip без error. Retry того же `mc mirror` подтащил. Recommendation: всегда verify по object count + size после mirror, не doверять exit code.
|
||||||
|
4. **IMGPROXY_KEY + IMGPROXY_SALT preserve обязательно** — это HMAC signing для URLs. Если поменять, все pre-existing CMS image URLs (signed ссылки в шаблонах + кешированные в admin) ломаются. Reuse same values из source.
|
||||||
|
5. **MinIO root creds vs AWS-style**: source использует MINIO_ACCESS_KEY/MINIO_SECRET_KEY (deprecated env vars), новый MinIO — MINIO_ROOT_USER/MINIO_ROOT_PASSWORD. Reuse same values (no rotation в этой миграции) → CMS+imgproxy credentials не меняются. Rotation — отдельная hardening-таска.
|
||||||
|
|
||||||
|
## CMS image pipeline — DLL hardcoded constraint (2026-05-22 finding)
|
||||||
|
|
||||||
|
Browser-side URL pattern: `https://www.<site>/imgproxy/<sig>/fill/W/H/no/1/<base64(s3://<bucket>/<path>)>.<ext>`. Sample (working URL provided by user):
|
||||||
|
```
|
||||||
|
https://www.pilorama98.ru/imgproxy/3rGOrTLEtTSjsrwvbs2fe75A1jDHFGPbaSe9ea7vtPQ/fill/800/800/no/1/czM6Ly9waWxvcmFtYTk4L3Byb2R1Y3RzL2wvOWQ0MjgwODktMGFjYi00ZGM2LWE3YjAtMGQxYzIxN2E1ZTFjLmpwZw.webp
|
||||||
|
```
|
||||||
|
Base64 source decode: `s3://pilorama98/products/l/9d428089-0acb-4dc6-a7b0-0d1c217a5e1c.jpg`. HMAC signature `3rGOr...` computed from `IMGPROXY_KEY + SALT` (preserved в нашей миграции).
|
||||||
|
|
||||||
|
**Server-side architecture:**
|
||||||
|
```
|
||||||
|
Browser → https://www.<site>/imgproxy/<sig>/...
|
||||||
|
→ traefik (windows-host) → IIS snolla site :8089
|
||||||
|
→ ImgproxyHandler (MoreThenCms.Modules.Imgproxy.dll, closed-source)
|
||||||
|
→ HTTP GET https://imgproxy.kzntsv.site/<sig>/... (HARDCODED in DLL)
|
||||||
|
→ traefik (windows-host) imgproxy.yml route
|
||||||
|
→ imgproxy-nginx:80 → imgproxy → MinIO localhost:9000
|
||||||
|
```
|
||||||
|
|
||||||
|
Decoded DLL strings (`cat MoreThenCms.Modules.Imgproxy.dll | tr -cd '[:print:]\n' | grep -oE ...`):
|
||||||
|
```
|
||||||
|
/imgproxy;https://imgproxy.kzntsv.site/-ImgproxyHandler_Invoke
|
||||||
|
```
|
||||||
|
|
||||||
|
`MoreThenCms.Modules.Imgproxy.dll` closed-source (исходника нет в `~/projects/MoreThenCms`; ни одного `*.cs` файла с `imgproxy` literal). Options для cutover:
|
||||||
|
- A) Hosts file + DNS-01 cert trick — средняя сложность
|
||||||
|
- B) Local nginx-relay на windows + self-signed cert + CallTrust поведение DLL unknown — средне-высокая
|
||||||
|
- C) Keep as-is — windows-host imgproxy/nginx/MinIO живут indefinitely, VDS stack = standby
|
||||||
|
- D) Decompile + recompile DLL — высокая, fragile (binding+strong-name)
|
||||||
|
|
||||||
|
**User decision 2026-05-22: Option C.** Image pipeline остаётся на windows-host; VDS stack — standby/future use. Decommission windows-host MinIO/imgproxy/imgproxy-nginx НЕ выполняется.
|
||||||
|
|
||||||
|
Если в будущем понадобится cutover — рассматривать Option A (DNS-01 challenge через REGRU API) как наиболее clean путь, при условии что `imgproxy.kzntsv.site` снова станет нашим (сейчас занят другим сервисом на другом сервере).
|
||||||
|
|
||||||
|
## Rollback
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On VDS
|
||||||
|
cd /opt/stacks/storage/minio-imgproxy && sudo docker compose down -v
|
||||||
|
# Source windows-host MinIO + imgproxy + imgproxy-nginx должны быть still running (48ч uptime acceptance).
|
||||||
|
# Если уже decommissioned — docker start minio imgproxy imgproxy-nginx.
|
||||||
|
# Snapshot insurance: tar archive bind-mount source data preserved отдельно (acceptance step 3).
|
||||||
|
```
|
||||||
99
.wiki/concepts/mssql-on-vds.md
Normal file
99
.wiki/concepts/mssql-on-vds.md
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
---
|
||||||
|
title: MSSQL on vds-kzntsv (Express 2022 Linux)
|
||||||
|
status: live
|
||||||
|
tags: [vds, mssql, migration, ops]
|
||||||
|
related: [[vds-kzntsv]], [[recovery-architecture-snapshot]], [[traefik-tcp-passthrough-vs-starttls]], [[db-tls-self-signed-via-traefik-raw-tcp]]
|
||||||
|
---
|
||||||
|
|
||||||
|
# MSSQL on vds-kzntsv
|
||||||
|
|
||||||
|
Запущен 2026-05-22 как часть `mssql-vds-migration`. SPOF с windows-recovery-host снят для CMS DB park.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
IIS snolla site (web.config)
|
||||||
|
→ mssql.kzntsv.site:1433 (LE/DNS A → 89.253.255.94)
|
||||||
|
→ VDS traefik :1433 (TCP entrypoint, HostSNI(*))
|
||||||
|
→ mssql container :1433 (self-signed TLS terminated по TDS)
|
||||||
|
→ /var/opt/mssql/data/{5 prod DBs}
|
||||||
|
```
|
||||||
|
|
||||||
|
Stack: `/opt/stacks/databases/mssql/{docker-compose.yml,.env,data,backups}`. Networks `proxy` only.
|
||||||
|
|
||||||
|
**Image:** `mcr.microsoft.com/mssql/server:2022-latest` (RTM-CU25, build 16.0.4255.1, on Ubuntu 22.04.5 LTS).
|
||||||
|
**Edition:** Express (`MSSQL_PID=Express`) — production licensing OK, 10 GB/DB cap (max .mdf сейчас `stostayer` 968 MB → 10× запас).
|
||||||
|
**Memory:** `MSSQL_MEMORY_LIMIT_MB=2048` env (Express auto-caps на 1410 в любом случае).
|
||||||
|
**TLS:** self-signed cert, mssql generates automatically. Client connects with `TrustServerCertificate=True`. Traefik forwards raw TCP — TLS terminates at mssql.
|
||||||
|
|
||||||
|
## Migration recipe (one-shot, executed 2026-05-22)
|
||||||
|
|
||||||
|
Источник: `mcr.microsoft.com/mssql/server:2019-latest` Developer на windows-recovery-host (volume `mssql_mssql_data` 26.6 GB; real data ~2.4 GB; .ldf logs 12 GB inflated).
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 1. Source: BACKUP DATABASE for each prod DB (5 total)
|
||||||
|
BACKUP DATABASE [<db>] TO DISK='/var/opt/mssql/backups/<db>.bak'
|
||||||
|
WITH COMPRESSION, COPY_ONLY, INIT, STATS=50;
|
||||||
|
-- Compressed total: 486 MB (10× от .mdf size — built-in compression на UTF-16/varchar pads)
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 2. Extract from container → scp → VDS bind
|
||||||
|
docker cp mssql:/var/opt/mssql/backups/. C:/tmp/mssql-backups/
|
||||||
|
scp C:/tmp/mssql-backups/*.bak vitya@vds.kzntsv.site:/tmp/mssql-bak-staging/
|
||||||
|
ssh vitya@vds.kzntsv.site 'sudo mv /tmp/mssql-bak-staging/*.bak /opt/stacks/databases/mssql/backups/
|
||||||
|
sudo chown 10001:0 /opt/stacks/databases/mssql/backups/*.bak'
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# 3. compose + .env (см. /opt/stacks/databases/mssql/)
|
||||||
|
# MSSQL_SA_PASSWORD из pass show mssql-vds/sa-password (32-char alnum, no special chars)
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# 4. Traefik: добавить TCP entrypoint в /opt/stacks/traefik/data/traefik.yml
|
||||||
|
entryPoints:
|
||||||
|
mssql:
|
||||||
|
address: ":1433"
|
||||||
|
# + port 1433 в /opt/stacks/traefik/docker-compose.yml ports list
|
||||||
|
# + ufw allow 1433/tcp
|
||||||
|
# + sudo docker compose up -d (RECREATE, не restart — port mapping)
|
||||||
|
```
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 5. RESTORE per DB
|
||||||
|
RESTORE DATABASE [<db>] FROM DISK='/var/opt/mssql/backups/<db>.bak' WITH REPLACE, STATS=50;
|
||||||
|
-- 2019 → 2022 schema upgrade автоматический (versions 953→957). DBCC CHECKDB PHYSICAL_ONLY clean.
|
||||||
|
```
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 6. CRITICAL: server-level logins НЕ переезжают в .bak (sysadmin/master DB only).
|
||||||
|
-- Создать manually + fix orphan users в каждой DB:
|
||||||
|
CREATE LOGIN snolla WITH PASSWORD = '<from-source-web.config>', CHECK_POLICY = OFF;
|
||||||
|
USE MoreThenCms;
|
||||||
|
ALTER USER snolla WITH LOGIN = snolla;
|
||||||
|
-- Repeat for каждой DB где web.config упоминает данного user'а.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gotchas
|
||||||
|
|
||||||
|
1. **Logins vs users**: .bak восстанавливает DB-level users (с их role memberships + permissions), но НЕ server logins. Sites с `User Id=X` в conn-string ловят `Login failed for user 'X'` после restore, пока не выполнить `CREATE LOGIN` + `ALTER USER ... WITH LOGIN`.
|
||||||
|
2. **Traefik recreate, не restart**: добавление port mapping в `docker-compose.yml` требует **recreate** контейнера (`docker compose up -d`), не `restart`. `restart` оставит старые published ports.
|
||||||
|
3. **PowerShell + `pass` (bash script)**: `pass show` в PowerShell возвращает NULL (PS не запускает bash-скрипты напрямую). Нужно `bash -c "pass show ..."` или literal. Симптом: `Login failed for user 'sa'` несмотря на правильный пароль на VDS.
|
||||||
|
4. **`MSSQL_SA_PASSWORD` спец-символы**: rotation password generator должен excludeавать `+/=` (Base64) и shell-meta (`$`, `` ` ``, `"`, `'`, `\`). Иначе env-var passing через ssh heredoc или sed конструкторы ломаются. Пример безопасного: `[Convert]::ToBase64String($bytes) -replace '[+/=]','x'`.
|
||||||
|
5. **MSSQL Linux user uid**: `mssql` user = uid 10001. Bind-mount должен быть `chown 10001:0` чтобы контейнер read/write. Parent dir owns `vitya:vitya` чтобы можно было редактировать compose без sudo.
|
||||||
|
|
||||||
|
## Backup integration (TODO)
|
||||||
|
|
||||||
|
Расширить `/opt/stacks/backup/scripts/run.sh` (см. [[vds-backup-rsync-kreknin]]):
|
||||||
|
- `mssql_dump_full` daily — `BACKUP DATABASE [<db>] TO DISK='...' WITH COMPRESSION, COPY_ONLY` через `docker exec mssql sqlcmd ...`
|
||||||
|
- `mssql_tx_log_backup` hourly — `BACKUP LOG [<db>] TO DISK='...'` для FULL-recovery DBs (только `MoreThenCms` — остальные SIMPLE).
|
||||||
|
- Достигает target RPO 1ч (vs current daily snapshot).
|
||||||
|
- ntfy push на `vds-backup` topic.
|
||||||
|
|
||||||
|
## Rollback recipe
|
||||||
|
|
||||||
|
1. Revert IIS web.config'ы (см. `.bak-pre-vds-cutover-20260522` файлы).
|
||||||
|
2. `iisreset /restart` (или ждать auto-recycle ~30 sec).
|
||||||
|
3. Убедиться windows-host MSSQL контейнер всё ещё running (acceptance 48ч uptime до decommission).
|
||||||
|
4. Если уже decommissioned: `docker start mssql` (volume сохранён ещё неделю по acceptance).
|
||||||
@@ -24,7 +24,9 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever
|
|||||||
- [future-resilient-architecture-goals](concepts/future-resilient-architecture-goals.md) — fault-tolerance roadmap placeholder (расширяется через `[resilience-roadmap-design]`)
|
- [future-resilient-architecture-goals](concepts/future-resilient-architecture-goals.md) — fault-tolerance roadmap placeholder (расширяется через `[resilience-roadmap-design]`)
|
||||||
- [hyper-backup-structure-and-recovery](concepts/hyper-backup-structure-and-recovery.md) — Hyper Backup — структура репо и стратегия восстановления
|
- [hyper-backup-structure-and-recovery](concepts/hyper-backup-structure-and-recovery.md) — Hyper Backup — структура репо и стратегия восстановления
|
||||||
- [iis-migration-2026-05-19-postmortem](concepts/iis-migration-2026-05-19-postmortem.md) — post-mortem миграции CMS на нативный IIS, 2026-05-19
|
- [iis-migration-2026-05-19-postmortem](concepts/iis-migration-2026-05-19-postmortem.md) — post-mortem миграции CMS на нативный IIS, 2026-05-19
|
||||||
|
- [minio-imgproxy-on-vds](concepts/minio-imgproxy-on-vds.md) — MinIO+imgproxy stack на VDS, миграция с upgrade 2020→2025 + DNS swap pending
|
||||||
- [mssql-container-data-restore](concepts/mssql-container-data-restore.md) — MSSQL контейнер с восстановленными production data — паттерн
|
- [mssql-container-data-restore](concepts/mssql-container-data-restore.md) — MSSQL контейнер с восстановленными production data — паттерн
|
||||||
|
- [mssql-on-vds](concepts/mssql-on-vds.md) — MSSQL Express 2022 Linux на VDS — миграция + login orphan fix + traefik TCP gotchas
|
||||||
- [ocis-on-vds-deploy-recipe](concepts/ocis-on-vds-deploy-recipe.md) — oCIS на VDS — deploy recipe + non-obvious gotchas (UID 1001 vs 1000, basic auth, LibreGraph user-create)
|
- [ocis-on-vds-deploy-recipe](concepts/ocis-on-vds-deploy-recipe.md) — oCIS на VDS — deploy recipe + non-obvious gotchas (UID 1001 vs 1000, basic auth, LibreGraph user-create)
|
||||||
- [portainer-2.21-admin-password-regression](concepts/portainer-2.21-admin-password-regression.md) — Portainer 2.21 `--admin-password` regression + min 12-char policy
|
- [portainer-2.21-admin-password-regression](concepts/portainer-2.21-admin-password-regression.md) — Portainer 2.21 `--admin-password` regression + min 12-char policy
|
||||||
- [recovery-architecture-snapshot](concepts/recovery-architecture-snapshot.md) — текущая recovery architecture (2026-05-19/21, attempt 2)
|
- [recovery-architecture-snapshot](concepts/recovery-architecture-snapshot.md) — текущая recovery architecture (2026-05-19/21, attempt 2)
|
||||||
|
|||||||
Reference in New Issue
Block a user