Files
chatballs/Caddyfile
T
AndreyandClaude Opus 5 a321109a8f 🐛 fix(gateway): установка на нестандартном порту принимает формы
Шлюз передавал дальше Host без порта ({host} в Caddy, $host в nginx). Браузер
при этом шлёт Origin с портом, и CSRF-проверка Django отвергала любой POST на
установке, опубликованной как ip:8081: «Origin checking failed».

Теперь Host уходит с портом. X-Forwarded-Proto и X-Forwarded-For Caddy
принимает от прокси из частных сетей — установку часто ставят за прокси
панели, который снимает TLS и ходит к шлюзу по http; без этого CSRF падал бы
снова, как только перед установкой появлялся https.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 11:32:25 +03:00

75 lines
3.8 KiB
Caddyfile

# Caddyfile — единый HTTP/HTTPS public boundary Chatballs (ADR-HUB-0028 §gateway).
# Подставляется в release bundle и монтируется в контейнер gateway.
#
# Свежая установка не знает своего домена: человек поднимает докер на сервере и
# открывает её по IP. Поэтому здесь нет блоков с зашитым именем хоста — они бы
# заставили Caddy выпускать сертификат и уводить http на https до того, как
# домен вообще появился. Вместо них: :80 отвечает по http на любом адресе, а
# https обслуживает любой хост, который одобрил ask-эндпоинт (домены порталов и
# домен установки, заданный в UI). Сертификаты выписываются по мере надобности,
# без перезапуска шлюза.
{
# ACME-контакт не задаётся при установке: пока домена нет, нет и выпуска
# сертификатов. Адрес для уведомлений добавляется вместе с доменом в UI.
# Caddy admin API не публикуется наружу (default localhost:2019).
on_demand_tls {
ask http://backend-platform:8000/api/v1/gateway/help-domain/
}
# Установку часто ставят за прокси панели (aaPanel, nginx хоста), который
# снимает TLS и ходит сюда по http. Его X-Forwarded-Proto/For принимаются
# только из частных сетей — оттуда, где такой прокси и стоит; клиент из
# интернета подделать их не может.
servers {
trusted_proxies static private_ranges
}
}
(surfaces) {
# Host уходит с портом: браузер шлёт Origin с портом (http://ip:8081), и
# без него CSRF-проверка Django отвергала любой POST на нестандартном
# порту. X-Forwarded-Proto Caddy ставит сам: {scheme}, а за доверенным
# прокси — то, что прислал прокси (https, если TLS снят перед нами).
# Платформенная поверхность живёт на своём домене; пока он не задан,
# матчер намеренно не совпадает ни с чем.
@platform host {$CHATBALLS_PLATFORM_DOMAIN:platform.invalid}
handle @platform {
reverse_proxy backend-platform:8000 {
header_up Host {hostport}
header_up X-Real-IP {client_ip}
header_up X-Forwarded-For {client_ip}
}
}
# Всё остальное — приложение и публичные порталы: маршрутизация внутри
# frontend-контейнера.
handle {
reverse_proxy frontend:80 {
header_up Host {hostport}
header_up X-Real-IP {client_ip}
header_up X-Forwarded-For {client_ip}
}
}
}
# Обычный http на любом адресе: IP сервера, localhost, ещё не подтверждённый
# домен. Редиректа на https здесь нет намеренно — его делает блок ниже, когда
# для хоста реально выписан сертификат.
:80 {
encode gzip zstd
import surfaces
}
# Дополнительные сайты из постоянного тома сохраняются при обновлении шлюза.
import /config/sites/*.caddy
# Любой хост, которому ask-эндпоинт разрешил сертификат.
https:// {
encode gzip zstd
tls {
on_demand
}
import surfaces
}