Как задеплоить Telegram-бота на VPS: systemd, Docker и webhook

За два года на фрилансе я задеплоил на VPS около полутора десятков ботов на aiogram и python-telegram-bot — от простых уведомлятелей для интернет-магазинов до воронок с оплатой и трекингом доставки. Деплой бота на VPS отличается от запуска на ноутбуке двумя вещами: сервер должен работать круглосуточно без вашего участия, а процесс — не падать после разрыва SSH-сессии или перезагрузки машины. Ниже — три рабочих способа: systemd для простых ботов, Docker для проектов с зависимостями и настройка webhook вместо long polling, когда бот обслуживает больше пары сотен пользователей в сутки.

Где размещать бота: VPS, PaaS или serverless

Перед тем как выбирать между systemd и Docker, нужно определиться с хостингом. Я перепробовал три варианта на разных проектах — и для продакшн-бота почти всегда возвращаюсь к VPS.

  • VPS (Timeweb, Selectel, Reg.ru) — от 200-400 ₽/мес, подходит для любых ботов, фоновых задач и парсеров. Минус — настройка вручную.
  • Хостинг ботов (bothost.ru) — от 99 ₽/мес, деплой из Git за минуты: домен, SSL и база данных настраиваются сами. Оплата российской картой, серверы в РФ и Европе, тест 7 дней без карты. Минус — меньше контроля, чем на голом VPS.
  • PaaS (Railway, Render) — от 5-7 $/мес, быстрый MVP и тестовый прототип. Минус — проблемы с оплатой из РФ и риск блокировки.
  • Serverless (Vercel, Cloudflare Functions) — оплата по трафику, только webhook-боты без фоновых задач. Минус — холодный старт и лимит времени выполнения.
  • Shared-хостинг — от 150 ₽, почти никогда. Нет root-доступа, процесс не держится в фоне.

VPS за 250-400 ₽ в месяц с 1 ГБ RAM спокойно тянет 3-5 ботов среднего размера, если они не гоняют тяжёлую обработку файлов или видео. Обычно я беру машину с 2 ГБ RAM и 1 vCPU — с запасом под Docker и логи.

Альтернатива для тех, кто не хочет админить: хостинг ботов с деплоем из Git — загрузили код, и бот уже работает, сервер, домен и SSL настраиваются сами. Подборка таких сервисов — в каталоге ServerScan (раздел Docker VPS).

Подготовка VPS перед деплоем бота

Первым делом — не работать под root. Создаю отдельного пользователя, обновляю систему и ставлю базовый набор пакетов:

adduser botuser
usermod -aG sudo botuser
apt update && apt upgrade -y
apt install python3-venv python3-pip ufw nginx -y
ufw allow OpenSSH
ufw allow 'Nginx Full'
ufw enable

Если бот будет работать через webhook — сразу открываю порты 80 и 443 и ставлю nginx: он понадобится под reverse proxy и SSL. Для polling-бота это не нужно — он сам стучится к Telegram API исходящими запросами.

Ещё один момент, который часто упускают: часовой пояс сервера. Если бот работает с расписанием (например, шлёт напоминания в 9 утра по Москве) — выставляю timedatectl set-timezone Europe/Moscow сразу, иначе потом ловишь баг с временем на проде и не сразу понимаешь причину.

Systemd: запускаем бота как системный сервис

Для большинства простых ботов systemd — самый быстрый вариант деплоя. Не нужен Docker, процесс перезапускается автоматически при падении и при перезагрузке сервера.

Создаю виртуальное окружение и ставлю зависимости:

cd /home/botuser/mybot
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

Дальше пишу unit-файл в /etc/systemd/system/mybot.service:

```ini [Unit] Description=Telegram bot mybot After=network.target

[Service] Type=simple User=botuser WorkingDirectory=/home/botuser/mybot ExecStart=/home/botuser/mybot/venv/bin/python bot.py Restart=on-failure RestartSec=5 EnvironmentFile=/home/botuser/mybot/.env

[Install] WantedBy=multi-user.target ```

Restart=on-failure и RestartSec=5 — обязательные строки. Без них бот, упавший от необработанного исключения, просто останется лежать до ручного перезапуска. Включаю и стартую сервис:

sudo systemctl daemon-reload
sudo systemctl enable mybot
sudo systemctl start mybot
sudo journalctl -u mybot -f

Последняя команда — живой лог: в нём сразу видно, если бот не смог законнектиться к API или упал на старте из-за опечатки в токене.

Docker: деплой бота в контейнере

Docker беру, когда у бота есть зависимости помимо Python — например, Redis для FSM-состояний aiogram, Postgres под базу клиентов или ffmpeg для обработки голосовых. Изолировать это через systemd неудобно, а через контейнер — 10 минут работы.

Dockerfile:

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "bot.py"]

docker-compose.yml:

version: "3.9"
services:
  bot:
    build: .
    restart: unless-stopped
    env_file: .env
    volumes:
      - ./data:/app/data
  redis:
    image: redis:7-alpine
    restart: unless-stopped

restart: unless-stopped в Docker делает то же, что Restart=on-failure в systemd — поднимает контейнер после падения или ребута хоста. Запуск и обновление:

docker compose up -d --build
docker compose logs -f bot
docker compose restart bot

На практике разница простая: systemd быстрее развернуть и легче дебажить логи через journalctl, Docker удобнее, если завтра нужно перенести бота на другой VPS или добавить второй сервис вроде очереди задач. Для одного простого бота без внешних зависимостей беру systemd, для проекта с базой и воркерами — Docker.

Webhook или long polling: что ставить на проде

По умолчанию aiogram и python-telegram-bot работают через long polling — бот сам раз в секунду опрашивает Telegram API на новые сообщения. Это просто, но на нагрузке от нескольких сотен активных пользователей в сутки начинает жрать CPU и добавляет задержку в ответах на 1-2 секунды.

Webhook переворачивает схему: Telegram сам присылает апдейты на ваш HTTPS-эндпоинт, как только что-то происходит. Для этого нужен домен или поддомен, SSL-сертификат и nginx в роли reverse proxy перед приложением на порту 8080:

```nginx server { listen 443 ssl; server_name bot.example.ru;

ssl_certificate /etc/letsencrypt/live/bot.example.ru/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/bot.example.ru/privkey.pem;

location /webhook { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; } } ```

Сертификат получаю через certbot --nginx -d bot.example.ru, обновляется он автоматически по крону. Код бота под webhook на aiogram 3.x:

```python from aiogram import Bot, Dispatcher from aiogram.webhook.aiohttp_server import SimpleRequestHandler, setup_application from aiohttp import web

WEBHOOK_PATH = "/webhook" WEBHOOK_URL = "bot.example.ru" + WEBHOOK_PATH

async def on_startup(bot: Bot): await bot.set_webhook(WEBHOOK_URL)

app = web.Application() SimpleRequestHandler(dispatcher=dp, bot=bot).register(app, path=WEBHOOK_PATH) setup_application(app, dp, bot=bot)

if __name__ == "__main__": web.run_app(app, host="127.0.0.1", port=8080) ```

Что выбрать: итог

  • Один простой бот без зависимостей — systemd: развернуть за 15 минут, логи через journalctl.
  • Проект с базой, Redis, воркерами — Docker: изоляция и переносимость.
  • Больше пары сотен пользователей в сутки — webhook вместо long polling: меньше нагрузка, быстрее ответы.
  • Не хотите администрировать сервер вообще — хостинг ботов (например, bothost.ru) с готовым деплоем из Git: домен, SSL, перезапуски и мониторинг уже встроены.

FAQ

Что лучше для бота — systemd или Docker?

Для одного простого бота без внешних сервисов — systemd (быстрее, логи через journalctl). Если есть Redis, Postgres или ffmpeg — Docker: всё изолируется в контейнерах и переносится на другой сервер за минуты.

Нужен ли webhook вместо long polling?

Long polling хватает для ботов до пары сотен активных пользователей в сутки. Выше — webhook: Telegram сам шлёт апдейты на ваш HTTPS-эндпоинт, меньше нагрузка на CPU и быстрее ответы.

Сколько ботов потянет VPS с 1 ГБ RAM?

3-5 ботов среднего размера, если они не обрабатывают тяжёлые файлы или видео. С запасом под Docker и логи лучше брать 2 ГБ RAM.

Можно ли не настраивать VPS вручную?

Да: хостинги ботов вроде DockerHosting берут деплой из Git на себя — код, домен, SSL, перезапуски и мониторинг. Это дороже голого VPS, но экономит дни на настройку. Сравнение тарифов — в каталоге ServerScan.

_Статья обновлена 31 августа 2026 по материалам каталога ServerScan._