Files
admin/.wiki/concepts/minio-imgproxy-on-vds.md
vitya 7ebab0a79d docs(wiki): add S3-access lookup block for client apps (books-vds MinIO)
Запрос snolla (raw-stream content-api) потребовал MinIO endpoint+креды;
ответ был выводим из вики, но не собран одним куском. Добавлен раздел
«S3 access для клиентских приложений» в minio-imgproxy-on-vds.md:
endpoint (https://minio.kzntsv.site / сырой :9000 / inter minio:9000),
root accessKey + pass-ссылка на secret, форма ключа, ssl/region/pathStyle.
Следующий такой вопрос — grep по вики, без SSH на сервер.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 10:49:13 +03:00

146 lines
9.9 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: MinIO + imgproxy stack on vds-kzntsv
status: STANDBY/unused for CMS — живой CMS image pipeline переехал на books-vds 2026-06-08 (см. ниже)
tags: [vds, minio, imgproxy, migration, ops]
related: [[vds-kzntsv]], [[recovery-architecture-snapshot]], [[mssql-on-vds]], [[../entities/books-vds]], [[galleries-storage-class-local-not-s3]]
---
# 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]].
## S3 access для клиентских приложений (content-api, raw-stream, прямой getObject)
**Это раздел-lookup — отвечать на «дай MinIO endpoint/креды» отсюда, без SSH на сервер.**
Живой MinIO с бакетами CMS — на **[[../entities/books-vds]]** (`89.253.255.133`), legacy-инстанс `minio/minio:RELEASE.2020-07-13` (миграция as-is, без ротации — поэтому ключ совпадает с историческим windows-host).
| Параметр | Значение |
|---|---|
| Endpoint (внешний, TLS) | `https://minio.kzntsv.site` (traefik → `minio:9000`, LE cert, port 443) |
| Endpoint (сырой host-порт) | `http://89.253.255.133:9000` (тот же бэкенд, ssl:false) |
| Endpoint (inter-container на books-vds) | `http://minio:9000` (сеть `proxy`) — так ходит imgproxy |
| accessKeyId | `AKIAJ2YJP72W6ZHCRE6Q` (= `MINIO_ACCESS_KEY`, root, read+write all) |
| secretAccessKey | в `pass minio-vds/full-env` (`MINIO_ROOT_PASSWORD`) |
| region / pathStyle / ssl | `local` / `true` / **`true` для https-хостнейма** (false для сырого `:9000`) |
**Форма ключа (подтверждена тем, что imgproxy отдаёт 200):** `bucket=<storageClient>`, `key=<ownerId-lowercase>/<storageFilename>`, backslash→slash. owner из MSSQL приходит UPPERCASE → лоуэркейсить. Бакеты: `assets` (`<ownerId>/<file>`), `galleries` (`<siteId-hex-no-dashes>/<guid>.<ext>`), `pilorama98` (`products/<hex-shard>/...`).
⚠️ В snolla dev `default.json` endpoint `212.24.37.82:9000` + ключ `AV1QWDHDUQIPO6ABJOM0`**устарели** (windows-host, декоммишен). Менять и endpoint, и креды на books-vds-значения выше.
> Прецедент: inbox-запрос snolla 2026-06-14 (raw-stream content-api) закрыт этим блоком.
Запущен 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).
```