Кейс: переводим два продакшен-бота на прокси-токены за вечер
Полевой отчёт без глянца. Два рабочих Telegram-бота — аналитический и рассылочный, суммарно пара тысяч запросов в сутки, — токены которых лежали в конфигах открытым текстом. Задача: спрятать оригиналы в хранилище, ничего не сломав. Ушёл один вечер и три грабли.
Исходная точка
Классика жанра: токены ботов в .env на сервере, в systemd-юнитах и в истории команд после каждой отладки. Любой, кто получает чтение диска или логов, получает и ботов. План миграции на credential proxy:
- завести настоящие токены в хранилище (шифруются, наружу больше не возвращаются);
- выписать по проходке на бота — со своими лимитами и привязкой к IP;
- поменять в конфигах ботов base URL и токен;
- убедиться, что всё работает, и вычистить оригиналы из конфигов.
По плану — полчаса. Дальше начались грабли, ради которых этот пост и написан.
Грабли 1: библиотека не приняла проходку
Первый бот на aiogram упал ещё до первого запроса: библиотека валидирует формат токена <цифры>:<хэш> на старте, и «голая» проходка vlt_telegrambot_… проверку не проходит.
<bot_id>:vlt_…: цифры до двоеточия игнорируются, но формат становится «правильным» для aiogram/telebot/grammY. Это не хак поверх, а поддержанное поведение — включая URL-encoded вариант %3A.
Грабли 2: long-polling обрывался
Аналитический бот работает через getUpdates с timeout=50 — запрос висит до 50 секунд в ожидании апдейтов. Первые прогоны через прокси обрывались раньше: таймаут заголовков у прокси был короче, чем таймаут поллинга.
Починили на стороне прокси: для getUpdates действует полный 300-секундный бюджет (и на заголовки тоже), а чтобы это не сломал будущий рефакторинг — есть тест, который фиксирует минимальный бюджет в 60 секунд. Если строите свой прокси для ботов — заложите это сразу: обычные HTTP-таймауты для long-polling не годятся.
Грабли 3: футган ручного ребинда IP
Проходки заводились в режиме auto: первый запрос обучает привязку к IP, дальше все чужие адреса получают 403. Оба бота корректно привязались к своему серверу.
А потом привязку одного из ботов снесли вручную: кнопка «переобучить IP» была нажата «на всякий случай» — и проходка снова стала принимать первый попавшийся адрес. Окно уязвимости заметили по таблице источников в панели.
Результат
| Было | Стало |
|---|---|
Токены в .env, юнитах, истории shell | В конфигах только отзываемые проходки |
| Утечка = revoke в BotFather + перезапуск всего | Утечка = «отозвать» одним кликом, оригинал не тронут |
| Кто и как дёргает Bot API — неизвестно | Лог каждого вызова: ~1700+ запросов/сутки на рассылочном боте, всплески и 4xx видны сразу |
| Токен работает с любого IP | 403 с любого адреса, кроме сервера бота |
Суммарное время миграции двух ботов со всеми граблями — один вечер. Повторная миграция третьего бота позже заняла десять минут: грабли уже были собраны.
Чеклист, если повторяете
- токен в библиотеку — в составной форме
<bot_id>:vlt_…; - base URL — на прокси, путь и всё остальное не трогаете;
- если бот на long-polling — проверьте таймауты прокси до продакшена;
- после привязки IP — не трогайте ребинд без причины;
- вычистите старые токены:
.env, юниты, историю (history -c), и только потом считайте миграцию законченной. Полный разбор про телеграм-токены — здесь.
Повторите на своём боте
Весь путь из этого кейса — панель, проходки, лимиты, лог — доступен бесплатно, без карты.
Начать →