EQVPS

Telegram-бот 24/7 на VPS: aiogram, systemd, polling против webhook

Jul 4, 2026 · 5 min read · EQVPS Team

Вы написали Telegram-бота на aiogram, погоняли локально — работает. Теперь ему нужно жить там, где не засыпают при закрытии ноутбука. Небольшой VPS — естественный дом, но между python bot.py в SSH-сессии и ботом, который реально держится через падения, перезагрузки и обрывы связи, есть пропасть.

Это боевая версия: virtualenv, токен вне кода, systemd-сервис, воскрешающий бота сам, и трезвый ответ на вопрос, который рано или поздно задаёт каждый — polling или webhook?

Почему не оставить на ноутбуке

Боту нужно устойчивое исходящее соединение с Telegram. Ноутбук засыпает, перезагружается ради обновлений, прыгает между сетями — каждый раз бот отваливается, и пользователи упираются в тишину. VPS держит это соединение круглосуточно. В этом весь смысл переезда с личной машины — по той же причине и Discord-боту место на сервере.

Если нужен самый быстрый путь «просто подними бота» с минимальным примером — это разобрано в гайде по хостингу Telegram-бота. Здесь — на уровень глубже: aiogram, безопасный токен и понимание, когда масштабироваться.

Бот в virtualenv

Заходим по SSH и держим бота изолированным в своём venv — не ставьте пакеты системно, потом замучаетесь с обновлениями и чисткой:

sudo apt update && sudo apt install -y python3-venv
mkdir ~/tgbot && cd ~/tgbot
python3 -m venv venv && source venv/bin/activate
pip install -U aiogram

Минимальный бот на aiogram 3, который читает токен из окружения, а не из зашитой строки:

# bot.py
import asyncio, logging, os
from aiogram import Bot, Dispatcher
from aiogram.types import Message
from aiogram.filters import CommandStart

logging.basicConfig(level=logging.INFO)
dp = Dispatcher()

@dp.message(CommandStart())
async def start(m: Message):
    await m.answer("Живой, работаю на VPS.")

async def main():
    bot = Bot(os.environ["BOT_TOKEN"])
    await dp.start_polling(bot)

if __name__ == "__main__":
    asyncio.run(main())

Токен — вне кода

Никогда не вставляйте токен от BotFather прямо в bot.py: один пуш в публичный репозиторий — и он утёк. Положите его в env-файл, читаемый только root:

sudo tee /etc/tgbot.env >/dev/null <<'EOF'
BOT_TOKEN=123456:ваш-токен-от-botfather
EOF
sudo chmod 600 /etc/tgbot.env

Утёкший токен чинится одним /revoke в BotFather — а вот утечка чего угодно ещё на общей машине куда хуже. Отдельный VPS под бота, честно говоря, безопаснее для токена, чем ваш рабочий ноутбук: если что-то утечёт, вы меняете один токен, а не всю свою систему.

То, что держит бота живым: systemd

Именно это отделяет бота, который «запускается», от бота, который «держится». Создаём сервис:

# /etc/systemd/system/tgbot.service
[Unit]
Description=Telegram bot (aiogram)
After=network-online.target
Wants=network-online.target

[Service]
User=botuser
WorkingDirectory=/home/botuser/tgbot
EnvironmentFile=/etc/tgbot.env
ExecStart=/home/botuser/tgbot/venv/bin/python bot.py
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

Запускайте от обычного пользователя (botuser выше), не от root — если бота когда-нибудь скомпрометируют, пусть он будет заперт в песочнице. Дальше:

sudo systemctl daemon-reload
sudo systemctl enable --now tgbot

Restart=always с RestartSec=3 означает, что падение — кривой ответ Telegram, необработанное исключение, OOM — вернёт бота через три секунды, а не оставит лежать, пока вы не заметите. Смотрим логи в реальном времени:

journalctl -u tgbot -f

Вот и вся настройка логирования. Никаких файлов логов для ротации, никаких лишних инструментов — journald уже всё пишет.

Обновление без драмы с даунтаймом

Когда меняете код или обновляете aiogram:

cd ~/tgbot && source venv/bin/activate
pip install -U aiogram          # если обновляете библиотеку
sudo systemctl restart tgbot
journalctl -u tgbot -n 30 --no-pager   # убедиться, что поднялся чисто

Рестарт мигает ботом на секунду-две. Для polling-бота это невидимо пользователям — Telegram копит апдейты и отдаёт их, как только бот переподключится.

Polling против webhook — честная версия

Это решение обычно переусложняют. Вот как есть:

Polling (start_polling, как в коде выше) — бот сам спрашивает Telegram «есть новое?» по долгоживущему соединению. Ему не нужно ничего, кроме исходящего интернета — ни домена, ни TLS, ни открытых входящих портов. Прекрасно работает за NAT. Для подавляющего большинства ботов это правильный выбор, и на этом можно остановиться.

Webhook — Telegram сам шлёт апдейты вам, а значит нужно выставить наружу публичный HTTPS-эндпоинт. Для этого требуется домен и доступный входящий порт — то есть либо выделенный публичный IP, либо reverse-proxy впереди. Больше настройки, больше того, что может сломаться. Выигрыш — меньшая задержка и меньше накладных расходов на большом масштабе: тысячи одновременных пользователей, высокий поток апдейтов.

Практическое правило: начинайте с polling на NAT-тарифе. Переходите на webhook, только когда реально переросли polling — и вот тогда выделенный IP оправдывает себя, потому что вам нужен этот входящий HTTPS-эндпоинт.

Сколько это стоит

Polling-бот лёгкий. Он висит на long-poll Telegram и реагирует на сообщения, так что сервер в основном ждёт:

Регистрация по одному email, оплата в USDC или USDT на Base или Ethereum — без карты, без документов. Карта тоже работает, но у онрампа минимум ~$27, поэтому для тарифа за $3 удобнее один раз пополнить баланс и списывать продления с него. Только CPU, один дата-центр в Германии — для бота неважно, но стоит знать, если нужен был GPU или конкретный регион.

Честный итог

Telegram-бот — одна из самых дешёвых вещей для самостоятельного хостинга: сервер за $3, юнит systemd и polling дают бота, который онлайн через падения и перезагрузки без няньки. За webhook и тариф побольше беритесь, только когда к этому реально принуждает масштаб, — а не потому что туториал сказал, будто webhook «лучше». Возьмите маленький сервер, держите токен в env-файле, доверьте аптайм systemd и — прежде всего — прогоните чек-лист безопасности нового VPS, чтобы сам сервер был закрыт.

FAQ

Polling или webhook — что выбрать?

Начинайте с polling. Он работает с любого сервера, где есть исходящий интернет — без домена, без открытых портов, без TLS — и этого хватает большинству ботов. Webhook нужен только при большом масштабе (тысячи пользователей) или когда критична минимальная задержка; для него требуется публичный HTTPS-эндпоинт, а значит домен и доступный входящий порт (выделенный IP или reverse-proxy) — больше движущихся частей. Для 95% ботов правильный ответ — polling на небольшом VPS.

Нужен ли выделенный IP или домен для Telegram-бота?

Для polling — нет. Бот только исходяще стучится к Telegram, поэтому хватает NAT-тарифа с проброшенным SSH. Публичный HTTPS-эндпоинт (домен + входящий порт, то есть выделенный IP или reverse-proxy) нужен только при переходе на webhook. Большинству ботов он не нужен никогда.

Какой размер VPS нужен aiogram-боту?

Самый маленький. Polling-бот в основном ждёт ответа от long-poll Telegram, так что 1 vCPU / 1 ГБ (Nano за $3) спокойно тянет большинство ботов. Апгрейд нужен, только когда тяжёлую работу делает сам бот — база данных, обработка медиа, локальная модель — тогда берут 2 ГБ ($5) и выше.

Как оставить бота работать после выхода из SSH?

Запустить как systemd-сервис с Restart=always. Запущенный в терминале бот умирает при закрытии SSH; под systemd он переживает выход, перезапускается при падении и поднимается после ребута. Это граница между демкой и тем, на что можно положиться.

← Back to blogSee plans & pricing →