gendesign/Caddyfile
lekss361 60cb510ef2
Some checks failed
Deploy / changes (push) Successful in 8s
Deploy Trade-In / changes (push) Successful in 12s
Deploy / deploy-caddy (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy / build-worker (push) Successful in 48s
Deploy / build-backend (push) Successful in 49s
Deploy / build-frontend (push) Successful in 49s
Deploy / deploy (push) Successful in 1m37s
Deploy / deploy-status (push) Successful in 1s
Deploy Trade-In / build-frontend (push) Successful in 2m34s
Deploy / perimeter-smoke (push) Successful in 10s
Deploy Trade-In / test (push) Failing after 3m56s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / deploy (push) Has been skipped
Deploy Trade-In / perimeter-smoke (push) Has been skipped
Deploy Trade-In / deploy-status (push) Failing after 1s
refactor(caddy): разделить site-блоки по хостам под переезд (#3062)
2026-08-23 21:52:48 +00:00

96 lines
5.9 KiB
Caddyfile
Raw 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.

# Caddy config.
#
# - gendsgn.ru — main production site, auto-TLS via Let's Encrypt.
# - www.gendsgn.ru — 301 redirect to apex (canonical URL).
# - :80 — fallback for raw IP access. Closed by same auth gate (pilot phase).
#
# `handle /api/*` (NOT `handle_path`) — we keep the /api prefix because
# the FastAPI router is mounted at /api/v1/*.
#
# Auth gate: basic_auth for pilot phase (2026-05-23).
# Users managed via caddy/users.caddy.snippet (git history = audit trail).
# Public exclusions: /health (liveness probe), /preview/* (static mockups).
#
# #2558: с 2026-07 basic_auth гейтит ТОЛЬКО Site Finder (`/`, `/api/*`,
# `/analytics` и т.д.). `/trade-in/*` (+ `/sale-share` redirect) вынесены ВЫШЕ
# import'ау trade-in своя авторизация (форма входа + opaque session-cookie,
# см. #2552) поверх RBAC (`tradein-mvp/backend/app/core/rbac.py`). Site Finder
# всё ещё легаси-пилотный basic_auth (roles.yaml dual-mode остаётся живым для
# него — НЕ трогать caddy/users.caddy.snippet).
#
# IMPORTANT: route { } block is required to preserve directive order.
# Without route { }, Caddy executes directives in hard-coded default order
# (basic_auth runs before handle), making /health and /preview/* exclusions
# ineffective. With route { }, handlers are matched top-to-bottom as written.
# #2213: global `log_credentials` УБРАН. Он заставлял Caddy писать raw
# Authorization header (Base64 `user:password`, тривиально обратимый) в ОБА лог-файла
# (gendsgn.ru.log + auth_audit.log). Даже при root-only доступе и коротком retention
# это plaintext-пароли пилотов на диске — недопустимый риск против скромной выгоды.
# Trade-off: glitchtip-auth-forwarder больше не извлекает `attempted_username` из 401
# (тег деградирует в "(none)" — forwarder это уже обрабатывает gracefully, не падает).
# Событие basic_auth 401 (remote_ip / uri / method) по-прежнему уходит в GlitchTip.
# ── Site-блоки вынесены по хостам (#3059, переезд 30.08) ────────────────────
# Раньше все восемь доменов жили прямо здесь. После разделения продуктов между
# двумя хостами это стало опасно: деплой синхронизирует рабочее дерево с
# origin/main и перечитывает конфиг, поэтому на Selectel приезжал бы файл
# целиком — и Caddy начинал бы выпускать сертификаты для obsidian/errors/git,
# чей DNS указывает на Beget. ACME падал бы на HTTP-01, с риском упереться в
# rate limit Let's Encrypt.
#
# caddy/sites/apps.caddy gendsgn.ru, www, meraocenka, merahome, meraotsenka
# -> уезжают на Selectel
# caddy/sites/infra.caddy obsidian, errors, git
# -> остаются на Beget (Forgejo, GlitchTip, CouchDB)
#
# CADDY_SITES выбирает подмножество. Дефолт `*` = оба файла = ТЕКУЩЕЕ поведение
# Beget, где сейчас обслуживаются все восемь доменов — то есть до переезда
# ничего не меняется. В окне: на Selectel CADDY_SITES=apps, на Beget=infra.
import caddy/sites/{$CADDY_SITES:*}.caddy
# Plain HTTP by IP — closed by same auth gate (prevent bypass via direct IP / SSH tunnel).
# Caddy issues no TLS here (no hostname). /health remains public.
:80 {
encode zstd gzip
route {
# /health — public, без auth (GHA deploy smoke check, liveness probe).
handle /health {
reverse_proxy backend:8000
}
# Auth gate (same snippet as gendsgn.ru).
import caddy/users.caddy.snippet
handle /api/* {
reverse_proxy backend:8000 {
header_up X-Authenticated-User {http.auth.user.id}
}
}
handle {
reverse_proxy frontend:3000 {
header_up X-Authenticated-User {http.auth.user.id}
}
}
}
}
# Test deploy flow 2026-05-15T21:43:32Z
# ─────────────────────────────────────────────────────────────────────────────
# Локальные site-блоки, которых не может быть в git.
#
# Мотив: garmin.gendsgn.ru (личный remote MCP на этом же VPS). Апстрим-сервер
# аутентификации не имеет вовсе, а claude.ai custom connector ходит на голый URL
# без кастомных заголовков — единственный доступный рубеж это секрет в пути.
# Секрет в git класть нельзя, а блок, вписанный руками прямо сюда, сносится
# первым же деплоем (`git reset --hard origin/main`; 2026-08-16 так и вышло —
# контейнер остался жив, но хост пропал вместе со своим сертификатом).
#
# Поэтому: сам блок лежит на VPS как untracked `caddy/local/*.caddy` (reset
# --hard untracked не трогает), а в репозитории живёт только этот import.
# Пустой glob для Caddy не ошибка — `caddy validate` проходит, на машинах без
# локальных блоков строка просто ничего не делает.
import caddy/local/*.caddy