fix(caddy): разделение сайтов по хостам доходит до контейнера #3088

Merged
lekss361 merged 1 commit from fix/3059-caddy-sites-env into main 2026-08-24 21:44:14 +00:00
Owner

Summary

  • У сервиса caddy в docker-compose.prod.yml не пробрасывалась переменная CADDY_SITES, поэтому разделение доменов по хостам из #3059 не работало вообще.
  • Плейсхолдер import caddy/sites/{$CADDY_SITES:*}.caddy раскрывает сам Caddy из окружения своего контейнера — значение с хоста до него не доходило, всегда действовал дефолт *.
  • Последствие проявилось бы в день переезда и молча: Caddy на продовом хосте импортировал бы блок инфраструктурных доменов и пошёл выпускать сертификаты для obsidian / errors / git, чей DNS остаётся на другой машине. HTTP-01 падает, Let's Encrypt считает неудачи — 5 на домен в час.

Test plan

  • YAML валиден
  • caddy adapt на живом caddy:2 с реальным конфигом, проверка по host-матчерам в готовом JSON:
    • переменная не задана → 8 доменов (сегодняшнее поведение бит в бит)
    • CADDY_SITES=appsgendsgn.ru, www, merahome, meraocenka, meraotsenka
    • CADDY_SITES=infraerrors, git, obsidian
  • в окне переезда: задать переменную на обоих хостах и сделать caddy reload

Refs #3059, #3057

## Summary - У сервиса `caddy` в `docker-compose.prod.yml` не пробрасывалась переменная `CADDY_SITES`, поэтому разделение доменов по хостам из #3059 не работало вообще. - Плейсхолдер `import caddy/sites/{$CADDY_SITES:*}.caddy` раскрывает сам Caddy из окружения своего контейнера — значение с хоста до него не доходило, всегда действовал дефолт `*`. - Последствие проявилось бы в день переезда и молча: Caddy на продовом хосте импортировал бы блок инфраструктурных доменов и пошёл выпускать сертификаты для `obsidian` / `errors` / `git`, чей DNS остаётся на другой машине. HTTP-01 падает, Let's Encrypt считает неудачи — 5 на домен в час. ## Test plan - [x] YAML валиден - [x] `caddy adapt` на живом `caddy:2` с реальным конфигом, проверка по host-матчерам в готовом JSON: - переменная не задана → 8 доменов (сегодняшнее поведение бит в бит) - `CADDY_SITES=apps` → `gendsgn.ru`, `www`, `merahome`, `meraocenka`, `meraotsenka` - `CADDY_SITES=infra` → `errors`, `git`, `obsidian` - [ ] в окне переезда: задать переменную на обоих хостах и сделать `caddy reload` Refs #3059, #3057
lekss361 added 1 commit 2026-08-24 21:34:21 +00:00
fix(caddy): разделение сайтов по хостам доходит до контейнера
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 10s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
00df38bc2a
#3059 развёл восемь доменов по двум файлам и научил Caddyfile импортировать
подмножество через `import caddy/sites/{$CADDY_SITES:*}.caddy`. Но у сервиса
caddy в environment стоял только TRADEIN_INTERNAL_AUTH_SECRET, а env_file нет
вовсе — переменной в контейнере не было никогда.

Плейсхолдер такого вида раскрывает сам Caddy из окружения своего процесса, а не
compose при разборе файла. Значит значение с хоста до него не доходило, всегда
работал дефолт `*`, и всё разделение существовало только на бумаге. Обнаружилось
бы это в день переезда и молча: Caddy на продовом хосте импортировал бы и блок
инфраструктурных доменов, пошёл бы выпускать сертификаты для obsidian, errors и
git, чей DNS остаётся на другой машине, HTTP-01 падал бы, а Let's Encrypt при
этом считает неудачи — пять на домен в час.

Дефолт `*` сохранён, поэтому сегодня не меняется ничего: пока переменная не
задана ни на одном хосте, импортируются оба файла ровно как раньше. В окне
переезда достаточно задать её на каждой машине.

Проверено на живом caddy:2 через `caddy adapt` с реальным конфигом, по списку
host-матчеров в готовом JSON: переменная не задана — восемь доменов
(gendsgn.ru, www, три меры, obsidian, errors, git); CADDY_SITES=apps — пять
уезжающих; CADDY_SITES=infra — три остающихся.

Refs #3059, #3057
lekss361 merged commit bf297d196f into main 2026-08-24 21:44:14 +00:00
lekss361 deleted branch fix/3059-caddy-sites-env 2026-08-24 21:44:14 +00:00
Author
Owner

Смержил. Это дыра в моём #3062, и стоит зафиксировать, почему мои проверки её не поймали — ошибка методическая, а не случайная.

Что я проверял и что из этого следовало

В #3062 я гонял caddy adapt так:

docker run --rm -e CADDY_SITES=apps -v "$PWD:/etc/caddy:ro" caddy:2 caddy adapt ...

Три режима, честные цифры: без переменной 8 доменов, apps → 5, infra → 3. Всё это верно — и всё это про Caddyfile, а не про то, как переменная попадает в контейнер на проде.

Я передавал -e CADDY_SITES прямо в docker run, то есть сам подставлял то звено, которого в compose не существовало. Проверка подтверждала логику конфига и обходила единственное место, где была ошибка.

Классический случай: тест доказывал, что механизм работает, если ему дать вход, — но не то, что вход дойдёт.

Почему это не поймалось и дальше

Я проверял #3062 на проде после мержа: caddy пересоздан, caddy/sites/ смонтирован, все 8 доменов отвечают. Всё сходилось — потому что 8 доменов и есть поведение по умолчанию. Отсутствие переменной выглядит ровно как корректная работа без переменной. Отличить одно от другого можно было только задав CADDY_SITES=apps на проде и увидев, что ничего не изменилось, а этого я не делал.

То есть моя пост-деплойная проверка была не бесполезной, но слепой ровно к этому классу отказа.

Что теперь верно

CADDY_SITES: ${CADDY_SITES:-*} в environment: сервиса — дефолт * сохраняет сегодняшнее поведение бит в бит, а в окне значение задаётся на каждом хосте.

Правильная проверка на будущее: не «отвечают ли домены», а docker exec gendesign-caddy-1 env | grep CADDY_SITES плюс список доменов из лога Caddy после reload. Первое доказывает, что вход дошёл; второе — что он подействовал.

Допишу это в раннбук как шаг проверки после установки переменной, чтобы в окне никто не повторил мою ошибку — не увидел восемь доменов там, где ожидал пять, и не счёл это успехом.

Refs #3059, #3062, #3057

Смержил. Это дыра в моём #3062, и стоит зафиксировать, **почему мои проверки её не поймали** — ошибка методическая, а не случайная. ## Что я проверял и что из этого следовало В #3062 я гонял `caddy adapt` так: ```bash docker run --rm -e CADDY_SITES=apps -v "$PWD:/etc/caddy:ro" caddy:2 caddy adapt ... ``` Три режима, честные цифры: без переменной 8 доменов, `apps` → 5, `infra` → 3. Всё это верно — и всё это про **Caddyfile**, а не про то, как переменная попадает в контейнер на проде. Я передавал `-e CADDY_SITES` прямо в `docker run`, то есть **сам подставлял то звено, которого в compose не существовало**. Проверка подтверждала логику конфига и обходила единственное место, где была ошибка. Классический случай: тест доказывал, что механизм работает, если ему дать вход, — но не то, что вход дойдёт. ## Почему это не поймалось и дальше Я проверял #3062 на проде после мержа: caddy пересоздан, `caddy/sites/` смонтирован, все 8 доменов отвечают. Всё сходилось — **потому что 8 доменов и есть поведение по умолчанию**. Отсутствие переменной выглядит ровно как корректная работа без переменной. Отличить одно от другого можно было только задав `CADDY_SITES=apps` на проде и увидев, что ничего не изменилось, а этого я не делал. То есть моя пост-деплойная проверка была не бесполезной, но слепой ровно к этому классу отказа. ## Что теперь верно `CADDY_SITES: ${CADDY_SITES:-*}` в `environment:` сервиса — дефолт `*` сохраняет сегодняшнее поведение бит в бит, а в окне значение задаётся на каждом хосте. Правильная проверка на будущее: не «отвечают ли домены», а **`docker exec gendesign-caddy-1 env | grep CADDY_SITES`** плюс список доменов из лога Caddy после reload. Первое доказывает, что вход дошёл; второе — что он подействовал. Допишу это в раннбук как шаг проверки после установки переменной, чтобы в окне никто не повторил мою ошибку — не увидел восемь доменов там, где ожидал пять, и не счёл это успехом. Refs #3059, #3062, #3057
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#3088
No description provided.