Webhook или polling для Telegram-бота: что выбрать
Когда бот только-только запущен и получает пару сообщений в час, вопрос "webhook или polling" кажется теоретическим — работает же и ладно. Но как только бот начинает жить на боевом сервере, обрастает пользователями и нервирует вас задержками или падениями после рестарта, выбор способа получения обновлений от Telegram превращается в конкретное архитектурное решение. Разберём, чем они отличаются на деле, как настроить оба варианта и когда действительно нужен переход с одного на другой.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Как работают polling и webhook — суть разницы
У Telegram Bot API есть два способа получить входящие сообщения.
Polling (long polling) — ваш бот сам, в цикле, стучится к серверам Telegram методом getUpdates и спрашивает: "есть что-то новое?". Если новых сообщений нет, Telegram держит соединение открытым до 30–50 секунд (это и называется *long* polling, в отличие от наивного опроса раз в секунду), а затем отвечает пустым списком, и бот тут же спрашивает снова. Как только сообщение появляется, ответ приходит почти мгновенно, соединение закрывается, и бот сразу открывает новое.
Webhook — вы регистрируете у Telegram HTTPS-адрес своего сервера, и дальше Telegram сам, при появлении нового события, делает POST-запрос на этот адрес. Никакого опроса нет: сервер бота просто ждёт входящих запросов, как любой обычный веб-сервис.
Разница на уровне архитектуры простая: при polling инициатор соединения — ваш бот, при webhook — сама Telegram. Из этого и вытекают все практические следствия ниже: что нужно для настройки, какая будет задержка, как это ведёт себя под нагрузкой и что происходит при сбоях.
Polling: настройка на практике
Главное достоинство polling — с ним можно запустить бота за пять минут на любом сервере с исходящим доступом в интернет, без домена, без сертификата, без открытых портов. Это то же самое, что запустить консольный скрипт: python bot.py — и всё работает.
Пример на aiogram 3:
import asyncio
from aiogram import Bot, Dispatcher
bot = Bot(token="ВАШ_ТОКЕН")
dp = Dispatcher()
@dp.message()
async def echo(message):
await message.answer(message.text)
async def main():
await dp.start_polling(bot)
asyncio.run(main())
Пример на python-telegram-bot:
from telegram.ext import Application, MessageHandler, filters
async def echo(update, context):
await update.message.reply_text(update.message.text)
app = Application.builder().token("ВАШ_ТОКЕН").build()
app.add_handler(MessageHandler(filters.TEXT, echo))
app.run_polling()
На сервере такой процесс имеет смысл держать под supervisor-ом, а не запускать вручную — иначе после перезагрузки VPS бот просто не поднимется. Проще всего — systemd-юнит:
[Unit]
Description=Telegram bot
After=network.target
[Service]
WorkingDirectory=/opt/mybot
ExecStart=/opt/mybot/venv/bin/python bot.py
Restart=always
RestartSec=5
User=botuser
[Install]
WantedBy=multi-user.target
Restart=always здесь критичен: если библиотека потеряет соединение с Telegram (сеть моргнула, сервер перезагрузился), процесс просто упадёт и поднимется заново — это штатное поведение для polling, а не авария.
Важный нюанс: два одновременных getUpdates с одним токеном конфликтуют — Telegram вернёт ошибку 409 Conflict, если запустить второй экземпляр бота (например, случайно оставили старый процесс при деплое новой версии). Это частая причина "бот отвечает дважды на одно сообщение" или "бот вообще не отвечает" — оба процесса дерутся за обновления.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSWebhook: настройка на практике
Webhook требует чуть больше подготовки: домен, направленный на сервер, и валидный HTTPS-сертификат — Telegram принципиально не отправляет вебхуки на голый HTTP или самоподписанный сертификат без явной передачи публичного ключа.
Порядок действий:
- Направить A-запись домена на IP сервера.
- Поднять nginx как обратный прокси и получить сертификат Let's Encrypt через certbot.
- Запустить бота как локальный HTTP-сервис на внутреннем порту (например, 8081).
- Зарегистрировать webhook у Telegram.
Минимальный конфиг nginx:
server {
listen 443 ssl;
server_name bot.example.com;
ssl_certificate /etc/letsencrypt/live/bot.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/bot.example.com/privkey.pem;
location /webhook {
proxy_pass http://127.0.0.1:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Код бота на aiogram с встроенным веб-сервером (aiohttp):
from aiohttp import web
from aiogram import Bot, Dispatcher
from aiogram.webhook.aiohttp_server import SimpleRequestHandler, setup_application
bot = Bot(token="ВАШ_ТОКЕН")
dp = Dispatcher()
async def on_startup(app):
await bot.set_webhook("https://bot.example.com/webhook")
app = web.Application()
app.on_startup.append(on_startup)
SimpleRequestHandler(dispatcher=dp, bot=bot).register(app, path="/webhook")
setup_application(app, dp, bot=bot)
web.run_app(app, host="127.0.0.1", port=8081)
Аналогично можно поднять webhook и на python-telegram-bot через app.run_webhook(...) с указанием webhook_url, listen, port и путей к сертификатам, если не используете nginx как терминатор SSL.
Регистрацию можно проверить напрямую через API:
curl "https://api.telegram.org/bot<TOKEN>/getWebhookInfo"
Если поле last_error_message не пустое — Telegram уже пытался достучаться до вашего сервера и получил ошибку; это первое место, куда стоит смотреть при проблемах с доставкой.
За настройку домена, DNS и первого сертификата на чистом сервере подробно рассказано в статье про nginx как обратный прокси на VPS и про выпуск SSL через Let's Encrypt — оба шага занимают вместе минут 20, если делать не в первый раз.
Сравнение по критериям
| Критерий | Polling | Webhook |
|---|---|---|
| Нужен домен и SSL | Нет | Да, обязательно |
| Сложность первого запуска | Минимальная — один скрипт | Требует nginx/сертификат/DNS |
| Задержка ответа | Обычно доли секунды–секунда, но не гарантирована | Ближе к мгновенной — событие приходит сразу |
| Нагрузка на сервер бота | Постоянные фоновые запросы к Telegram | Нагрузка только при реальных сообщениях |
| Поведение при падении процесса | Просто переподключается при рестарте | Нужно, чтобы порт/сервис снова слушал запросы |
| Несколько инстансов бота одновременно | Конфликтует (409 Conflict) | Можно балансировать через nginx/несколько воркеров |
| Локальная отладка на своём компьютере | Работает из коробки | Нужен туннель (ngrok и подобные) или второй домен |
| Открытые порты наружу | Не нужны | Нужен открытый 443 (или другой разрешённый Telegram порт) |
| Расход ресурсов при простое | Небольшой, но непрерывный трафик опроса | Нулевой при отсутствии сообщений |
| Подходит для высоконагруженных ботов | С ростом нагрузки менее эффективен | Масштабируется лучше |
Цифры задержки и нагрузки — ориентировочные: конкретные значения зависят от библиотеки, региона сервера, канала связи и текущей нагрузки Telegram API, а не являются фиксированной характеристикой протокола.
Когда выбрать polling, когда webhook
Polling подходит, если:
- бот обслуживает десятки-сотни пользователей в день, а не тысячи одновременно;
- у вас нет домена или не хочется с ним возиться ради одного бота;
- бот запускается на слабом VPS или даже временно на локальной машине;
- вы на этапе разработки и часто перезапускаете процесс.
Секундная-другая задержка на polling для чат-бота поддержки, личного ассистента или бота для небольшого сообщества практически никогда не заметна пользователю — это тот случай, когда "медленнее" не значит "плохо".
Webhook стоит настраивать, если:
- бот обрабатывает сотни сообщений в минуту и заметна нагрузка от постоянного опроса;
- важна минимальная задержка (торговые уведомления, интеграция с колл-центром, боты реального времени);
- бот работает в связке с другими веб-сервисами на том же домене — прокси и SSL уже настроены;
- вы масштабируете бота на несколько воркеров за балансировщиком.
Честно: для подавляющего большинства небольших и средних ботов — магазин с уведомлениями, бот поддержки, личный помощник, бот для сообщества на несколько тысяч участников — polling полностью достаточен, а иногда даже предпочтительнее из-за простоты эксплуатации. Webhook даёт выигрыш там, где счёт идёт на сотни сообщений в секунду или где задержка в 1–2 секунды действительно критична для сценария использования, а не потому что "так правильнее".
Типичные проблемы и как их избежать
- Два процесса на одном токене (polling). Убедитесь при деплое, что старый процесс гарантированно остановлен (
systemctl restart, а не запуск нового поверх старого) — иначе получите409 Conflictи дублирующиеся ответы. - Забытый
set_webhookпосле переезда на новый сервер. Если IP или домен бота сменился, а старый webhook остался зарегистрирован на прежний адрес, Telegram будет слать запросы в никуда. ПроверяйтеgetWebhookInfoпосле любого переноса. - Самоподписанный сертификат без явной передачи. Webhook с невалидным SSL просто не будет получать обновления — Telegram тихо перестаёт присылать запросы после нескольких неудачных попыток. Используйте нормальный сертификат Let's Encrypt, а не самоподписанный.
- Webhook и polling одновременно. Это несовместимые режимы — если у бота активен webhook, а вы параллельно вызываете
getUpdates, начнутся конфликты. Перед переходом на polling обязательно снимите webhook:bot.deleteWebhook(). - Нет автозапуска после перезагрузки сервера. И для polling, и для webhook процесс бота должен быть под systemd или Docker с
restart: always— иначе после планового ребута VPS или обновления пакетов бот просто замолчит, пока кто-то не заметит и не перезапустит вручную. - Недостаточно памяти под несколько инстансов. Если планируете webhook с несколькими воркерами под нагрузкой, заранее прикиньте, сколько ОЗУ реально нужно — ориентиры для типичных ботов разобраны в статье сколько RAM нужно для Telegram-бота.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли одному боту сначала работать на polling, а потом перейти на webhook?
Да, это обычная практика: на старте и в разработке используют polling, а при росте нагрузки переключаются на webhook. Перед переключением обязательно вызовите deleteWebhook() или set_webhook() — режимы не работают параллельно.
Нужен ли отдельный домен именно под бота?
Нет, подойдёт любой поддомен основного сайта (bot.example.com) с отдельным location в nginx — заводить отдельный домен не обязательно.
Что будет, если сервер с webhook ляжет на несколько минут?
Telegram делает несколько повторных попыток доставки, но не бесконечно — при систематических ошибках он приостанавливает отправку обновлений на этот webhook, и часть сообщений может быть потеряна. Polling в этом смысле "живучее": бот просто получит накопленные обновления, как только снова поднимется.
Можно ли тестировать webhook локально, на своём компьютере?
Напрямую — нет, Telegram должен достучаться до публичного HTTPS-адреса. Для локальной отладки используют туннели (ngrok и аналоги), но для боевого бота это решение не подходит — держите webhook только на сервере с постоянным адресом.
Влияет ли выбор способа на стоимость аренды сервера?
Напрямую нет — оба варианта работают на самом скромном VPS. Polling создаёт небольшой постоянный фоновый трафик, webhook требует открытого порта 443 и работающего SSL, но по ресурсам процессора и памяти разница для типичного бота минимальна.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →