Вы написали 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 и реагирует на сообщения, так что сервер в основном ждёт:
- Nano за $3 (1 vCPU / 1 ГБ) — хватает большинству ботов, даже довольно болтливым.
- Micro за $5 (2 vCPU / 2 ГБ) — когда бот держит базу (SQLite/Postgres), работает с медиа или обслуживает много пользователей.
- Выше — только если бот сам делает реальную работу: обработка изображений, локальная модель, тяжёлая логика на каждое сообщение.
Регистрация по одному email, оплата в USDC или USDT на Base или Ethereum — без карты, без документов. Карта тоже работает, но у онрампа минимум ~$27, поэтому для тарифа за $3 удобнее один раз пополнить баланс и списывать продления с него. Только CPU, один дата-центр в Германии — для бота неважно, но стоит знать, если нужен был GPU или конкретный регион.
Честный итог
Telegram-бот — одна из самых дешёвых вещей для самостоятельного хостинга: сервер за $3, юнит systemd и polling дают бота, который онлайн через падения и перезагрузки без няньки. За webhook и тариф побольше беритесь, только когда к этому реально принуждает масштаб, — а не потому что туториал сказал, будто webhook «лучше». Возьмите маленький сервер, держите токен в env-файле, доверьте аптайм systemd и — прежде всего — прогоните чек-лист безопасности нового VPS, чтобы сам сервер был закрыт.