Telegram-бот на VPS: чтобы работал круглые сутки
Бот на ноутбуке умирает каждый раз, когда закрывается крышка. На VPS он работает без перерывов и сам поднимается после сбоя или перезагрузки. Ниже — минимальный бот на Python, служба systemd, которая держит его живым, и логи, которые реально удобно читать.
Что понадобится
- VPS с Ubuntu 24.04 или Debian 12. Обычному боту с запасом хватит самого младшего тарифа: у Pulse 2 vCPU и 2 ГБ памяти за $10 в месяц, а бот на aiogram занимает из этого 60–100 МБ — останется место ещё для нескольких ботов или небольшой базы.
- Токен бота от @BotFather.
- Доступ к серверу по SSH (см. Подключение по SSH).
С тяжёлыми ботами история другая. Если ваш режет видео через ffmpeg, гоняет локальную ML-модель или держит большую базу — начинайте с Pulse или Drive.
1. Отдельный пользователь и виртуальное окружение
Не запускайте бота от root. Лишний пользователь ничего не стоит, зато если в коде бота найдётся дыра, ущерб будет ограничен.
apt update && apt install -y python3-venv
useradd -r -m -d /opt/bot -s /usr/sbin/nologin bot
sudo -u bot python3 -m venv /opt/bot/venv
sudo -u bot /opt/bot/venv/bin/pip install aiogram
2. Сам бот
/opt/bot/bot.py отвечает на /start и повторяет сообщения. Обработчики замените своей логикой.
import asyncio, os
from aiogram import Bot, Dispatcher
from aiogram.filters import CommandStart
from aiogram.types import Message
dp = Dispatcher()
@dp.message(CommandStart())
async def start(m: Message):
await m.answer("Привет! Я работаю на VPS.")
@dp.message()
async def echo(m: Message):
await m.answer(m.text or "…")
async def main():
await dp.start_polling(Bot(os.environ["BOT_TOKEN"]))
asyncio.run(main())
Токен держите не в коде, а в файле, который может читать только пользователь бота:
echo 'BOT_TOKEN=123456:ABC...' > /opt/bot/.env
chown bot:bot /opt/bot/.env /opt/bot/bot.py && chmod 600 /opt/bot/.env
3. systemd следит, чтобы бот работал
/etc/systemd/system/bot.service:
[Unit]
Description=Telegram bot
After=network-online.target
Wants=network-online.target
[Service]
User=bot
WorkingDirectory=/opt/bot
EnvironmentFile=/opt/bot/.env
ExecStart=/opt/bot/venv/bin/python bot.py
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now bot
systemctl status bot
Restart=always поднимает бота через пять секунд после любого падения, а enable запускает его после перезагрузки сервера.
4. Логи и обновления
journalctl -u bot -f # лог в реальном времени
journalctl -u bot --since today # всё за сегодня
Новая версия — скопировать файл и выполнить systemctl restart bot. Если код лежит в git, большинству ботов за всю жизнь не понадобится ничего сложнее git pull в /opt/bot и того же перезапуска.
Polling или webhook?
В примере polling: бот сам спрашивает у Telegram новые сообщения. Ему не нужны домен, сертификат и открытые порты, поэтому я бы начинал с него. Webhook имеет смысл, когда у бота много трафика или он и так живёт рядом с веб-приложением на HTTPS. Тогда Telegram сам присылает обновления на ваш адрес, но понадобятся домен и сертификат (хватит nginx и Let's Encrypt).
Одна честная оговорка: при polling бот держит долгое соединение с Telegram. Это нормально и почти не тратит трафик, а он на всех VPS dedisrv и так без ограничений.