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 і так без обмежень.