Образи зібрались із першого разу, але далі знайшлось три речі. memlock без обмеження для Dragonfly дозволений не всюди: у контейнерній віртуалізації ядро відмовляє, і контейнер не стартує взагалі. Швидкість того не варта — обмеження знято. Caddy нескінченно просив Let's Encrypt видати сертифікат на IP, чого той не робить, і сайт лишався без TLS. Тепер порожня ACME_EMAIL означає самопідписаний сертифікат. Плюс default_sni: SNI не містить IP-адрес, тож без нього рукостискання обривалось «internal error». У README команда заведення власника не працювала: у образу ENTRYPOINT, і без --entrypoint ім'я команди йшло аргументом до netpulse-api. Заразом netpulse-user навчився створювати перший кабінет — свіжа база не має жодного, а користувач без кабінету нікуди не належить. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
83 lines
3.6 KiB
Caddyfile
83 lines
3.6 KiB
Caddyfile
# Зворотний проксі NetPulse.
|
||
#
|
||
# Caddy бере на себе сертифікати Let's Encrypt і оновлює їх сам. Це
|
||
# знімає з розгортання найчастішу причину нічного дзвінка — прострочений
|
||
# сертифікат на системі, яка сама має повідомляти про проблеми.
|
||
{
|
||
# Яким сертифікатом відповідати, коли клієнт не назвав імені.
|
||
#
|
||
# SNI не містить IP-адрес: стандарт дозволяє там лише доменні імена,
|
||
# тож браузер, який іде на https://93.171.243.247, не каже нічого — і
|
||
# Caddy не має за чим обрати сертифікат. Рукостискання обривається
|
||
# «internal error», сайт виглядає мертвим.
|
||
#
|
||
# З доменом ця настройка нічого не міняє: SNI приходить, і збіг
|
||
# знаходиться звичайним шляхом.
|
||
default_sni {$NETPULSE_DOMAIN}
|
||
}
|
||
|
||
# Одна директива на два випадки.
|
||
#
|
||
# tls <пошта> — сертифікат від Let's Encrypt на цю адресу;
|
||
# tls internal — власний самопідписаний.
|
||
#
|
||
# Значення приходить із NETPULSE_TLS, яке compose виводить із ACME_EMAIL:
|
||
# пошта задана — беремо справжній сертифікат, порожньо — самопідписаний.
|
||
#
|
||
# Порожнє значення тут не працює: Let's Encrypt не видає сертифікатів на
|
||
# публічні IP-адреси, і Caddy вічно повторював би спробу, а сайт лежав
|
||
# би без TLS. Перевірено живим розгортанням на голому IP.
|
||
|
||
# --- інтерфейс і API -------------------------------------------------
|
||
{$NETPULSE_DOMAIN} {
|
||
tls {$NETPULSE_TLS}
|
||
|
||
encode zstd gzip
|
||
|
||
# WebSocket живих оновлень. Окремим блоком, бо йому не можна
|
||
# ставити таймаут на відповідь: зʼєднання висить годинами й
|
||
# мовчить, поки на мапі нічого не змінюється.
|
||
@ws path /api/v1/ws
|
||
reverse_proxy @ws api:8080 {
|
||
flush_interval -1
|
||
}
|
||
|
||
# API і вшитий у бінарник інтерфейс — за однією адресою, тож
|
||
# розділяти їх не потрібно: SPA віддає той самий процес.
|
||
reverse_proxy api:8080
|
||
|
||
header {
|
||
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||
X-Content-Type-Options "nosniff"
|
||
X-Frame-Options "DENY"
|
||
Referrer-Policy "strict-origin-when-cross-origin"
|
||
-Server
|
||
}
|
||
|
||
log {
|
||
output stdout
|
||
format console
|
||
}
|
||
}
|
||
|
||
# --- колектор зондів -------------------------------------------------
|
||
#
|
||
# Зонди говорять gRPC поверх HTTP/2. Усередині мережі — h2c без TLS:
|
||
# сертифікат живе тут, а не в кожному примірнику колектора.
|
||
{$NETPULSE_DOMAIN}:9443 {
|
||
tls {$NETPULSE_TLS}
|
||
|
||
reverse_proxy h2c://collector:9443 {
|
||
# Потік Control двонаправлений і довгий: агент тримає його
|
||
# відкритим, доки живий. Буферизація тут ламає саме те, заради
|
||
# чого потік існує — миттєву доставку команд.
|
||
flush_interval -1
|
||
}
|
||
|
||
log {
|
||
output stdout
|
||
format console
|
||
}
|
||
}
|