Telegram-бот на VPS: запуск через systemd, автозапуск и логи
Переносим Python-бота на сервер правильно: отдельный пользователь, venv, токен вне кода, служба systemd с перезапуском при падении и чтение логов через journalctl.

python bot.py в SSH-сессии умирает вместе с сессией. nohup и screen переживают обрыв, но не перезагрузку сервера и не падение бота. Правильный способ — служба systemd: запускается при загрузке, перезапускается при ошибке, пишет логи в журнал. Ниже на примере Python-бота на aiogram; для Node.js отличия в одной строке.
Для экспериментов подойдёт любой VPS с Ubuntu или Debian; на tanaka.host сервер можно взять на день-два, пройти инструкцию и удалить без лишних трат.
Что нужно: VPS с Ubuntu 24.04 или Debian 12 (боту на long polling хватит самого младшего тарифа), токен от @BotFather, SSH. Домен и сертификат для long polling не нужны.
1. Python
apt update && apt upgrade -y
apt install -y python3-venv git
2. Отдельный пользователь
Бот не должен работать под root. Системный пользователь без права входа:
useradd --system --create-home --home-dir /opt/mybot --shell /usr/sbin/nologin mybot
3. Код
Из Git:
sudo -u mybot git clone https://github.com/ВЫ/ВАШ_БОТ.git /opt/mybot/app
Или минимальный бот для проверки:
sudo -u mybot mkdir -p /opt/mybot/app
sudo -u mybot nano /opt/mybot/app/bot.py
import asyncio
import logging
import sys
from os import getenv
from aiogram import Bot, Dispatcher
from aiogram.filters import CommandStart
from aiogram.types import Message
dp = Dispatcher()
@dp.message(CommandStart())
async def start(message: Message) -> None:
await message.answer("Привет! Я работаю на VPS.")
@dp.message()
async def echo(message: Message) -> None:
await message.send_copy(chat_id=message.chat.id)
async def main() -> None:
bot = Bot(token=getenv("BOT_TOKEN"))
await dp.start_polling(bot)
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
asyncio.run(main())
Токен читается из переменной окружения BOT_TOKEN, в коде его нет — значит, он не утечёт в Git.
4. Виртуальное окружение
sudo -u mybot python3 -m venv /opt/mybot/venv
sudo -u mybot /opt/mybot/venv/bin/pip install aiogram
Для настоящего проекта — pip install -r /opt/mybot/app/requirements.txt.
5. Токен в отдельном файле
nano /etc/mybot.env
BOT_TOKEN=123456789:ТОКЕН_ОТ_BOTFATHER
chmod 600 /etc/mybot.env
Файл читает systemd под root, сам пользователь mybot его не видит.
6. Служба systemd
nano /etc/systemd/system/mybot.service
[Unit]
Description=My Telegram bot
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=0
[Service]
Type=simple
User=mybot
Group=mybot
WorkingDirectory=/opt/mybot/app
EnvironmentFile=/etc/mybot.env
Environment=PYTHONUNBUFFERED=1
ExecStart=/opt/mybot/venv/bin/python bot.py
Restart=always
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
[Install]
WantedBy=multi-user.target
Что здесь важно:
User/Group— бот без привилегий;ExecStartвызывает python из venv напрямую, «активировать» окружение не нужно;Restart=always+RestartSec=5— перезапуск через 5 секунд после любого выхода;StartLimitIntervalSec=0— systemd не сдастся после серии быстрых падений;PYTHONUNBUFFERED=1— иначе Python копит вывод в буфере и логи появляются с задержкой;- последние три строки — минимальная изоляция от системы.
systemctl daemon-reload
systemctl enable --now mybot
systemctl status mybot
Ожидается active (running). Отправьте боту /start.
7. Логи
journalctl -u mybot -f # в реальном времени
journalctl -u mybot -n 100 # последние 100 строк
journalctl -u mybot --since "1 hour ago"
journalctl -u mybot -b # с последней загрузки
Обновление
cd /opt/mybot/app
sudo -u mybot git pull
sudo -u mybot /opt/mybot/venv/bin/pip install -r requirements.txt
systemctl restart mybot
Если правили сам .service — перед restart нужен systemctl daemon-reload.
Node.js и Discord-боты
Схема та же: отдельный пользователь, код в /opt/mybot/app, npm ci от имени пользователя, а в службе меняется одна строка:
ExecStart=/usr/bin/node index.js
Несколько ботов — несколько пользователей, env-файлов и служб: shopbot.service, supportbot.service. Они не мешают друг другу и перезапускаются независимо.