feat(galleries): migrate pilorama98 gallery originals Local-disk → S3
snolla galleries 404 (imgproxy "Source unreachable"): legacy storageClient "galleries" = MoreThenCms Local storage class (App_Data\galleries\<siteId>), never in S3 — products were migrated, galleries weren't. Path A (user pick): new bucket `galleries`, 301 pilorama98 originals (77 MiB) rclone'd from RUVDS IIS → s3://galleries/37e6…/<guid>.jpg verbatim. snolla code unchanged (storageClient=bucket is the working convention). imgproxy smoke from books-vds: real obj 200 image/webp, fake guid 404. Other sites unmigrated (scope). Inbox sent to victor/snolla. - close [migrate-gallery-originals-to-s3] (scope pilorama98) - NEW .wiki concept galleries-storage-class-local-not-s3 - fix stale minio-imgproxy-on-vds (pipeline on books-vds since 2026-06-08) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
# Admin Task Board
|
# Admin Task Board
|
||||||
|
_Updated: 2026-06-12 (4) — 🟢 **[migrate-gallery-originals-to-s3] closed (scope pilorama98).** Галереи snolla не отдавались (imgproxy 404) т.к. в legacy `storageClient="galleries"` = тип **Local** (диск `App_Data\galleries\<siteId>`), НЕ S3 — оригиналы никогда туда не заливались (продукты — заливались, bucket `pilorama98`). Развилка A/B закрыта фактами MinIO → **A**: создан bucket `galleries`, залиты 301 файл (77 MiB) pilorama98 (siteId `37e67fc4…`) с RUVDS IIS через rclone → `s3://galleries/<siteId>/<guid>.jpg` verbatim (== ровно то, что строит `middleware/galleries.js:47`). Код snolla НЕ менялся. Verify: count+size == source. Smoke с books-vds: реальный объект imgproxy → 200 webp, fake → 404. Уточнение инфра: `imgproxy.kzntsv.site` с 08.06 на **books-vds** (стек 29/30), не на windows-host — `minio-imgproxy-on-vds.md` был stale. Inbox victor/snolla отправлен._
|
||||||
_Updated: 2026-06-12 (3) — 🟢 **bookva-es snapshot done** (не отложен). Portainer stack 37 пересоздан с `path.repo=/snapshots`+bind (PUT API, том цел, epz/products уцелели), repo `kreknin` зарегистрирован, snapshot-блок в `run.sh`. Поймана коллизия basename `snapshots` (оба ES-каталога одноимённы → сливались в один dest-репо, порча обоих) → источник bookva-es = родительский `/usr/docker/bookva-es`. Verified: `BOOKS-VDS backup OK 10m28s`, на kreknin раздельно `snapshots/`(slovo index-41) + `bookva-es/snapshots/`(index-4). Таска `bookva-es-snapshot-repo` 🟢 closed._
|
_Updated: 2026-06-12 (3) — 🟢 **bookva-es snapshot done** (не отложен). Portainer stack 37 пересоздан с `path.repo=/snapshots`+bind (PUT API, том цел, epz/products уцелели), repo `kreknin` зарегистрирован, snapshot-блок в `run.sh`. Поймана коллизия basename `snapshots` (оба ES-каталога одноимённы → сливались в один dest-репо, порча обоих) → источник bookva-es = родительский `/usr/docker/bookva-es`. Verified: `BOOKS-VDS backup OK 10m28s`, на kreknin раздельно `snapshots/`(slovo index-41) + `bookva-es/snapshots/`(index-4). Таска `bookva-es-snapshot-repo` 🟢 closed._
|
||||||
_Updated: 2026-06-12 (2) — 🟢 **bookva-* backup gap закрыт.** bookva tenant (db/mongo/es/minio, поднят 26.05) не бэкапился — books-скрипт написан 25.05 до bookva, покрытие не расширили (висело wiki-follow-up #2). Добавлены bookva-db (тот же root pw), bookva-mongo (no-auth), bookva-minio (raw volume) в `books-vds-backup-daily-kreknin/run.sh`; деплой == репо (`.bak-pre-bookva`). Verified green: `BOOKS-VDS backup OK 10m42s`, артефакты на kreknin (bookva-mariadb 257M, bookva-mongo 3.2M, bookva-minio 1.4G). bookva-es отложен → `bookva-es-snapshot-repo` (покрыт slovo-снапшотом, индексы идентичны). Правило в память: новый stateful → бэкап в том же коммите._
|
_Updated: 2026-06-12 (2) — 🟢 **bookva-* backup gap закрыт.** bookva tenant (db/mongo/es/minio, поднят 26.05) не бэкапился — books-скрипт написан 25.05 до bookva, покрытие не расширили (висело wiki-follow-up #2). Добавлены bookva-db (тот же root pw), bookva-mongo (no-auth), bookva-minio (raw volume) в `books-vds-backup-daily-kreknin/run.sh`; деплой == репо (`.bak-pre-bookva`). Verified green: `BOOKS-VDS backup OK 10m42s`, артефакты на kreknin (bookva-mariadb 257M, bookva-mongo 3.2M, bookva-minio 1.4G). bookva-es отложен → `bookva-es-snapshot-repo` (покрыт slovo-снапшотом, индексы идентичны). Правило в память: новый stateful → бэкап в том же коммите._
|
||||||
_Updated: 2026-06-12 — 🔴→🟢 **MSSQL backup incident + estate backup audit.** VDS daily backup падал с 12.06 (line 108, exit 1): mssql-блок (added 11.06) использовал `WITH ... INIT` → упирался в компрессованный media-header майских `.bak` (Express не пишет COMPRESSION) → молча падал первым cron-запуском. **5 боевых CMS-баз 3 недели без offsite-копии.** Fix: `INIT`→`FORMAT`, прогон verified (MoreThenCms 910M/StayerCalculator 528M/StayerPrice 39M/TireService 4.5M/stostayer 990M на kreknin). Репо-копия `run.sh` синхронизирована (mssql-блока не было). Concept: `.wiki/concepts/mssql-on-vds.md` gotcha#2. **Estate backup-аудит** → `.wiki/concepts/backup-inventory-2026-06.md`: ✅ openwrt UCI backup настроен (cron 03:30 → kreknin, restricted forced-command key); ⚪ заведена `kreknin-self-backup` (#1 SPOF, на потом); nl-vds x-ui.db — user: не нужен; windows-host stale script — user: забыть._
|
_Updated: 2026-06-12 — 🔴→🟢 **MSSQL backup incident + estate backup audit.** VDS daily backup падал с 12.06 (line 108, exit 1): mssql-блок (added 11.06) использовал `WITH ... INIT` → упирался в компрессованный media-header майских `.bak` (Express не пишет COMPRESSION) → молча падал первым cron-запуском. **5 боевых CMS-баз 3 недели без offsite-копии.** Fix: `INIT`→`FORMAT`, прогон verified (MoreThenCms 910M/StayerCalculator 528M/StayerPrice 39M/TireService 4.5M/stostayer 990M на kreknin). Репо-копия `run.sh` синхронизирована (mssql-блока не было). Concept: `.wiki/concepts/mssql-on-vds.md` gotcha#2. **Estate backup-аудит** → `.wiki/concepts/backup-inventory-2026-06.md`: ✅ openwrt UCI backup настроен (cron 03:30 → kreknin, restricted forced-command key); ⚪ заведена `kreknin-self-backup` (#1 SPOF, на потом); nl-vds x-ui.db — user: не нужен; windows-host stale script — user: забыть._
|
||||||
@@ -362,7 +363,9 @@ vehicles-loader (stostayer) деплоится в Docker у клиента (lite
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ⚪ [migrate-gallery-originals-to-s3] — Галерейные (blog/gallery) картинки не отдаются ни на dev (imgproxy 404 "Source image is unreachable"), ни на prod (legacy-ресайз 404). Диагностика проведена в victor/snolla против живого pilorama98 + кода MoreThenCms. Нужен доступ к БОЕВОМУ серверу (локальный диск IIS + MinIO/S3), которого нет у snolla-агента — поэтому задача на admin.
|
## 🟢 [migrate-gallery-originals-to-s3] — closed 2026-06-12 (scope: pilorama98) — путь A: создан bucket `galleries`, залиты 301 файл (77 MiB) legacy-оригиналов pilorama98 с RUVDS IIS `App_Data\galleries\37e6…` → `s3://galleries/37e67fc44b9e4c06a522a26a73bac9b0/<guid>.jpg`. Smoke с books-vds: реальный объект через imgproxy → 200 image/webp 32102 B, fake guid → 404. Код snolla НЕ менялся (storageClient=имя бакета — рабочая конвенция). Inbox victor/snolla отправлен. Развилка A/B закрыта фактами MinIO: galleries в legacy = Local storage class (диск), никогда не в S3; A выбран user'ом.
|
||||||
|
|
||||||
|
Галерейные (blog/gallery) картинки не отдаются ни на dev (imgproxy 404 "Source image is unreachable"), ни на prod (legacy-ресайз 404). Диагностика проведена в victor/snolla против живого pilorama98 + кода MoreThenCms. Нужен доступ к БОЕВОМУ серверу (локальный диск IIS + MinIO/S3), которого нет у snolla-агента — поэтому задача на admin.
|
||||||
|
|
||||||
## Диагноз (доказан, не гипотеза)
|
## Диагноз (доказан, не гипотеза)
|
||||||
|
|
||||||
@@ -412,11 +415,19 @@ vehicles-loader (stostayer) деплоится в Docker у клиента (lite
|
|||||||
**weight:** needs-human
|
**weight:** needs-human
|
||||||
**notify:** victor/snolla
|
**notify:** victor/snolla
|
||||||
|
|
||||||
**Status:** ready
|
**Status:** done (closed 2026-06-12, scope pilorama98)
|
||||||
**Where I stopped:** (not started) — диагностика выполнена в victor/snolla, см. тело
|
**Where I stopped:** мигрировано. MinIO (books-vds стек 30, за `imgproxy.kzntsv.site` с 08.06): bucket `galleries` создан, prefix `37e67fc44b9e4c06a522a26a73bac9b0/` залит (301×.jpg, 77.0 MiB, rclone RUVDS→minio.kzntsv.site, count+size == source). Smoke OK с books-vds (200/404).
|
||||||
**Next action:** 1) В MinIO/S3 проверить: существует ли бакет `galleries` и есть ли в нём объекты `<siteId>/<storageFilename>`; сверить с тем, как лежат рабочие продукты (`s3://pilorama98/products/...`). 2) Залить legacy-оригиналы `App_Data\galleries\<siteId>\*` в целевой бакет под ключи `<siteId>/<storageFilename>`. 3) Re-smoke imgproxy на одной картинке.
|
**Next action:** — (хвосты в inbox victor/snolla: остальные siteId-папки галерей не мигрированы по скоупу; legacy prod-ресайз остаётся 404 by design).
|
||||||
**Branch:** master
|
**Branch:** master
|
||||||
**Notify:** victor/snolla
|
**Notify:** victor/snolla — ✅ inbox `.claude-inbox/2026-06-12T11-47-33Z-admin.md`
|
||||||
|
|
||||||
|
**Closure note (2026-06-12):**
|
||||||
|
- **Развилка A/B закрыта фактами:** в Web.config legacy `<fileStorageClients>` storageClient `galleries` = тип **Local** (`GalleriesStorage`, диск `App_Data\galleries\<siteId>`), НЕ S3 → галереи никогда не были в S3 (продукты — да, bucket `pilorama98/products`). Корень доказан. **A** (отдельный bucket `galleries`, key `<siteId>/<storageFilename>`) выбран user'ом → нулевой код-фикс snolla.
|
||||||
|
- **MinIO state:** bucket'ы до миграции — artmone/books/imgproxytest/manuals/modulair/modules/obsidian/ozon/pilorama98/strapi/test/upload; `galleries` отсутствовал; `pilorama98` = только `products/` (шард по hex, без siteId). Зафиксировано.
|
||||||
|
- **Залив:** RUVDS IIS `C:\sites\snolla\App_Data\galleries\37e67fc44b9e4c06a522a26a73bac9b0\` (301 файл, dir-name уже lowercase 32-hex == ownerId snolla) → `s3://galleries/37e6…/<guid>.jpg` verbatim. rclone v1.74.2 inline s3-remote (env-var config, без записи cred). Verify: 301 объект, 77.012 MiB == source.
|
||||||
|
- **Smoke (с books-vds, мимо LAN-DNS-перехвата воркстейшна):** подписанный imgproxy-URL реального объекта → 200 image/webp 32102 B; несуществующий guid → 404 (негативный контроль).
|
||||||
|
- **Wiki-drift зафиксирован:** `minio-imgproxy-on-vds.md` устарел (говорит pipeline на windows-host; фактически imgproxy на books-vds с 08.06). Добавлен concept `galleries-storage-class-local-not-s3`.
|
||||||
<!-- created-by: OpeItcLoc03@DESKTOP-NSEF0UK / from: victor/snolla / 2026-06-12T11:09:50.425Z -->
|
<!-- created-by: OpeItcLoc03@DESKTOP-NSEF0UK / from: victor/snolla / 2026-06-12T11:09:50.425Z -->
|
||||||
|
<!-- closed-by: vitya@.admin-exec / 2026-06-12 / path A: bucket galleries + 301 pilorama98 originals, imgproxy 200 verified, snolla code unchanged -->
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
58
.wiki/concepts/galleries-storage-class-local-not-s3.md
Normal file
58
.wiki/concepts/galleries-storage-class-local-not-s3.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
title: MoreThenCms galleries — Local storage class, never in S3 (snolla imgproxy 404 root cause)
|
||||||
|
status: resolved for pilorama98 (2026-06-12); other sites unmigrated
|
||||||
|
tags: [cms, snolla, morethencms, minio, imgproxy, s3, galleries, migration]
|
||||||
|
related: [[minio-imgproxy-on-vds]], [[../entities/books-vds]], [[../entities/ruvds-iis-host]]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Galleries storage class = Local (disk), not S3
|
||||||
|
|
||||||
|
## Root cause
|
||||||
|
|
||||||
|
В MoreThenCms `<fileStorageClients>` (Web.config) каждый `storageClient` — это **алиас конфига**, не имя бакета. Алиас `galleries` маппится на тип **`MoreThenCms.FileStorage.Local.GalleriesStorage`** → файлы на локальном диске IIS:
|
||||||
|
|
||||||
|
```
|
||||||
|
C:\sites\snolla\App_Data\galleries\<siteId:N>\<storageFilename-guid>.<ext>
|
||||||
|
```
|
||||||
|
|
||||||
|
То же у `assets`, `images`, `scripts`, `stylesheets`, `watermarks` — все **Local**. Продукты (e-commerce) — другой механизм, **реально в S3** (bucket `pilorama98`, prefix `products/`, шард по hex, без siteId).
|
||||||
|
|
||||||
|
Переписка **snolla** (Node) наивно строит источник как `s3://${image.storageClient}/${siteId}/${storageFilename}` (`packages/snolla/middleware/galleries.js:47`, `lib/viewModels/index.js:289`) — т.е. ждёт галереи в S3 в бакете с именем `galleries`. Но их там никогда не было → imgproxy «Source image is unreachable» (404). Это НЕ баг билдера URL и НЕ поломка ресайза — просто **данные не мигрированы** из Local-диска в S3.
|
||||||
|
|
||||||
|
Симптом-близнец на legacy-prod (`pilorama98.ru/galleries/<id>/images/<size>/<seq>.jpg`): `original/*` = 200 (читает диск), любой ресайз = 404 — отдельная мёртвая ветка legacy-ресайзера (System.Drawing/image-cache). Целевая архитектура = imgproxy, legacy-ресайз не чинится.
|
||||||
|
|
||||||
|
## Fix recipe (путь A — выбран)
|
||||||
|
|
||||||
|
storageClient как **имя бакета** = рабочая конвенция snolla. Заливаем Local-диск в одноимённый bucket, ключи verbatim — код snolla не меняется:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# на RUVDS IIS (rclone v1.74.2 уже стоит). env-var remote, без записи cred в rclone.conf
|
||||||
|
$env:RCLONE_CONFIG_MIN_TYPE='s3'; $env:RCLONE_CONFIG_MIN_PROVIDER='Minio'
|
||||||
|
$env:RCLONE_CONFIG_MIN_ACCESS_KEY_ID='<minio-access>'; $env:RCLONE_CONFIG_MIN_SECRET_ACCESS_KEY='<minio-secret>'
|
||||||
|
$env:RCLONE_CONFIG_MIN_ENDPOINT='https://minio.kzntsv.site' # books-vds S3 API за traefik
|
||||||
|
& rclone mkdir min:galleries
|
||||||
|
& rclone copy "C:\sites\snolla\App_Data\galleries\<siteId>" min:galleries/<siteId> --transfers 8
|
||||||
|
& rclone size min:galleries/<siteId> # сверить count+size с источником
|
||||||
|
```
|
||||||
|
|
||||||
|
- `<siteId>` папки на диске уже lowercase 32-hex == `ownerId` snolla (`String(site.id).replace(-).toLowerCase()`) → ключи совпадают 1:1, трансформаций не надо.
|
||||||
|
- Креды MinIO: `pass books-vds/full-env` (контейнер `minio`, env `MINIO_ACCESS_KEY`/`MINIO_SECRET_KEY`). imgproxy key/salt — env контейнера `imgproxy`.
|
||||||
|
|
||||||
|
## Smoke (важно: мимо LAN-DNS воркстейшна)
|
||||||
|
|
||||||
|
`imgproxy.kzntsv.site` с воркстейшна резолвится в `127.0.0.1` (LAN-перехват CMS-доменов) — смоук гнать **с самого books-vds** или `--resolve …:89.253.255.133`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -sk --resolve imgproxy.kzntsv.site:443:127.0.0.1 'https://imgproxy.kzntsv.site/<sig>/fill/W/H/ce/0/<b64url(s3://galleries/<siteId>/<guid>.jpg)>.webp'
|
||||||
|
# подпись: base64url( HMAC_SHA256(KEY_bin, SALT_bin + path) ), KEY/SALT = hex из env imgproxy
|
||||||
|
```
|
||||||
|
|
||||||
|
Реальный объект → 200 image/webp; несуществующий guid → 404 (негативный контроль).
|
||||||
|
|
||||||
|
## Status / scope
|
||||||
|
|
||||||
|
- **pilorama98** (siteId `37e67fc44b9e4c06a522a26a73bac9b0`): мигрирован 2026-06-12 — 301 файл / 77 MiB, imgproxy 200 verified.
|
||||||
|
- **Остальные ~40 siteId-папок** в `App_Data\galleries` — НЕ мигрированы (часть пустые). Bucket `galleries` shared; заполнен только префикс pilorama98. Другие сайты в snolla → 404 пока не зальёшь (регрессии нет).
|
||||||
|
- Если поднимаются другие Local-классы (`assets`/`images`/…) в snolla через imgproxy — их ждёт та же дыра, тот же рецепт.
|
||||||
|
|
||||||
|
См. задачу `.tasks/STATUS.md` → `[migrate-gallery-originals-to-s3]`.
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
---
|
---
|
||||||
title: MinIO + imgproxy stack on vds-kzntsv
|
title: MinIO + imgproxy stack on vds-kzntsv
|
||||||
status: live as standby — CMS image pipeline остаётся на windows-host (closed-source DLL hardcoded URL)
|
status: STANDBY/unused for CMS — живой CMS image pipeline переехал на books-vds 2026-06-08 (см. ниже)
|
||||||
tags: [vds, minio, imgproxy, migration, ops]
|
tags: [vds, minio, imgproxy, migration, ops]
|
||||||
related: [[vds-kzntsv]], [[recovery-architecture-snapshot]], [[mssql-on-vds]]
|
related: [[vds-kzntsv]], [[recovery-architecture-snapshot]], [[mssql-on-vds]], [[../entities/books-vds]], [[galleries-storage-class-local-not-s3]]
|
||||||
---
|
---
|
||||||
|
|
||||||
# MinIO + imgproxy on vds-kzntsv
|
# MinIO + imgproxy on vds-kzntsv
|
||||||
|
|
||||||
|
> ⚠ **Stale для живого pipeline (2026-06-08).** `imgproxy.kzntsv.site` (hardcoded в `MoreThenCms.Modules.Imgproxy.dll`) теперь смотрит на **[[../entities/books-vds]]** (стек 29 imgproxy + стек 30 minio, bucket'ы `pilorama98`, `galleries`, …), а windows-recovery-host декоммишнен. Этот VDS-kzntsv стек — standby/неиспользуемый для CMS. Option C ниже («остаётся на windows-host») историчен. Миграция галерей и рецепт smoke — [[galleries-storage-class-local-not-s3]].
|
||||||
|
|
||||||
Запущен 2026-05-22 как часть `minio-imgproxy-vds-migration`. Заодно **upgrade MinIO** `RELEASE.2020-07-13` (5 лет, CVE-куча) → `RELEASE.2025-09-07`.
|
Запущен 2026-05-22 как часть `minio-imgproxy-vds-migration`. Заодно **upgrade MinIO** `RELEASE.2020-07-13` (5 лет, CVE-куча) → `RELEASE.2025-09-07`.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|||||||
@@ -69,3 +69,5 @@ Append-only log of wiki operations (ingests, promotions, lints, migrations).
|
|||||||
## [2026-06-06] decision | nl-vds-3xui: +3 classic Shadowsocks inbounds (ports 32031/32/33) for Outline-app, per-key revocable; protocol e2e-tested OK, RF reachability unverified (SS DPI-blocked in RF); creds in pass; discovered undocumented VLESS:13027.
|
## [2026-06-06] decision | nl-vds-3xui: +3 classic Shadowsocks inbounds (ports 32031/32/33) for Outline-app, per-key revocable; protocol e2e-tested OK, RF reachability unverified (SS DPI-blocked in RF); creds in pass; discovered undocumented VLESS:13027.
|
||||||
|
|
||||||
## [2026-06-10] ingest | concepts/mcp-init-resilience
|
## [2026-06-10] ingest | concepts/mcp-init-resilience
|
||||||
|
|
||||||
|
## [2026-06-12] migrate | galleries pilorama98 → S3. NEW concepts/galleries-storage-class-local-not-s3.md (root: storageClient `galleries` = Local disk class, never in S3; snolla ждёт s3://galleries/<siteId>/<file> → 404). Путь A: bucket `galleries` создан, 301 файл (77 MiB) с RUVDS IIS залиты verbatim, imgproxy 200 verified с books-vds. UPDATE concepts/minio-imgproxy-on-vds.md (stale-баннер: pipeline на books-vds с 08.06, не windows-host). Task migrate-gallery-originals-to-s3 🟢.
|
||||||
|
|||||||
Reference in New Issue
Block a user