Как запустить Telegram-бота на VPS: деплой, автозапуск и вебхуки

Написать бота — половина дела. Вторая половина начинается, когда его нужно вынести с ноутбука туда, где он будет отвечать круглосуточно: без падений после обрыва связи, с логами, автоматическим перезапуском и понятным способом выкатывать обновления.
Это руководство — именно про вторую половину. Оно подойдёт для бота на любом языке, но все примеры даны для Python, как самого частого случая.
Почему боту нужен именно сервер
Telegram не хранит ваш код: он лишь передаёт сообщения программе, которая должна быть запущена. Пока она работает на домашнем компьютере, бот умирает вместе с перезагрузкой, спящим режимом или сменой Wi-Fi.
Бесплатные площадки для запуска кода эту задачу решают наполовину: они усыпляют процесс при простое, ограничивают время работы и не дают нормально хранить файлы и базу. VPS свободен от этих ограничений: это ваша машина, которая просто не выключается.
Шаг 1. Взять сервер
В панели NodexGo нажмите «Создать сервер». Дальше по шагам: локация — рядом с каждой показан ваш реальный пинг до неё; тариф и образ системы; имя сервера; период оплаты 1, 3, 6 или 12 месяцев.
По ресурсам: боту на polling хватает младшего тарифа с 1 vCPU и 2 ГБ памяти. Запас нужен, только если бот обрабатывает картинки, ведёт большую базу или рассылает сообщения десяткам тысяч пользователей. Образ берите Ubuntu 24.04 — команды ниже написаны под него.
Через минуту после оплаты сервер готов: IP-адрес и пароль root придут в панель и на почту.
Круглосуточный сервер под бота — от 1 vCPU и 2 ГБ, готов через минуту.
Создать серверШаг 2. Базовая настройка сервера
Подключаемся и обновляем систему:
ssh root@IP-адрес-сервера
apt update && apt upgrade -yСоздаём отдельного пользователя: запускать бота от root — плохая привычка, любая ошибка в коде получает права на всю машину.
adduser bot
usermod -aG sudo botЗакрываем всё лишнее файрволом. Разрешаем SSH обязательно ДО включения ufw, иначе отрежете себе доступ:
ufw allow OpenSSH
ufw enableСтавим Python и git:
apt install -y python3 python3-venv python3-pip gitШаг 3. Перенести код бота на сервер
Самый удобный способ — через git: обновление потом будет занимать одну команду. Заходим под пользователем bot и клонируем репозиторий:
su - bot
git clone https://github.com/ваш-аккаунт/ваш-бот.git ~/bot
cd ~/botЕсли репозитория нет, файлы можно просто скопировать со своего компьютера — команда выполняется в вашем локальном терминале, а не на сервере:
scp -r ./mybot bot@IP-адрес-сервера:~/botСтавим зависимости в виртуальное окружение:
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txtШаг 4. Секреты — в отдельный файл
Токен бота, пароль базы и ключи не должны лежать в коде: их место в файле .env, который не попадает в репозиторий.
nano ~/bot/.envBOT_TOKEN=ваш-токен-от-BotFather
ADMIN_ID=ваш-числовой-id
DATABASE_URL=sqlite:///bot.dbchmod 600 ~/bot/.envПроверьте, что .env указан в .gitignore — иначе при следующем коммите токен уедет в открытый репозиторий.
Шаг 5. Автозапуск через systemd
systemd — штатный способ держать программу живой: он стартует бота при загрузке сервера и перезапускает его после любого падения. Выходим в root и создаём службу:
exit
nano /etc/systemd/system/bot.service[Unit]
Description=Telegram bot
After=network.target
[Service]
Type=simple
User=bot
WorkingDirectory=/home/bot/bot
EnvironmentFile=/home/bot/bot/.env
ExecStart=/home/bot/bot/venv/bin/python /home/bot/bot/main.py
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.targetВключаем и запускаем:
systemctl daemon-reload
systemctl enable --now bot
systemctl status botПроверить, что бот действительно пережил бы перезагрузку сервера, можно честным способом:
rebootЧерез полминуты подключитесь снова и убедитесь, что служба поднялась сама.
Шаг 6. Логи и обновление кода
Весь вывод бота попадает в системный журнал. Живой просмотр и последние сто строк:
journalctl -u bot -f
journalctl -u bot -n 100 --no-pagerВыкатка новой версии сводится к трём командам:
su - bot -c 'cd ~/bot && git pull && venv/bin/pip install -r requirements.txt'
systemctl restart botЖурнал со временем разрастается — ограничьте его, чтобы он не съел диск:
journalctl --vacuum-size=200MPolling или вебхук
Polling — бот сам раз в секунду спрашивает у Telegram, есть ли новости. Это проще всего: работает сразу, не требует домена и сертификата. Для большинства ботов этого достаточно навсегда.
Вебхук — наоборот: Telegram сам присылает обновления на ваш адрес. Он экономнее и отвечает быстрее, но требует домен, HTTPS-сертификат и открытый 443 порт. Имеет смысл, когда сообщений действительно много.
Если выбрали вебхук, поставьте перед ботом обратный прокси с автоматическим сертификатом — проще всего это делает Caddy:
apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
apt update && apt install -y caddyНаправьте A-запись домена на IP сервера и опишите проксирование двумя строками в /etc/caddy/Caddyfile:
bot.example.com {
reverse_proxy 127.0.0.1:8080
}ufw allow 80/tcp
ufw allow 443/tcp
systemctl reload caddyСертификат Caddy выпустит и будет продлевать сам. Адрес вебхука в коде бота — https://bot.example.com/ваш-секретный-путь.
Резервные копии
Если бот хранит данные, их нужно копировать отдельно: сервер — не бэкап. Простейший вариант для SQLite — ежедневная копия по расписанию. Открываем планировщик:
crontab -eИ добавляем строку — копия каждый день в 4 утра с датой в имени файла:
0 4 * * * cp /home/bot/bot/bot.db /home/bot/backup-$(date +\%F).dbДля PostgreSQL вместо копирования файла используйте pg_dump. Хотя бы раз в месяц проверяйте, что копия действительно открывается — бэкап, который ни разу не восстанавливали, бэкапом не считается.
Частые проблемы
Ошибка Conflict: terminated by other getUpdates request — бот запущен дважды с одним токеном. Обычно вторая копия осталась на домашнем компьютере: остановите её.
Служба постоянно перезапускается — смотрите journalctl, почти всегда это неверный путь в ExecStart или незагруженный .env.
Бот работает, но со временем начинает тормозить — проверьте память командой free -h, часто дело в утечке или в разросшемся журнале. Если ресурсов правда мало, в карточке сервера есть кнопка «Увеличить мощности»: тариф меняется на старший, диск и IP сохраняются, ничего переносить не нужно.
Совсем нет доступа к серверу — в панели у каждого сервера есть web-консоль VNC, она работает в обход SSH и сети, а рядом кнопки «Сменить пароль root» и «Переустановить ОС».
Коротко
Арендовать VPS, создать отдельного пользователя, перенести код через git, вынести секреты в .env, повесить бота на systemd с Restart=always и следить за ним через journalctl. Дальше обновление — это git pull и перезапуск службы, а бот отвечает даже когда ваш компьютер выключен.
Выберите конфигурацию под своего бота — перейти на старший тариф можно в один клик.
Посмотреть тарифы