Как запустить Telegram бота на сервере

Polling или webhook, где взять токен и как его защитить, как запускать бота через systemd, pm2 или Docker и что делать при сбоях.

4 мин чтенияОпубликовано 1 октября 2026 г.

Содержание8
  1. Коротко
  2. Polling или webhook
  3. Токен и переменные окружения
  4. Запуск как службы
  5. Webhook и HTTPS
  6. Проверка и сбои
  7. Безопасность
  8. Если не получилось

Коротко

  • Обновления боту приходят двумя способами: polling (бот сам спрашивает Telegram) и webhook (Telegram сам присылает их на ваш HTTPS-адрес). Без особых причин начинайте с polling.
  • Токен из BotFather работает как пароль от бота. Храните его в переменных окружения, а не в коде и не в git.
  • Запускайте бота как службу (systemd, pm2 или Docker) с автоматическим перезапуском.
  • Если токен утёк, выполните /revoke в BotFather.

Polling или webhook

Polling (метод getUpdates): бот регулярно запрашивает новые сообщения. Домен и HTTPS не нужны, работает даже за NAT, отлаживать проще. С одним токеном должен работать только один экземпляр бота.

Webhook: Telegram отправляет каждое обновление на ваш адрес. Нужны домен с действующим HTTPS-сертификатом и один из портов: 443, 80, 88 или 8443. Если домен проксируется Cloudflare, используйте 443 или 8443. Подходит для бессерверных окружений и нескольких экземпляров за балансировщиком.

Одновременно использовать оба способа нельзя: пока установлен webhook, getUpdates не работает. В руководстве Telegram отдельно сказано, что использовать getUpdates вполне нормально.

Токен и переменные окружения

В @BotFather выполните /newbot, задайте имя и username (он заканчивается на bot). BotFather пришлёт токен, который даёт полный контроль над ботом. Не публикуйте его в репозитории, на скриншотах и в логах.

Положите значения в файл .env рядом с ботом, задайте права chmod 600 .env и добавьте файл в .gitignore.

BOT_TOKEN=PASTE_TOKEN_HERE
ADMIN_IDS=123456789
WEBHOOK_SECRET=PASTE_RANDOM_STRING

Запуск как службы

Создайте для бота отдельного пользователя без sudo и положите код и .env в его каталог (ниже это /home/mybot/app):

sudo adduser --disabled-password --gecos "" mybot

Затем создайте файл /etc/systemd/system/mybot.service:

[Unit]
Description=Telegram bot
After=network-online.target
Wants=network-online.target

[Service]
User=mybot
WorkingDirectory=/home/mybot/app
EnvironmentFile=/home/mybot/app/.env
ExecStart=/home/mybot/app/.venv/bin/python main.py
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now mybot
sudo journalctl -u mybot -f

Для Node.js в ExecStart нужен абсолютный путь к node, его покажет which node. Вариант на pm2: pm2 start index.js --name mybot, затем pm2 startup и pm2 save. Учтите, что pm2 сам .env не читает: бот должен загружать файл, например библиотекой dotenv. Вариант на Docker: docker run -d --name mybot --restart unless-stopped --env-file .env mybot-image.

Webhook и HTTPS

Поставьте перед ботом Caddy или nginx, который проксирует запросы на локальный порт (пример в статье как развернуть сайт на VPS), и зарегистрируйте адрес. Чтобы токен не попал в историю команд, сначала загрузите значения из .env в оболочку (от имени пользователя, которому принадлежит файл):

set -a; source .env; set +a
curl "https://api.telegram.org/bot${BOT_TOKEN}/setWebhook" \
  -d "url=https://bot.example.com/webhook" \
  -d "secret_token=${WEBHOOK_SECRET}"
curl "https://api.telegram.org/bot${BOT_TOKEN}/getWebhookInfo"

В secret_token допустимы буквы, цифры, _ и -. Telegram передаёт его в заголовке X-Telegram-Bot-Api-Secret-Token, и бот должен его проверять. Сертификату нужна полная цепочка (fullchain). Метод getWebhookInfo показывает last_error_message и pending_update_count. Про сертификаты читайте в статье SSL сертификат и HTTPS.

Проверка и сбои

  • Добавьте адрес /health, который отвечает кодом 200, и проверяйте его внешним мониторингом по публичному адресу либо локальным скриптом, который пишет вам при сбое. Для бота без HTTP проверяйте systemctl is-active mybot.
  • Restart=always перезапускает процесс, а причину ищите в sudo journalctl -u mybot -n 100.
  • Перехватывайте исключения в обработчиках. Если бот падает на одном сообщении, после перезапуска Telegram может отдать его снова, и бот зациклится.
  • При ответе 429 соблюдайте паузу retry_after.

Безопасность

  • Админов определяйте по числовому ID и проверяйте from.id перед командами. Username меняется, ID нет.
  • Не пишите в логи токен, полные адреса запросов к API (в них есть токен) и личные данные пользователей.
  • Запускайте бота от отдельного пользователя без sudo, а не от root и не от своего администратора.
  • Docker публикует порты в обход ufw, поэтому порт webhook открывайте только на localhost: -p 127.0.0.1:3000:3000.
  • Если токен утёк, выполните /revoke у BotFather, обновите значение в .env и перезапустите бота. Старый токен перестанет работать.

Если не получилось

  1. Ошибка 401 Unauthorized: токен неверный или отозван.
  2. Ошибка 409 Conflict: запущено два экземпляра с polling либо установлен webhook. Оставьте один экземпляр или вызовите deleteWebhook.
  3. Webhook не доходит: смотрите last_error_message в getWebhookInfo и проверьте порт, полную цепочку сертификата, DNS, файрвол и правила защиты в Cloudflare.
  4. Бот молчит в группе: включён privacy mode. Отключите его командой /setprivacy у BotFather, затем удалите бота из группы и добавьте снова, иначе изменение не вступит в силу. Можно и сделать бота админом.
  5. Бот не стартует: прочитайте sudo journalctl -u mybot -n 100, проверьте путь в ExecStart и то, что код и .env лежат в каталоге пользователя mybot.
  6. С сервера нет доступа к Telegram: выполните curl -I https://api.telegram.org. Любой ответ значит, что связь есть, а зависание или ошибка соединения указывает на проблему. Доступность зависит от страны и провайдера.

Если что-то непонятно, напишите мне в Telegram: @lztcoder

Читайте также