gendesign/caddy/sites/infra.caddy
bot-backend 309d273f3f
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 9s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
feat(observability): стек метрик и логов — Prometheus, Loki, Grafana, агенты на обоих хостах
Метрик в проекте не было ни одной: ни экспортеров, ни /metrics в бэкендах,
единственный канал наблюдения — journald, единственный сигнал об аварии —
исключение в GlitchTip. Из-за этого целый класс отказов невидим в принципе:
задача рапортует done, строк ноль, исключения нет. Так протухли данные на семь
месяцев (#2998), 34 дня был мёртв house_imv_backfill (#2698), 8 суток писал ноль
newbuilding_enrich (#2767), 91 день копилось раздутие listings (#2992).

Grafana не заменяет GlitchTip: ошибки остаются там. Grafana OSS не принимает
Sentry DSN ни одним компонентом, а скрубберы в before_send — требование 152-ФЗ.
Здесь появляется другой класс данных: ряды и алерты по трендам.

Наблюдатель поставлен у ДРУГОГО провайдера, чем наблюдаемое: серверная сторона
на Beget, рядом с GlitchTip. Если ляжет Poincare, мониторинг должен об этом
сказать, а не лечь вместе с ним.

Транспорт push, а не pull: агент на Poincare шлёт remote_write и логи исходящим
HTTPS, поэтому там не открывается ни одного входящего порта сверх 22/80/443.
При обрыве канала Alloy копит в WAL и досылает — pull-скрейп в той же ситуации
терял бы точки именно в аварии, ради которой мониторинг и нужен.

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

GlitchTip читается прямым SQL, а не Sentry-плагином: у плагина на 6.1.6
stats_v2 отдаёт 500 (баг GlitchTip #381), Events/Discover — 404 (#416), а в
grafana/sentry-datasource слово glitchtip не встречается ни разу. Схема сверена
на живой базе: колонка времени называется timestamp, а не received, и отдельной
таблицы IssueIndex не существует — агрегаты лежат на самой issue_events_issue.

Алерты за профилем alerts: канал доставки — открытый вопрос #3078, и стек не
должен на нём стоять. Деплой предупреждает, что уведомлять пока некому.

Каждая настройка, способная отказать молча, закрыта явно: ретенция Prometheus
задана и по времени и по размеру, retention_enabled у компактора Loki (без него
retention_period не работает вовсе), путь к журналу и запуск Alloy от root
(иначе агент читает ноль записей без ошибки), проверка Caddy до перезагрузки
(на этом хосте тот же Caddy держит git, errors и obsidian).

Refs #3078
2026-08-26 10:45:54 +03:00

105 lines
5.3 KiB
Text
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/sites/infra.caddy — инфраструктурные домены, остающиеся на Beget
#
# Переезд GenDesign с Beget (46.173.16.127) на Selectel Poincare
# (188.246.224.93), окно 30.08.2026. Три домена этого файла ОСТАЮТСЯ на
# Beget — переезжают только Site Finder/МЕРА-домены (см.
# caddy/sites/apps.caddy). Общий механизм переключения (переменная
# CADDY_SITES, `import caddy/sites/{$CADDY_SITES:*}.caddy` в корневом
# Caddyfile, мотив с ACME rate-limit) описан в шапке apps.caddy — не
# дублируем здесь, читай там.
#
# Домены в этом файле (после переезда — на Beget, CADDY_SITES=infra):
# - obsidian.gendsgn.ru — Obsidian Self-hosted LiveSync (CouchDB backend)
# - errors.gendsgn.ru — GlitchTip, self-hosted error tracking
# - git.gendsgn.ru — Forgejo, self-hosted git + Actions CI
#
# На Selectel (CADDY_SITES=apps) этот файл не импортируется вообще — Caddy
# там даже не видит эти хосты и не пытается выпускать для них сертификаты.
# ═══════════════════════════════════════════════════════════════════════════
# Obsidian Self-hosted LiveSync (CouchDB backend).
# Auto-TLS Let's Encrypt. CORS уже включён на стороне CouchDB через bootstrap
# (см. scripts/setup-couchdb.sh). Basic-auth — на стороне CouchDB (admin user).
#
# DNS: A-record obsidian.gendsgn.ru → IP VPS.
# Клиенты Obsidian + Self-hosted LiveSync plugin указывают на этот URL.
obsidian.gendsgn.ru {
encode zstd gzip
reverse_proxy couchdb:5984 {
# Большие документы (vault attachments / images) — увеличиваем timeout
transport http {
response_header_timeout 120s
}
}
}
# GlitchTip — self-hosted error tracking (Sentry-compatible).
# DNS: A-record errors.gendsgn.ru → IP VPS.
errors.gendsgn.ru {
encode zstd gzip
reverse_proxy glitchtip-web:8080
log {
output file /var/log/caddy/errors.gendsgn.ru.log
}
}
# Forgejo — self-hosted git (migration 2026-05-16).
# DNS: A-record git.gendsgn.ru → IP VPS.
# Forgejo container из forgejo-migration/docker-compose.yml на shared
# gendesign_default network. HTTP port 3000 (default Forgejo).
# Был добавлен вручную при migration, потерян при первом auto-deploy после
# изменения Caddyfile (deploy.yml делает git reset --hard). См. fix issue.
git.gendsgn.ru {
encode zstd gzip
reverse_proxy forgejo:3000
log {
output file /var/log/caddy/git.gendsgn.ru.log
}
}
# Мониторинг — Grafana + приёмник метрик и логов (задача #3078).
# DNS: A-record metrics.gendsgn.ru → 46.173.16.127 (заведена 2026-08-26).
#
# ПОЧЕМУ ЗДЕСЬ, А НЕ В apps.caddy. Наблюдатель сознательно поставлен у ДРУГОГО
# провайдера, чем наблюдаемое: продукт живёт на Selectel Poincare, и если ляжет
# он, мониторинг обязан выжить и сказать об этом. Стек поднимается отдельным
# compose-проектом gendesign-metrics и виден Caddy через сеть gendesign_shared.
#
# ДВА КОНТУРА С РАЗНЫМИ УЧЁТКАМИ:
# /ingest/* — машинный. Агент Alloy с Poincare шлёт сюда remote_write и логи
# исходящим HTTPS. Благодаря этому на Poincare не открыт НИ ОДИН
# входящий порт сверх 22/80/443.
# всё прочее — витрина Grafana под отдельным паролем.
# Пароль приёмника по построению лежит в открытом виде на продуктовом хосте;
# разделив учётки, мы не отдаём вместе с ним доступ к дашбордам.
metrics.gendsgn.ru {
encode zstd gzip
# handle_path срезает префикс: Prometheus получает /api/v1/write,
# как если бы обращались к нему напрямую.
handle_path /ingest/prometheus/* {
import ../metrics-ingest.caddy.snippet
reverse_proxy prometheus:9090
}
# Loki ожидает путь /loki/api/v1/push — он и остаётся после среза /ingest/loki.
handle_path /ingest/loki/* {
import ../metrics-ingest.caddy.snippet
reverse_proxy loki:3100
}
handle {
import ../metrics-ui.caddy.snippet
reverse_proxy grafana:3000
}
log {
output file /var/log/caddy/metrics.gendsgn.ru.log
}
}