Перейти к содержанию

Конфигурация

Всё настраивается через переменные окружения. Они также читаются из .env и .env.local в рабочем каталоге (более поздние файлы имеют приоритет, а настоящие переменные окружения важнее обоих). Имена нечувствительны к регистру; логические значения принимают true/false, 1/0, yes/no, on/off.

Источник истины — settings.py.

Пресеты

compose.yaml загружает один из deploy/presets/*.env (standard, full, minimal) перед вашим .env. См. Быстрый старт.

Обзор

Переменная По умолчанию Группа
HOST 0.0.0.0 Сервер
PORT 3000 Сервер
WEB_CONCURRENCY число CPU, не больше 4 Сервер
FORWARDED_ALLOW_IPS 127.0.0.1 Сервер
ACCESS_LOG false Сервер
GRACEFUL_TIMEOUT 10 Сервер
WORKERS_MAX_RSS_MB — Сервер
METRICS_PORT — Сервер
DISABLE_DOCS false API
CORS_ALLOW_ORIGINS ["*"] API
PUBLIC_URL — API
DOCS_SITE_DIR — (в образе: /app/docs) API
ENABLE_PREVIEWS true Функции
ENABLE_FEED false Функции
ENABLE_RATE_LIMIT false Защита
RATE_LIMIT_RPM 120 Защита
RATE_LIMIT_BURST = RATE_LIMIT_RPM Защита
RATE_LIMIT_SHARED true Защита
ENABLE_POW false Защита
POW_SECRET — Защита
POW_DIFFICULTY 18 Защита
POW_CHALLENGE_TTL 300 Защита
POW_BIND_IP true Защита
ENABLE_GRAPHQL true GraphQL
GRAPHQL_MAX_DEPTH 10 GraphQL
GRAPHQL_MAX_COMPLEXITY 1500 GraphQL
GRAPHQL_MAX_ALIASES 15 GraphQL
GRAPHQL_MAX_TOKENS 2000 GraphQL
GRAPHQL_MAX_BATCH_SIZE 10 GraphQL
CACHE_MODE normal Производительность
PARSER_MODE full Производительность
MEMORY_TRIM_INTERVAL 10 Производительность
TELEGRAM_BASE_URL https://t.me Источник
TELEGRAM_TIMEOUT 10 Источник
TELEGRAM_MAX_CONCURRENCY 32 Источник
TELEGRAM_CLIENT browser Источник
TELEGRAM_BROWSER_PROFILE chrome_156 Источник
TELEGRAM_BROWSER_PLATFORM android Источник
TELEGRAM_SESSION_LIFETIME 14400 Источник
UPSTREAM_QUEUE_LIMIT 16 × TELEGRAM_MAX_CONCURRENCY Источник
MAX_WAITING_REQUESTS 4096 Источник
SHARED_COALESCING true Источник
EARLY_REFRESH_WINDOW 0.1 Источник
REDIS_URL — Кэш
REDIS_TIMEOUT 0.5 Кэш
REDIS_CONNECT_TIMEOUT 2 Кэш
REDIS_HEARTBEAT_INTERVAL 5 Кэш
PREVIEW_CACHE_TTL 3600 Кэш
MEMORY_CACHE_MAX_MB 64 Кэш
MEMORY_CACHE_MAX_TTL 10 Кэш
ENABLE_PEERS false Узлы
PEERS — Узлы
PEER_PORT 7946 Узлы
PEER_ADVERTISE_ADDR адрес маршрута по умолчанию Узлы
PEER_ALLOW_CIDR частные сети Узлы
PEER_SECRET — Узлы
PEER_ENCRYPTION false Узлы
PEER_TIMEOUT 0.05 Узлы
FEED_FRESH_TTL 60 Лента
FEED_STALE_TTL 900 Лента
FEED_REFRESH_MODE embedded Лента
FEED_REFRESH_MIN_INTERVAL 30 Лента
FEED_REFRESH_MAX_INTERVAL 600 Лента
FEED_REFRESH_TOP 200 Лента
FEED_POPULARITY_HALF_LIFE 3600 Лента
FEED_HALF_LIFE_HOURS 24 Лента
FEED_DIVERSITY 0.5 Лента
FEED_COLLAPSE_DUPLICATES true Лента
LOG_LEVEL INFO Логи
LOG_FORMAT text Логи

Сервер

HOST

Интерфейс, к которому привязывается HTTP-сервер (и слушатель метрик). Внутри контейнеров оставляйте 0.0.0.0; для экземпляра без контейнера за локальным обратным прокси используйте 127.0.0.1.

PORT

Порт HTTP-сервера. Docker-образ слушает 3000; публикуйте его через -p 8000:3000.

WEB_CONCURRENCY

Число процессов-воркеров. По умолчанию — число CPU, доступных процессу, но не больше 4. У каждого воркера свой цикл событий и, без Redis, свой кэш в памяти, поэтому при нескольких воркерах используйте Redis.

FORWARDED_ALLOW_IPS

Адреса прокси через запятую, заголовкам X-Forwarded-For / X-Forwarded-Proto которых можно доверять, или *, чтобы доверять любым (только если порт недоступен напрямую). От этого зависит IP клиента, который использует ограничитель частоты запросов. Пример для nginx на другом хосте: FORWARDED_ALLOW_IPS=10.0.0.5.

ACCESS_LOG

Логировать каждый запрос (true) — по умолчанию выключено, чтобы логи не шумели при высокой нагрузке.

GRACEFUL_TIMEOUT

Сколько секунд воркер может завершать текущие запросы после SIGTERM, прежде чем его принудительно остановят.

WORKERS_MAX_RSS_MB

Перезапускать воркер, резидентная память которого превысила столько МиБ. Страховка для хостов с ограниченной памятью; по умолчанию не задано. Воркер занимает ~60 МиБ в простое и ~100 МиБ под нагрузкой, плюс до MEMORY_CACHE_MAX_MB на свой кэш внутри процесса, так что значение около MEMORY_CACHE_MAX_MB + 150 срабатывает только при реальных проблемах.

METRICS_PORT

Отдавать метрики Prometheus сервера на этом порту по пути /metrics. См. Служебные эндпоинты.

API

DISABLE_DOCS

Скрыть стартовую страницу (/), справочник API (/api), /openapi.json, документацию (/docs/) и /sitemap.xml, а на /graphql — IDE GraphiQL, GET-запросы и интроспекцию схемы. /robots.txt тогда запрещает всё. См. Служебные эндпоинты.

CORS_ALLOW_ORIGINS

JSON-список разрешённых origin для браузеров, например CORS_ALLOW_ORIGINS='["https://example.com"]'. Значение по умолчанию ["*"] разрешает любой origin.

PUBLIC_URL

Публичный адрес экземпляра: схема и хост без пути и завершающей косой черты, например https://tme.example.com. С него начинаются абсолютные URL в /robots.txt и /sitemap.xml. Если не задан, берётся адрес, на который пришёл каждый запрос; за прокси он верен, только если прокси передаёт исходный Host. Workflow развёртывания задаёт его из PUBLIC_URL или PUBLIC_HOST.

DOCS_SITE_DIR

Каталог документации, собранной для /docs/ (scripts/build_docs.py), которую приложение там отдаёт. Docker-образ содержит сборку и задаёт /app/docs. Если не задан (установка из исходников), /docs/… перенаправляет на ту же страницу опубликованной документации. См. Служебные эндпоинты.

Функции

ENABLE_PREVIEWS

Включить /v1/preview/{channel} и /v1/previews. Когда они отключены, они отвечают 503.

ENABLE_FEED

Включить POST /v1/feed (и его фоновый рефрешер). По умолчанию выключено, потому что это самый тяжёлый эндпоинт. Когда он отключён, он отвечает 503.

Защита

Обе выключены по умолчанию; как они работают и что отправляют клиенты, описано в разделе Ограничение частоты и proof of work.

ENABLE_RATE_LIMIT

Ограничение частоты запросов по IP клиента для всех эндпоинтов (GCRA): всплеск до RATE_LIMIT_BURST запросов, затем RATE_LIMIT_RPM в минуту. При превышении API отвечает 429 с Retry-After. За прокси укажите FORWARDED_ALLOW_IPS, чтобы учитывался настоящий IP клиента. Запросы самого сервера (через loopback и не проксированные), например health check и smoke-тест деплоя, не ограничиваются.

RATE_LIMIT_RPM

Устойчивый темп: запросов в минуту на IP клиента.

RATE_LIMIT_BURST

Сколько запросов клиент может сделать сразу, прежде чем начнёт действовать поминутный темп. По умолчанию равно RATE_LIMIT_RPM.

RATE_LIMIT_SHARED

При заданном REDIS_URL каждый клиент считается по всем воркерам и серверам: раз в секунду каждый процесс добавляет свои счётчики в Redis и блокирует клиентов, превысивших лимит там. Запросы никогда не ждут Redis. При false или без Redis каждый процесс ограничивает сам по себе.

ENABLE_POW

Требовать proof of work в каждом запросе (кроме документации, /healthz и эндпоинта задач). Нужен POW_SECRET; задачи выдаёт GET /v1/pow/challenge.

POW_SECRET

Подписывает задачи (HMAC-SHA256). Не короче 32 символов, одинаковый на всех серверах и секретный: зная его, можно подделывать задачи. Сгенерировать: openssl rand -hex 32. Смена секрета делает выданные задачи недействительными.

POW_DIFFICULTY

Сколько ведущих нулевых бит должно быть в SHA-256 каждого запроса, от 8 до 32. Каждый бит удваивает работу клиента: 18 — это около 0,2 с на Python и 17 мс в нативном коде на запрос. См. Выбор сложности.

POW_CHALLENGE_TTL

Сколько секунд задача остаётся действительной, от 30 до 3600. Всё это время клиент использует одну задачу для всех своих запросов.

POW_BIND_IP

Принимать задачу только с того IP, которому она выдана, чтобы решённые задачи нельзя было раздавать. Выключите для клиентов, у которых адрес часто меняется.

GraphQL

Как применяются лимиты, описано в разделе GraphQL.

ENABLE_GRAPHQL

Обслуживать GraphQL API на /graphql. Когда он отключён, путь отвечает 404. GraphiQL, GET-запросы и интроспекция дополнительно зависят от DISABLE_DOCS.

GRAPHQL_MAX_DEPTH

Максимально допустимая вложенность выборок ниже корневого поля (у корневого поля глубина 0; поля интроспекции не считаются).

GRAPHQL_MAX_COMPLEXITY

Максимально допустимая стоимость операции: 1 за каждое выбранное поле плюс 10 за каждый канал, который корневое поле может загрузить с t.me.

GRAPHQL_MAX_ALIASES

Максимальное число алиасов в одном документе.

GRAPHQL_MAX_TOKENS

Максимальная длина документа в токенах лексера GraphQL; ограничивает работу разбора.

GRAPHQL_MAX_BATCH_SIZE

Максимальное число операций в одном пакетном запросе (JSON-массив). Пакеты большего размера отклоняются с 400.

Производительность

CACHE_MODE

Значение Кэш страниц Cache-Control для Cloudflare
off нет — каждый запрос идёт на t.me нет
normal 10 с public, max-age=10, stale-while-revalidate=10
aggressive 120 с public, max-age=120, stale-while-revalidate=240

Действует на /v1/body, /v1/post и /v1/more. У превью и ленты свои настройки, см. ниже.

PARSER_MODE

Значение Что извлекается
full всё: текст с сущностями, медиа, опросы, кнопки, ответы, превью ссылок, реакции
simplified текст (без сущностей), медиа и кнопки — заметно дешевле по CPU

MEMORY_TRIM_INTERVAL

Интервал в секундах, с которым освобождённая память кучи возвращается операционной системе (malloc_trim, только glibc — то есть Docker-образ). Иначе после всплеска трафика glibc удерживает память больших короткоживущих объектов для повторного использования: воркер под нагрузкой держал ~80 МиБ такой свободной кучи. Одна очистка занимает около 1 мс. 0 отключает её.

Источник

TELEGRAM_BASE_URL

Адрес, с которого загружаются страницы t.me, — схема://хост[:порт] без пути. Позволяет направить сервис на зеркало или на поддельный t.me: так интеграционные тесты запускают образ против tests/integration/fake_telegram.py.

TELEGRAM_TIMEOUT

Общий тайм-аут одного запроса к t.me в секундах (фаза подключения ограничена 5 с). Неудачный запрос повторяется один раз на новом соединении, если ошибка сетевая.

TELEGRAM_MAX_CONCURRENCY

Максимум одновременных запросов к t.me на процесс-воркер. Защищает сервер от ограничения частоты запросов со стороны Telegram при больших запросах ленты или превью. Слоты делятся честно: по кругу между каналами и запросами ленты или превью, запросы пользователей — раньше фоновых обновлений (см. Кэширование).

TELEGRAM_CLIENT

HTTP-клиент для запросов к t.me:

  • browser (по умолчанию): нативный (wreq на BoringSSL). TLS-рукопожатие, настройки HTTP/2 и заголовки запроса берутся из одного профиля TELEGRAM_BROWSER_PROFILE, поэтому описывают один и тот же браузер.
  • reqwest: pyreqwest (rustls и hyper). Отправляет заголовки того же профиля, но его отпечатки TLS и HTTP/2 — это rustls и hyper, каких нет ни у одного браузера, и cookie он не хранит. В продакшене не используется.

Измерения — в разделе HTTP-клиент.

TELEGRAM_BROWSER_PROFILE

Браузер, которым представляются запросы. По умолчанию — chrome_156, собственный профиль проекта для текущего стабильного Chrome, в rust/telegram-me-native/src/http/chrome.rs. Можно выбрать и Chromium-профили wreq-util, например chrome_149, edge_148 или opera_131. С неизвестным именем сервер не запускается, а в сообщении указан самый новый профиль Chrome.

TELEGRAM_BROWSER_PLATFORM

Платформа этого браузера: android (по умолчанию), ios, windows, macos или linux. Задаёт User-Agent, sec-ch-ua-platform и sec-ch-ua-mobile; рукопожатие на всех платформах одинаковое. У chrome_156 нет варианта ios: Chrome на iOS использует TLS-стек Apple, а не BoringSSL; с такой парой сервер не запускается.

TELEGRAM_SESSION_LIFETIME

Сколько секунд живёт одна личность браузера у клиента browser, ±25 % случайно. Личность — это хранилище cookie (t.me ставит stel_ssid), соединения и их TLS-тикеты. Когда она заканчивается, клиент начинает с пустым хранилищем и новыми соединениями, как новый профиль браузера. По умолчанию 14400 (4 часа, то есть от 3 до 5); 0 держит личность, пока не истекут её cookie (у t.me они живут 24 часа) или t.me не ответит 4xx, кроме 404. И то и другое завершает личность и раньше срока. У каждого процесса-воркера своя личность (см. HTTP-клиент).

UPSTREAM_QUEUE_LIMIT

Сколько запросов воркер позволяет держать в ожидании свободного слота к источнику. Следующие запросы, которым нужен t.me, получают 503 с заголовком Retry-After вместо постановки в очередь. По умолчанию 16 на каждый слот TELEGRAM_MAX_CONCURRENCY (512).

MAX_WAITING_REQUESTS

Сколько запросов воркер позволяет одновременно держать в ожидании работы с источником (загрузки или рендеринга, начатых кем-то другим); сверх этого — 503 с Retry-After. Ограничивает память, которую может занять лавина запросов.

SHARED_COALESCING

С REDIS_URL каждая страница загружается один раз на все воркеры и серверы: процесс, который загружает, берёт в Redis короткую аренду (lease), а остальные ждут его результата, вместо того чтобы самим обращаться к t.me. Выключите, чтобы объединять запросы только внутри воркера.

EARLY_REFRESH_WINDOW

Обновлять в фоне кэшированную страницу, которую всё ещё читают в последней доле её свежести (0.1 — последняя секунда из 10 с при CACHE_MODE=normal), чтобы популярные страницы никогда не истекали под нагрузкой. 0 отключает.

Кэш

REDIS_URL

URL Redis или Valkey, например redis://valkey:6379/0 или rediss://user:pass@host:6380/0. Если задан, кэш страниц, кэш превью, популярность для ленты и блокировка лидера рефрешера общие для всех воркеров и серверов. Повторные запросы каждый воркер всё равно сначала обслуживает из своего кэша внутри процесса (MEMORY_CACHE_MAX_MB, MEMORY_CACHE_MAX_TTL), так что обращения к Redis ждут только его промахи. Если не задан, кэш внутри процесса — единственный.

Сбой Redis надолго не замедляет запросы: команды прерываются по тайм-ауту через REDIS_TIMEOUT, а после трёх ошибок подряд в течение 10 секунд Redis обходится стороной 30 секунд (circuit breaker), и API тем временем работает на своём кэше внутри процесса. Одна неудачная команда его не включает.

Каждый воркер держит до 2 × TELEGRAM_MAX_CONCURRENCY (не меньше 32) соединений с Redis. Всплеск команд сверх этого, например несколько запросов ленты по 100 каналов одновременно, ждёт свободного соединения до REDIS_TIMEOUT; команда, которая так и не получила соединение, считается промахом кэша и не размыкает circuit breaker.

REDIS_TIMEOUT

Тайм-аут выполнения команды в секундах, а также максимальное время ожидания свободного соединения из пула. Команда медленнее этого размыкает circuit breaker.

REDIS_CONNECT_TIMEOUT

Сколько секунд даётся на открытие нового соединения с Redis, включая TLS-рукопожатие. Он больше REDIS_TIMEOUT, потому что подключение к удалённому TLS-эндпоинту занимает несколько обменов: около 0,3–0,7 с при задержке 90 мс. С тайм-аутом команд каждое переподключение после ошибки не укладывалось бы во время и снова размыкало бы circuit breaker, и Redis продолжал бы отваливаться. Кроме того, каждый воркер открывает первое соединение при старте, чтобы за него не платил ни один запрос.

REDIS_HEARTBEAT_INTERVAL

Раз в столько секунд каждый воркер пишет в Redis свою метку (tme:v2:node:<host>:<pid>, TTL — три интервала); 0 отключает это.

  • Метка держит соединение открытым, поэтому запросы не платят за переподключение к удалённому TLS-эндпоинту.
  • Сбой замечается не позже чем через один интервал.
  • Метка отправляется даже при разомкнутом circuit breaker: как только Redis снова отвечает, breaker замыкается, не дожидаясь конца 30-секундной паузы.
  • Живые метки показывают, какие процессы на каких серверах работают: redis-cli --scan --pattern 'tme:v2:node:*'.

PREVIEW_CACHE_TTL

Сколько секунд превью канала хранится в кэше. Неизвестные каналы в любом случае кэшируются на 60 секунд.

MEMORY_CACHE_MAX_MB

Лимит памяти кэша внутри процесса, на воркер, с Redis и без него: записи хранятся сжатыми, а лимит учитывает то, что они реально занимают (значение, ключ и служебные данные). Первыми вытесняются давно не использовавшиеся записи. При значении по умолчанию 64 воркер под высокой нагрузкой держится около 170 МиБ (весь контейнер — около 230 МиБ). С Redis воркер держит только то, что было прочитано или записано за последние MEMORY_CACHE_MAX_TTL секунд, обычно намного меньше лимита.

MEMORY_CACHE_MAX_TTL

С Redis: сколько секунд максимум воркер хранит собственную копию записи кэша. Запись, которую другой сервер (или воркер ленты) записал в Redis, воркер увидит не позже чем через это время после записи; цена — одно чтение из Redis на ключ и воркер с такой периодичностью, для ключей, которые читают. Копии никогда не живут дольше записи в Redis. Без Redis, а также пока Redis недоступен, записи хранятся весь свой TTL. См. Внутреннее устройство → Кэширование.

Узлы

Узлы в одной частной сети могут делить работу напрямую: каждый ключ загружает с t.me один узел, его владелец, а остальные спрашивают его. Это работает и без Redis. См. Развёртывание → Слой узлов.

ENABLE_PEERS

Включает слой узлов. Каждый процесс-воркер становится узлом. Требует PEER_SECRET.

PEERS

Где искать другие узлы: записи host или host:port через запятую, например PEERS=10.0.0.108,10.0.0.165. DNS-имя может указывать на несколько адресов; имена заново разрешаются каждые 30 секунд. Запись без порта пробуется на всех портах диапазона PEER_PORT. Достаточно одного доступного узла: об остальных узнают от него. С Redis узлы находят друг друга ещё и по меткам heartbeat, так что PEERS можно оставить пустым.

PEER_PORT

Первый порт слоя узлов, и для UDP (членство), и для TCP (запросы). Каждый воркер берёт первый свободный порт от PEER_PORT до PEER_PORT + WEB_CONCURRENCY (один запасной — для воркера, который как раз заменяется). 0 позволяет ОС выбрать порт; полезно только в тестах.

PEER_ADVERTISE_ADDR

IP-адрес, по которому этот узел доступен другим. По умолчанию — адрес источника маршрута по умолчанию. Внутри контейнера это адрес самого контейнера, поэтому там укажите частный адрес хоста (продакшен-деплой так и делает).

PEER_ALLOW_CIDR

Сети через запятую, из которых другим узлам можно подключаться. Соединения и датаграммы откуда-либо ещё отбрасываются до того, как что-то прочитано. По умолчанию — все частные и loopback-диапазоны: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8, fc00::/7 и ::1/128.

PEER_SECRET

Общий секрет узлов, не короче 32 символов, например из openssl rand -hex 32. Каждое сообщение несёт сделанный им тег HMAC-SHA256, метку времени и nonce; поддельные, повторённые и старше 30 с сообщения отклоняются.

PEER_ENCRYPTION

Ещё и шифровать каждое сообщение (XChaCha20-Poly1305 с ключом, выведенным из PEER_SECRET) — для сетей, которым вы не доверяете. Настройка должна совпадать на всех узлах.

PEER_TIMEOUT

Сколько секунд у узла есть, чтобы подключиться и ответить на чтение кэша или принять загрузку, прежде чем этот узел сделает работу сам. Узел, не уложившийся в срок, обходят стороной 3 секунды.

Лента

Всё это имеет значение только при ENABLE_FEED=true. См. Внутреннее устройство → Лента.

FEED_FRESH_TTL

Закэшированная страница канала моложе этого значения (в секундах) используется как есть.

FEED_STALE_TTL

Страница старше FEED_FRESH_TTL, но моложе этого значения отдаётся сразу, а фоновое обновление её заменяет. Более старые страницы загружаются до ответа.

FEED_REFRESH_MODE

Значение Поведение
embedded рефрешер запускает каждый процесс API; с Redis работу выполняет только один из них (лидер)
worker API его не запускает; запустите telegram-me worker отдельно (нужен Redis)
off без фонового обновления; страницы обновляются только запросами ленты

FEED_REFRESH_MIN_INTERVAL

Самый короткий интервал обновления (в секундах), для самых популярных каналов.

FEED_REFRESH_MAX_INTERVAL

Самый длинный интервал обновления, для каналов почти без спроса. Канал с оценкой популярности s обновляется каждые clamp(MAX / (1 + s), MIN, MAX) секунд.

FEED_REFRESH_TOP

Сколько самых популярных каналов обслуживает рефрешер.

FEED_POPULARITY_HALF_LIFE

Период полураспада популярности канала в секундах: по прошествии этого времени запрос ленты весит вдвое меньше. Каналы с оценкой ниже 0.05 забываются.

FEED_HALF_LIFE_HOURS

Через сколько часов свежесть поста в ранжировании уменьшается вдвое. Меньшие значения сильнее продвигают самые новые посты.

FEED_DIVERSITY

От 0 (чистый порядок по оценке) до 1 (максимальное перемешивание каналов и тем). См. Внутреннее устройство → Лента.

FEED_COLLAPSE_DUPLICATES

Сворачивать одну и ту же новость, опубликованную несколькими каналами, в её лучший пост, перечисляя остальные в _duplicates.

Логи

LOG_LEVEL

DEBUG, INFO, WARNING или ERROR.

LOG_FORMAT

text — для людей, json — для сборщиков логов (по одному JSON-объекту на строку с time, level, logger, message и любыми структурированными дополнительными полями).