refactor(caddy): разделить site-блоки по хостам под переезд #3062
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#3062
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "refactor/caddyfile-split-by-host"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Зачем
Пункт 4 из чеклиста переезда. Корневой
Caddyfileсодержал все восемь доменов в одном файле, а деплой синхронизирует рабочее дерево сorigin/mainи перечитывает конфиг целиком. Значит на Selectel приехал бы файл со всеми восемью — и Caddy начал бы выпускать сертификаты дляobsidian/errors/git, чей DNS указывает на Beget. ACME падал бы на HTTP-01, с риском упереться в rate limit Let's Encrypt.Вторая, более тяжёлая сторона той же проблемы (найдена при разведке порядка остановки/запуска, см. #3061): сейчас этот Caddy — единственный публичный вход и для тех трёх доменов тоже. Он уезжает, а Forgejo, GlitchTip и CouchDB остаются на Beget. Без разделения они отдавали бы 502, оставаясь при этом живыми — то есть отвалился бы и git, и приём ошибок, и синк волта, причём в момент переезда, когда они нужнее всего. Теперь на Beget остаётся Caddy с
CADDY_SITES=infra.Что сделано
caddy/sites/apps.caddycaddy/sites/infra.caddyКорневой
Caddyfileужался с 522 строк до 96: глобальные опции, snippet'ы, блок:80и два import. Site-блоки перенесены дословно, вместе с комментариями — поведенческих правок нет, только перемещение.Выбор режима — через
import caddy/sites/{$CADDY_SITES:*}.caddy.Test plan
caddy adaptв трёх режимах, домены посчитаны из полученного JSON:CADDY_SITES=apps→ 5: gendsgn.ru merahome.ru meraocenka.ru meraotsenka.ru www.gendsgn.ruCADDY_SITES=infra→ 3: errors.gendsgn.ru git.gendsgn.ru obsidian.gendsgn.ruДве правки, найденные этой же валидацией (обе были бы тихими поломками на проде):
{$VAR:default}, а не{$VAR:-default}как в shell/compose. С шелловской формой Caddy искал файл с литеральным именемcaddy/sites/{$CADDY_SITES:-*}.caddy.importрезолвится относительно импортирующего файла, поэтомуimport caddy/users.caddy.snippetпри переносе внутрьcaddy/sites/перестал находиться →import ../users.caddy.snippet.Известное ограничение
Пустое значение переменной — не то же самое, что незаданная: Caddy подставит пустую строку, получится путь
caddy/sites/.caddy, конфиг не соберётся. Оставлено как есть осознанно — это ошибка оператора, которая падает громко (reload отказывает, старый конфиг продолжает работать), а не тихо отдаёт не тот набор доменов. Предупреждение стоит комментарием над монтированием вdocker-compose.prod.yml.Refs #3059, #3057, #2989
Корневой Caddyfile содержал все восемь доменов. Деплой синхронизирует рабочее дерево с origin/main и перечитывает конфиг, поэтому на Selectel приехал бы файл целиком — и Caddy начал бы выпускать сертификаты для obsidian/errors/git, чей DNS указывает на Beget. ACME падал бы на HTTP-01, с риском упереться в rate limit Let's Encrypt. Вторая, более тяжёлая сторона той же проблемы: сейчас ЭТОТ Caddy — единственный публичный вход и для тех трёх доменов тоже. Он уезжает, а Forgejo, GlitchTip и CouchDB остаются. Без разделения они отдавали бы 502, оставаясь живыми. Теперь на Beget остаётся Caddy с CADDY_SITES=infra. caddy/sites/apps.caddy gendsgn.ru, www, meraocenka, merahome, meraotsenka caddy/sites/infra.caddy obsidian, errors, git Корневой файл ужался с 522 строк до 96: глобальные опции, snippet'ы, блок :80 и два import. Site-блоки перенесены дословно, вместе с комментариями. Проверено caddy adapt в трёх режимах: без переменной -> 8 доменов (текущее поведение Beget, не меняется) CADDY_SITES=apps -> 5 CADDY_SITES=infra -> 3 Две правки, найденные валидацией: синтаксис дефолта у Caddy {$VAR:default}, а не {$VAR:-default}; путь к users.caddy.snippet из подкаталога стал ../users.caddy.snippet — import резолвится относительно импортирующего файла. Refs #3059, #3057, #2989CI поймал настоящую связь, которую разделение site-блоков порвало: два фронтовых теста читают Caddyfile как ИСТОЧНИК ПРАВДЫ о публичном периметре, а не дублируют список путей. public-perimeter.test.ts — ищет блок meraocenka.ru, сверяет, что каждый маршрут из PUBLIC_ROUTES раздаётся, и что у каждой страницы есть 301 с длинного адреса RouteGuard.publicPaths.ts — вытаскивает матчер @meraPages и сверяет с списком публичных путей в гварде Оба комментария прямо объясняют, зачем так: списки уже расходились дважды (15.08 и 16.08), причём страница в обоих случаях отдавала 200 и ломалась только после гидратации — ни один тест по коду ответа этого не видел. После переноса site-блоков в caddy/sites/*.caddy корневой файл этих блоков не содержит, и проверки стали бы пустыми. Тесты честно упали на своих же страховках («блок не найден — иначе проверки ниже пустые», «не нашли матчер @meraPages — проверка стала бы пустой»), а не тихо позеленели. Теперь оба читают эффективный конфиг: корневой Caddyfile + все caddy/sites/*.caddy. Все файлы берутся намеренно — `import caddy/sites/{$CADDY_SITES:*}` без переменной раскрывается в звёздочку, то есть это и есть конфиг по умолчанию. Проверено симуляцией ровно тех утверждений, на которых падал CI: срез между meraocenka.ru и merahome.ru = 10 458 символов (тест ждёт >500), матчер @meraPages найден, в нём 5 путей. Запустить vitest локально не вышло — фронтовые зависимости не установлены (node_modules/.bin пуст), так что окончательная проверка за CI. Refs #3059CI поймал настоящую связь, которой я не ждал — и это хороший знак, что она поймалась громко.
Два фронтовых теста читают
Caddyfileкак источник правды о публичном периметре, а не дублируют список путей:public-perimeter.test.tsmeraocenka.ru, сверка что каждый маршрут изPUBLIC_ROUTESраздаётся, и что у каждой страницы есть 301 с длинного адресаRouteGuard.publicPaths.test.ts@meraPages, сверка со списком публичных путей в гвардеКомментарии в обоих прямо объясняют, зачем так: списки уже расходились дважды (15.08 — на
/, 16.08 — на/estimate), причём страница в обоих случаях отдавала 200 и ломалась только после гидратации, так что ни один тест по коду ответа этого не видел.После переноса site-блоков в
caddy/sites/*.caddyкорневой файл их не содержит — и проверки стали бы пустыми. Тесты упали на своих же страховках («блок не найден — иначе проверки ниже пустые», «не нашли матчер@meraPages— проверка стала бы пустой»), а не тихо позеленели. Ровно то, ради чего эти страховки и писались.Починено в
87ffb5d6: оба теста читают эффективный конфиг — корневойCaddyfileплюс всеcaddy/sites/*.caddy. Все файлы берутся намеренно:import caddy/sites/{$CADDY_SITES:*}без переменной раскрывается в звёздочку, то есть это и есть конфиг по умолчанию.Проверено симуляцией ровно тех утверждений, на которых падал CI:
meraocenka.ru {иmerahome.ru {— 10 458 символов (тест ждёт >500)@meraPagesнайден, в нём 5 путейЗапустить vitest локально не вышло — фронтовые зависимости не установлены (
node_modules/.binпуст), так что окончательная проверка за CI.