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
Метрик в проекте не было ни одной: ни экспортеров, ни /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
105 lines
5.3 KiB
Text
105 lines
5.3 KiB
Text
# ═══════════════════════════════════════════════════════════════════════════
|
||
# 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
|
||
}
|
||
}
|