Выбор между webhook и polling в Telegram-боте - не абстрактный архитектурный спор, а конкретное решение, которое влияет на скорость ответа бота, стоимость хостинга и количество головной боли при деплое. Я несколько лет держу ботов на aiogram и не так давно переводил клиентский бот с polling на webhook посреди рабочего дня без даунтайма - расскажу, чем эти два подхода отличаются на практике и как настроить каждый из них.
Webhook или polling: в чём разница для Telegram-бота
Polling - бот сам стучится к серверам Telegram методом getUpdates с определённым интервалом. Aiogram по умолчанию использует long polling с таймаутом 30 секунд: бот открывает соединение, Telegram держит его, пока не появится новый апдейт или не истечёт время, потом бот тут же открывает следующее. Со стороны кажется, что реакция мгновенная, но по факту это постоянный опрос.
Webhook работает наоборот: вы один раз регистрируете у Telegram HTTPS-адрес методом setWebhook, и дальше при каждом новом сообщении Telegram сам присылает POST-запрос на этот адрес. Бот не спрашивает - ему приносят.
Long polling: как работает getUpdates и когда его хватает
Для разработки и тестовых ботов long polling - самый быстрый способ начать. Не нужен домен, не нужен SSL-сертификат, бот прекрасно работает с ноутбука за NAT или с дешёвого VPS без белого IP. Запускается буквально в три строки на aiogram:
import asyncio
from aiogram import Bot, Dispatcher
async def main():
bot = Bot(token="TOKEN")
dp = Dispatcher()
await dp.start_polling(bot)
asyncio.run(main())
Проблемы начинаются при росте нагрузки. Если бот падает или перезапускается, апдейты копятся в очереди на серверах Telegram - они хранятся там до 24 часов, но при возврате бот получит их пачкой, и обработка растянется. Второй нюанс: если случайно запустить два инстанса одного бота (например, старый процесс не убился при деплое), Telegram отдаёт ошибку 409 Conflict - оба клиента дерутся за один и тот же getUpdates. С polling я сталкивался с этим регулярно на ранних версиях CI/CD, пока не добавил принудительный kill предыдущего процесса перед стартом нового.
Webhook: как Telegram стучится в ваш бот
Для webhook нужен HTTPS с валидным сертификатом - самоподписанный тоже годится, но тогда публичный ключ придётся передать в параметре certificate при вызове setWebhook. Порт должен быть одним из разрешённых: 443, 80, 88 или 8443. Домен или статический IP обязателен, локальная разработка через ngrok или Cloudflare Tunnel подходит только для тестов.
Telegram допускает до 40 одновременных соединений на один webhook (параметр max_connections, можно поднять до 100 для высоконагруженных ботов), и присылает апдейт сразу - обычно задержка укладывается в 100-300 мс, против нескольких секунд у long polling под нагрузкой. Отдельно советую сразу выставлять secret_token при регистрации вебхука: без него на ваш эндпоинт в теории может постучаться кто угодно с поддельным JSON, а с токеном вы проверяете заголовок X-Telegram-Bot-Api-Secret-Token перед обработкой.
Webhook vs polling: сравнение в цифрах
| Критерий | Polling | Webhook |
|---|---|---|
| Задержка ответа | от долей секунды до нескольких секунд под нагрузкой | 100-300 мс стабильно |
| Домен и SSL | не нужны | обязательны |
| Нагрузка на сеть | постоянные запросы даже без новых сообщений | запрос только при реальном событии |
| Масштабирование на несколько инстансов | конфликтует, нужен один процесс | штатно раздаётся через max_connections |
| Диагностика ошибок | видно в логах бота сразу | нужно проверять getWebhookInfo и last_error_message |
| Подходит для | MVP, тестов, низкой нагрузки | продакшена, интеграций с оплатой и логистикой |
Бесплатный материал
🎁 Полезный скрипт в подарок
Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.
Без спама. Отписка в 1 клик.
Как настроить webhook для aiogram-бота
Сертификат и домен
Проще всего взять VPS с nginx в роли reverse-proxy и бесплатный сертификат Let’s Encrypt через certbot. Бот слушает localhost на своём порту, nginx проксирует HTTPS-трафик с домена на него - тогда сертификат для Telegram грузить вообще не нужно, он видит валидный сертификат самого домена. Самоподписанный сертификат имеет смысл только если домена в принципе нет и вы регистрируете вебхук напрямую на IP, но такой вариант я бы не советовал для продакшена - слишком много нюансов с обновлением сертификата.
Код на aiogram 3.x
from aiogram import Bot, Dispatcher
from aiogram.webhook.aiohttp_server import SimpleRequestHandler, setup_application
from aiohttp import web
WEBHOOK_PATH = "/webhook"
WEBHOOK_URL = "https://yourdomain.ru" + WEBHOOK_PATH
SECRET = "my-secret-token"
async def on_startup(bot: Bot):
await bot.set_webhook(WEBHOOK_URL, secret_token=SECRET, max_connections=60)
bot = Bot(token="TOKEN")
dp = Dispatcher()
dp.startup.register(on_startup)
app = web.Application()
SimpleRequestHandler(dispatcher=dp, bot=bot, secret_token=SECRET).register(app, path=WEBHOOK_PATH)
setup_application(app, dp, bot=bot)
web.run_app(app, host="127.0.0.1", port=8080)
Если бот собран в n8n, руками поднимать aiohttp-сервер не придётся: нода Telegram Trigger сама вызывает setWebhook при активации workflow, указывая публичный URL инстанса n8n. Единственное условие - сам n8n должен быть на HTTPS с корректным сертификатом, иначе Telegram откажется регистрировать вебхук.
Если не хочется писать обвязку под вебхук с нуля, у меня в библиотеке готовых скриптов есть рабочий шаблон настройки вебхука для aiogram вместе с systemd-юнитом и конфигом nginx - экономит час-полтора на типовой настройке.
Частые ошибки при переходе на webhook
- Забыть вызвать
deleteWebhookперед запуском бота в режиме polling - Telegram не даёт использовать getUpdates, пока активен вебхук, и отдаёт понятную, но неожиданную для новичка ошибку 409 - Выпустить сертификат на IP-адрес вместо домена - Telegram такие сертификаты не принимает при ручной загрузке через параметр certificate
- Пропустить проверку secret_token на своей стороне - тогда любой, кто узнает URL эндпоинта, сможет слать в бот произвольные фейковые апдейты
- Долго обрабатывать апдейт до ответа 200 OK - Telegram ждёт быстрое подтверждение, тяжёлые операции (запрос к CRM, генерация отчёта) нужно выносить в фоновую задачу, а не держать в теле обработчика запроса
- Не учитывать повторную доставку - если сервер не успел ответить вовремя, Telegram может прислать тот же апдейт ещё раз, и без проверки на дубли бот отправит пользователю два одинаковых сообщения
Когда оставаться на polling, а когда переключаться на webhook
Polling закрывает 90% задач на этапе MVP и тестового запуска: нет домена, нет нагрузки, разработчик гоняет бота с локальной машины. Как только бот выходит в продакшен и обрастает интеграциями - переход на webhook становится не опцией, а необходимостью.
Показательный пример из практики: бот интернет-магазина, который принимает уведомления об оплате от Т‑Банка и статусы доставки от СДЭК, а потом сам отвечает клиенту в Telegram. Тут задержка в пару секунд на каждом хопе складывается в заметное для пользователя ожидание, поэтому и приём внешних вебхуков, и связь с Telegram у такого бота идут через webhook - иначе разница в реакции видна невооружённым глазом уже при паре десятков заказов в день.
Разработка Telegram-бота под ключ у меня стоит от 30 000 ₽, а перенастройка уже работающего бота с polling на webhook - с сертификатом, nginx и systemd - обычно укладывается в рамки короткой доработки, отталкивайтесь от консультации от 3 000 ₽, если нужна оценка именно вашего случая.
Автоматизация в мессенджере
Telegram-бот / Mini App
от 30 000 ₽
Подробнее →Частые вопросы
Можно ли использовать webhook без своего домена?
Технически нет - Telegram требует HTTPS-адрес с валидным сертификатом, а для тестов можно временно прокинуть туннель через ngrok или Cloudflare Tunnel, но для продакшена такой вариант нестабилен: туннель может обрываться, а адрес меняться при перезапуске.
Насколько быстрее webhook по сравнению с polling?
На практике задержка при webhook держится в районе 100-300 мс, потому что Telegram присылает апдейт сразу же после события. У long polling задержка зависит от загрузки - в спокойные моменты тоже доли секунды, но под нагрузкой или при большом таймауте getUpdates может доходить до нескольких секунд.
Что произойдёт, если сервер с webhook временно упадёт?
Telegram делает несколько попыток доставки с нарастающим интервалом, а апдейты, которые не удалось доставить, хранятся в очереди до 24 часов. Как только сервер отвечает 200 OK, доставка возобновляется - сообщения не теряются, но реагировать бот будет с задержкой, накопленной за время простоя.
Нужно ли настраивать webhook вручную для бота на n8n?
Нет, нода Telegram Trigger регистрирует вебхук автоматически при активации workflow - она сама вызывает setWebhook с публичным адресом вашего инстанса n8n. Единственное условие - сам n8n должен работать по HTTPS с действующим сертификатом, иначе Telegram откажется принимать регистрацию.