Files
admin/.wiki/concepts/minio-imgproxy-on-vds.md
vitya adcd8bda1f tasks(minio+iis): close 🟢 — CMS image pipeline стоп-на-windows-host
Finding: MoreThenCms.Modules.Imgproxy.dll (closed-source) содержит
hardcoded https://imgproxy.kzntsv.site URL (strings analysis из binary).
Архитектура: browser → traefik → IIS snolla → ImgproxyHandler →
server-side GET imgproxy.kzntsv.site → windows-host traefik → imgproxy-nginx
→ imgproxy → MinIO localhost:9000.

Sample URL decode: https://www.pilorama98.ru/imgproxy/<sig>/.../
czM6Ly9waWxvcmFtYTk4L3Byb2R1Y3RzL2wv... → base64 =
s3://pilorama98/products/l/<uuid>.jpg

DLL closed-source, исходника в репо нет. 4 options рассмотрены
(hosts+cert trick / nginx-relay / keep-as-is / decompile+recompile).
User decision: Option C — оставить как есть. Windows-host imgproxy/nginx
/MinIO живут indefinitely, VDS stack = standby.

minio-imgproxy-vds-migration 🟢 — VDS stack ready as standby
iis-cutover-to-vds-services 🟢 — MSSQL leg done, image pipeline stays
Decommission window-host MSSQL осtaется (48ч soak до 2026-05-24);
MinIO/imgproxy/nginx на windows — НЕ decommission.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 10:47:29 +03:00

7.3 KiB
Raw Blame History

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

# 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

# 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).