trbrt — специализированный шлюз для маршрутизации, валидации и дедупликации событий Tribute. Сервис обеспечивает идемпотентность обработки, защиту от replay-атак, буферизацию нагрузки и безопасную доставку полезной нагрузки во внутренние системы.
Система поставляется как композиция сервисов:
- trbrt (Core): Golang-приложение. Реализует бизнес-логику, работу с SQLite, очередь отправки и метрики.
- Nginx: Обеспечивает SSL (Let's Encrypt), сжатие, заголовки безопасности и маршрутизацию трафика.
- Certbot: Автоматизация жизненного цикла TLS-сертификатов (ACME).
- Prometheus: Сбор метрик с интервалом 5s.
- Grafana: Визуализация. Провиженинг дашбордов.
Развертывание выполняется через docker compose с оркестрацией скриптом deploy.sh.
- ОС: Ubuntu LTS.
- Сеть: Открытые порты TCP 80, 443.
- DNS: A/AAAA записи для
NGINX_SERVER_NAME.
Создайте файл .env на основе .env.example. Критические параметры:
| Параметр | Описание |
|---|---|
TRIBUTE_API_KEY |
Секрет для валидации HMAC-SHA256 подписи. |
NGINX_SERVER_NAME |
FQDN сервера. |
LETSENCRYPT_EMAIL |
Email для уведомлений Let's Encrypt. |
GRAFANA_ADMIN_PASSWORD |
Пароль администратора Grafana (admin). |
ENABLE_NFS=1 ENABLE_UFW=1 ENABLE_TLS=1 ./deploy.shENABLE_NFS=1: Запрет запуска на сетевых ФС (SQLite требует корректныхfcntlблокировок).ENABLE_UFW=1: Настройка firewall (allow 22, 80, 443).ENABLE_TLS=1: Выпуск сертификатов. При0Nginx работает в HTTP-only режиме.
Эндпоинт приема событий.
Заголовки:
Content-Type: application/jsontrbt-signature: HMAC-SHA256 (hex). Префиксsha256=допускается.
Схема события (JSON):
{
"name": "new_subscription",
"created_at": "2024-01-01T12:00:00Z",
// RFC3339 / RFC3339Nano
"sent_at": "2024-01-01T12:00:01Z",
// RFC3339 / RFC3339Nano
"payload": {
"channel_id": 12345,
// int > 0
"telegram_user_id": 987654321,
// int > 0
"period": "1m",
// string, non-empty
"expires_at": "2024-02-01T12:00:00Z"
// RFC3339, optional
}
}Временные метки нормализуются к UTC.
Коды ответов:
| Код | Описание |
|---|---|
200 |
Успех (в т.ч. дедупликация или soft-drop). |
400 |
Ошибка валидации JSON или нарушение Freshness policy. |
401 |
Невалидная подпись. |
413 |
Превышен лимит тела (TRIBUTE_MAX_BODY_BYTES). |
429 |
Перегрузка очереди (при TRIBUTE_REJECT_ON_OVERLOAD=1). |
503 |
Сервис не готов (Readiness) или ошибка записи в БД. |
GET /healthz: Liveness probe (Nginx -> App).GET /readyz: Readiness probe. Возвращает 503, если БД недоступна, очередь переполнена или есть ошибки конфигурации.
Вычисляется HMAC-SHA256(body, TRIBUTE_API_KEY). Несовпадение → 401.
Валидируется структура JSON. Некорректные поля → 400.
Проверка возраста события: |now - sent_at| <= TRIBUTE_MAX_EVENT_AGE.
- По умолчанию:
5m. - При нарушении: Возвращается
400. - Если
TRIBUTE_FRESHNESS_SOFT_DROP=1: Возвращается200, событие игнорируется (не пишется в БД).
Идемпотентность обеспечивается на уровне БД (SQLite Unique Index).
- Ключ:
tenant+name+channel_id+created_at. - Окно:
TRIBUTE_DEDUPE_WINDOW(default12h). - Поведение:
INSERT OR IGNORE. Дубликат не считается ошибкой.
Формат данных, отправляемых в целевую систему, зависит от TRIBUTE_COMPACT_FORWARD.
- Full Mode (
0, default): Отправляется исходный JSON веб-хука. - Compact Mode (
1): Отправляется сокращенная структура:{ "user_id": 123, "expires_at": "..." }
Стек мониторинга изолирован во внутренней сети. Внешний доступ только через Nginx (/grafana/).
- Версия: v3.7.3
- Scrape Target:
trbrt:8080/metrics(доступ закрыт извне). - Retention: 30 дней.
- Версия: 12.3.0
- Доступ:
https://<HOST>/grafana/. Логинadmin, пароль изGRAFANA_ADMIN_PASSWORD. - Provisioning: Дашборды загружаются автоматически из
monitoring/grafana/provisioning.
Ключевые метрики:
- Service Health: Success Rate, RPS, Saturation (очередь, память дедупликатора).
- Ingress: Детализация ошибок (подпись, роутинг, формат).
- Storage (SQLite):
Write Errors: Критический показатель отказа диска/прав.Locks (Retries): Индикатор конкуренции за файл БД (WAL).
- Upstream: Latency, коды ответов, блокировки SSRF/Redirects.
Все параметры задаются через переменные окружения.
| Переменная | Default | Описание |
|---|---|---|
TRIBUTE_API_KEY |
— | Required. Секрет подписи. |
TRIBUTE_LOG_LEVEL |
debug |
Уровень логов (debug, info, warn, error). |
TRIBUTE_MAX_BODY_BYTES |
1048576 |
Лимит тела запроса (1MB). |
| Переменная | Default | Описание |
|---|---|---|
TRIBUTE_ROUTES_PATH |
/etc/trbrt/routes.json |
Путь к файлу маршрутов. |
TRIBUTE_CHANNELS_PATH |
/etc/trbrt/channels.json |
Путь к файлу каналов. |
TRIBUTE_DB_PATH |
/var/lib/trbrt/events.db |
Путь к SQLite БД. |
TRIBUTE_RETENTION_DAYS |
14 |
Срок хранения событий в БД. |
| Переменная | Default | Описание |
|---|---|---|
TRIBUTE_FORWARD_CONCURRENCY |
64 |
Количество воркеров отправки. |
TRIBUTE_FORWARD_QUEUE |
4096 |
Размер буфера канала. |
TRIBUTE_FORWARD_TIMEOUT |
5s |
Таймаут запроса к апстриму. |
TRIBUTE_REJECT_ON_OVERLOAD |
0 |
1 = Отказ (429/503) при полной очереди. |
TRIBUTE_UPSTREAM_HTTPS_ONLY |
1 |
Запрет отправки на http:// URL. |
TRIBUTE_COMPACT_FORWARD |
0 |
1 = Отправлять компактный JSON. |
| Переменная | Default | Описание |
|---|---|---|
TRIBUTE_READY_FAIL_ON_INVALID_SIGNATURES |
0 |
1 = Fail readyz при всплеске невалидных подписей (атака). |
TRIBUTE_READY_FAIL_ON_CONFIG_ERRORS |
0 |
1 = Fail readyz при ошибках hot-reload конфигов. |
Управление маршрутами без простоя сервиса.
# Список маршрутов
docker compose run --rm trbrtctl routes list
# Добавление маршрута
docker compose run --rm trbrtctl routes add --tenant client_A --url https://api.client-a.com/webhook
# Привязка канала к тенанту
docker compose run --rm trbrtctl channels add --tenant client_A --channel-id 123456Для разработки без выпуска TLS сертификатов.
Вариант A: Docker Compose (HTTP only)
Закомментируйте сервис certbot и certbot-init. В nginx/conf.d/trbrt.conf
не должно быть редиректа на HTTPS (или используйте порт 8080 напрямую, если он опубликован).
Вариант B: Запуск без Nginx
services:
trbrt:
ports:
- "8080:8080"Приложение будет доступно по http://127.0.0.1:8080/webhook/tribute.
- Pprof: Включите
TRIBUTE_PPROF=1. Профайлер доступен наlocalhost:6060(требует проброса порта). - JSON Errors:
TRIBUTE_ERRORS_AS_JSON=1включает структурное логирование ошибок в HTTP-ответах.
Распространяется по лицензии Mit License. Подробности смотрите в разделе LICENSE. © 2025 Robert Tkach.