Telegram-бот на VPS: long polling или webhook, что выбрать
Как запустить Telegram-бота на VPS: сравнение getUpdates и webhook, пример на python-telegram-bot и защита токена. Что делать, если бот не получает сообщения.
Содержание 18
- Коротко
- Два способа получать обновления
- Что выбрать
- Шаги
- Переход с webhook на polling
- Примеры
- Симптом → причина → решение
- Пример: проверка webhook одной командой
- Пример: ответ с клавиатурой
- Чек-лист перед запуском
- Что делать, если бот начал падать
- Частые ошибки
- Итог
- Вопросы и ответы
- Можно ли запускать Telegram-бота на домашнем компьютере?
- Long polling нагружает сервер?
- Нужен ли домен для long polling?
- Что такое privacy mode?
Telegram-бот на VPS решает ту же задачу, что и Discord-бот: работает, пока вы спите. Разница в способе получения сообщений. Бот может сам спрашивать Telegram о новых обновлениях или ждать, пока Telegram пришлёт их на ваш адрес. От выбора зависит, нужен ли вам домен, сертификат и открытый порт.
Коротко
Для большинства ботов выбирайте long polling (getUpdates): бот сам запрашивает обновления, домен и сертификат не нужны. Webhook (setWebhook) имеет смысл, когда нужна мгновенная доставка и у вас есть HTTPS на порту 443, 80, 88 или 8443. Токен берите у @BotFather, храните в файле окружения и запускайте службой systemd.
Два способа получать обновления
У бота есть два взаимоисключающих способа получать сообщения. Первый — long polling через метод getUpdates: бот держит исходящий запрос к Telegram, и тот отдаёт новые сообщения, как только они появились. Второй — webhook через setWebhook: Telegram отправляет каждое обновление HTTPS-запросом POST на адрес вашего сервера.
Официальная документация Bot API прямо указывает: пока webhook установлен, getUpdates не работает. Поэтому переключаться между ними нужно аккуратно, сначала отключив старый способ.
Для webhook Telegram требует HTTPS и поддерживает порты 443, 80, 88 и 8443. На VPS это означает домен, сертификат Let’s Encrypt и настроенный nginx или другой веб-сервер. Подробно эта схема разобрана в статье Сайт на VPS с nginx и Let’s Encrypt.
Что выбрать
Long polling подходит, если бот отвечает на команды и не обрабатывает тысячи сообщений в секунду. Он проще в настройке, работает за NAT и не требует домена. Минус — небольшая задержка и постоянный исходящий запрос, но для обычного бота это незаметно.
Webhook выбирайте, если у вас уже есть HTTPS-сайт, бот принимает много обновлений или вы строите сервис на несколько серверов. В этом случае Telegram не держит запросы к вашей машине, а присылает данные сам.
Шаги
- Создайте бота у @BotFather: команда
/newbot, затем имя и username. BotFather выдаст токен. Сохраните его, но не публикуйте. - Подготовьте VPS: Ubuntu 24.04, обновления системы, ключи SSH вместо пароля и пользователь без root для бота.
- Установите окружение и библиотеку python-telegram-bot версии 21:
sudo apt update && sudo apt install -y python3-venv
sudo useradd -r -s /usr/sbin/nologin tgbot
sudo mkdir -p /opt/tg-bot && sudo chown tgbot:tgbot /opt/tg-bot
cd /opt/tg-bot
python3 -m venv venv
./venv/bin/pip install "python-telegram-bot>=21,<22"- Напишите
bot.py. Токен берётся из окружения:
import os
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text("Бот работает.")
def main():
app = Application.builder().token(os.environ["BOT_TOKEN"]).build()
app.add_handler(CommandHandler("start", start))
app.run_polling(allowed_updates=Update.ALL_TYPES)
if __name__ == "__main__":
main()- Создайте файл
/opt/tg-bot/.envи положите в него токен (без кавычек):
BOT_TOKEN=вставьте-токен-из-BotFathersudo chown tgbot:tgbot /opt/tg-bot/.env
sudo chmod 600 /opt/tg-bot/.env- Опишите службу
/etc/systemd/system/tg-bot.service:
[Unit]
Description=Telegram bot
After=network-online.target
Wants=network-online.target
[Service]
User=tgbot
WorkingDirectory=/opt/tg-bot
EnvironmentFile=/opt/tg-bot/.env
ExecStart=/opt/tg-bot/venv/bin/python bot.py
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target- Запустите и проверьте журнал:
sudo systemctl daemon-reload
sudo systemctl enable --now tg-bot
sudo journalctl -u tg-bot -f- Отправьте боту команду
/startи проверьте ответ.
Переход с webhook на polling
Если бот раньше работал через webhook, а теперь вы переходите на long polling, сначала отключите webhook. Метод deleteWebhook делает это одним запросом к Bot API. Иначе бот будет получать ошибку при каждом getUpdates, а сообщения будут уходить на старый адрес.
Проверить состояние можно методом getWebhookInfo: если в ответе есть непустой url, webhook ещё активен.
Примеры
Команда «/start» в группе. В группе при включённом privacy mode (так по умолчанию) бот видит только команды, ответы на свои сообщения и упоминания. Чтобы он читал все сообщения группы, отключите privacy mode в BotFather командой /setprivacy или сделайте бота администратором группы.
Перезапуск после ошибки. Если процесс упал из-за необработанного исключения, Restart=always поднимает его через пять секунд. Кратковременные сетевые сбои при long polling библиотека в основном переживает сама, но не рассчитывайте на это и смотрите журнал.
Утёкший токен. Команда /revoke в BotFather выпускает новый токен. Старый перестаёт работать, а бот нужно обновить в .env и перезапустить службу.
Симптом → причина → решение
| Симптом | Частая причина | Что сделать |
|---|---|---|
Бот не отвечает на /start |
Служба не запущена или упала | sudo systemctl status tg-bot, затем журнал |
Conflict: terminated by other getUpdates request |
Запущены два экземпляра с одним токеном | Остановите лишний процесс: ps aux | grep bot.py |
InvalidToken или 401 Unauthorized в журнале |
Токен неверный или отозван | Получите новый токен у BotFather (/token или /revoke) и обновите .env |
| Сообщения не приходят после webhook | Webhook всё ещё активен | Вызовите deleteWebhook, затем перезапустите бота |
| Бот не получает обновления, в журнале таймауты | С VPS нет доступа к api.telegram.org |
Проверьте curl -sS -m 10 https://api.telegram.org, при необходимости смените локацию или сеть |
| Ответы приходят с задержкой | Тяжёлый код в обработчике | Вынесите долгие операции в фоновую задачу |
Пример: проверка webhook одной командой
Если вы не уверены, работает ли webhook, проверьте его через getWebhookInfo. Токен подставляется из файла окружения, поэтому в историю команд попадает только имя переменной. Выполняйте команду от root или от пользователя, который может читать .env.
source /opt/tg-bot/.env
curl -s "https://api.telegram.org/bot${BOT_TOKEN}/getWebhookInfo"В ответе поле url должно быть пустым при long polling. Не публикуйте вывод целиком: он безопасен, но привычка не светить URL с токеном (.../bot<токен>/...) в чатах и тикетах спасает от утечек.
Пример: ответ с клавиатурой
Команда /menu показывает кнопки, а нажатие обрабатывается отдельным обработчиком. Так бот выглядит живее, чем с набором текстовых команд:
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import CallbackQueryHandler
async def menu(update, context):
keyboard = [[InlineKeyboardButton("Статус", callback_data="status")]]
await update.message.reply_text("Выберите действие:", reply_markup=InlineKeyboardMarkup(keyboard))
async def on_button(update, context):
query = update.callback_query
await query.answer()
await query.edit_message_text("Бот работает.")
# в main():
# app.add_handler(CommandHandler("menu", menu))
# app.add_handler(CallbackQueryHandler(on_button))Кнопки с callback_data обрабатываются через CallbackQueryHandler. Не забывайте вызывать query.answer(), иначе у пользователя будет крутиться индикатор ожидания.
Чек-лист перед запуском
Перед тем как пустить бота к пользователям, проверьте:
- Токен хранится в
.envс правами 600, а в коде вызывается черезos.environ. - Служба стартует после
rebootи перезапускается после падения. - Бот отвечает на
/startи на одну команду с ошибкой, например на неверный ввод. Ошибка не должна ронять процесс. - В журнале нет исключений при обычной работе:
journalctl -u tg-bot --since "1 hour ago". - Команда
/revokeв BotFather известна тем, кто за ботом следит: она нужна при утечке. - Если используется webhook, сертификат действителен, а
getWebhookInfoне содержит ошибок в полеlast_error_message.
Что делать, если бот начал падать
Сначала посмотрите журнал за последний час. Если ошибка сетевая, например таймаут до Telegram, это временная проблема, и служба сама повторит запрос. Если исключение в вашем коде, поправьте обработчик и перезапустите службу. Если бот падает раз в несколько минут без причины, проверьте память командой free -h: процесс мог не хватать памяти и его остановило ядро.
Частые ошибки
- Бот молчит, хотя служба работает. Смотрите журнал:
Conflict: terminated by other getUpdates requestозначает, что запущены два экземпляра бота с одним токеном. - Webhook включён, а polling не работает. Вызовите
deleteWebhook, затем перезапустите бота. - Токен в коде или в репозитории. Такой токен надо отзывать через
/revoke. Держите его в.envс правами 600. - Нет доступа к api.telegram.org с VPS. Бот сам обращается к Telegram, поэтому доступность API проверяйте именно с сервера:
curl -sS -m 10 https://api.telegram.org. Если запрос не проходит, смотрите сеть, DNS и локацию сервера. Доступность самого мессенджера для ваших пользователей от этого не зависит. - Webhook без HTTPS. Telegram принимает webhook только по HTTPS на портах 443, 80, 88 или 8443. Для теста используйте long polling.
- Служба падает при старте. Проверьте, что путь в
ExecStartуказывает на Python внутри venv, а.envчитается пользователем tgbot.
Итог
Telegram-бот на VPS проще всего запустить через long polling: отдельный пользователь, venv, файл .env и служба systemd с Restart=always. Webhook добавляет домен и HTTPS, зато даёт мгновенную доставку. Выбирайте по задаче, а не по моде, и не забывайте про deleteWebhook, если меняете способ получения обновлений.
Вопросы и ответы
Можно ли запускать Telegram-бота на домашнем компьютере?
Можно, но он будет работать только при включённой машине и стабильном интернете. VPS решает это.
Long polling нагружает сервер?
Нет, для обычного бота нагрузка минимальна. Long polling держит один исходящий запрос.
Нужен ли домен для long polling?
Нет. Домен и сертификат нужны только для webhook.
Что такое privacy mode?
Это настройка, из-за которой бот в группе видит только команды и упоминания. Меняется в BotFather командой /setprivacy.
Сервер под игры за пару минут — egnetwork.ru
Читать далее
Вся рубрика →Мониторинг ресурсов VPS: htop, iotop и vnstat
Как за несколько минут понять, что тормозит VPS: процессор, память, диск или сеть. Команды htop, iotop, vnstat, free и df с примерами вывода и таблицей симптомов.
Трафик VPS: как посчитать объём и не получить сюрприз в конце месяца
Что считается трафиком, как перевести скорость канала в терабайты за месяц, как читать счётчик входящего и исходящего трафика в кабинете EGN и что делать, если лимит закончился.
IPv6 на VPS: как пользоваться префиксом /64
Что значит /64, как проверить адрес на сервере, назначить дополнительные адреса, настроить ufw для IPv6 и не выпасть из сети. Примеры команд и типичные ошибки.