Команда python bot.py, запущенная по SSH, живёт ровно до закрытия терминала. Сессия оборвалась — процесс получил SIGHUP и умер, бот замолчал, фоновая обработка встала. Для прода нужно не «запустить», а держать запущенным: чтобы процесс поднимался после краша, после OOM, после перезагрузки сервера — без участия человека.
Разберём три рабочих способа: systemd, pm2 и restart-политики Docker, — и чем они отличаются.
Почему nohup и screen не подходят
Первое, что подсказывает поиск, — nohup python bot.py & или запуск внутри screen/tmux. Это решает только одну проблему: процесс переживает выход из сессии. Но он по-прежнему:
- не перезапускается, если упал с ошибкой;
- не поднимается после перезагрузки сервера;
- не пишет логи в стандартное место;
- не имеет управляемого старта и остановки.
nohup и screen — это «запустил и забыл, пока не упадёт». Для прода нужен супервизор — процесс-менеджер, который следит за приложением и поднимает его обратно.
systemd — стандарт для Linux
В любом современном дистрибутиве уже есть systemd, и для большинства приложений это лучший выбор: ничего ставить не нужно, перезапуск и автозапуск встроены, логи идут в journald.
Unit-файл /etc/systemd/system/mybot.service:
[Unit]
Description=Telegram bot
After=network.target
[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/mybot
ExecStart=/opt/mybot/.venv/bin/python bot.py
Restart=always
RestartSec=3
Environment=PYTHONUNBUFFERED=1
[Install]
WantedBy=multi-user.target
Ключевые строки — Restart=always (поднимать после любого завершения) и RestartSec=3 (пауза перед рестартом, чтобы при падении на старте не молотить рестартами вплотную). Сам по себе крах-цикл это не останавливает: за это отвечает встроенный лимит StartLimitBurst — по умолчанию после 5 запусков за 10 секунд systemd переводит сервис в состояние failed. Активация:
sudo systemctl daemon-reload
sudo systemctl enable --now mybot
sudo systemctl status mybot
journalctl -u mybot -f # логи в реальном времени
enable ставит автозапуск при загрузке, --now сразу стартует сервис. С этого момента процесс переживает и краш, и перезагрузку.
pm2 — для Node.js
Если приложение на Node.js, удобен pm2 — менеджер процессов с человеко-понятным CLI, логами и мониторингом из коробки.
npm install -g pm2
pm2 start app.js --name api
pm2 logs api
pm2 restart api
Чтобы pm2 поднимал процессы после перезагрузки сервера, список нужно зафиксировать:
pm2 startup # выведет команду для регистрации в systemd — выполнить её
pm2 save # сохранить текущий список процессов
Важная деталь: без pm2 save после перезагрузки список окажется пустым. И, по сути, pm2 startup всё равно регистрирует pm2 как сервис systemd — то есть под капотом это надстройка над тем же механизмом.
Docker restart policies
Если приложение уже в контейнере, отдельный супервизор не нужен — рестартом управляет сам Docker через политику перезапуска.
# docker-compose.yml
services:
bot:
build: .
restart: unless-stopped
healthcheck:
test: ["CMD", "python", "healthcheck.py"]
interval: 30s
timeout: 5s
retries: 3
Политика unless-stopped поднимает контейнер после краша и после перезагрузки демона, но не трогает контейнер, если он остановлен вручную. Альтернатива — always. Через чистый docker run то же самое: --restart unless-stopped. healthcheck позволяет Docker понимать, что процесс жив не только как PID, но и функционально.
Что выбрать
| Инструмент | Когда подходит | Автозапуск при ребуте | Логи |
|---|---|---|---|
| systemd | любые приложения на «голом» сервере | да | journald |
| pm2 | Node.js, нужен удобный CLI и мониторинг | да, после pm2 save | свой лог-файл |
| Docker restart | приложение уже контейнеризовано | да (unless-stopped) | docker logs |
Если коротко: для контейнера — restart-политика, для Node.js без контейнера — pm2, во всех остальных случаях — systemd.
Чего эти инструменты не делают
Супервизор держит процесс живым — и только. Он не выкатывает новую версию по git push, не выпускает и не продлевает SSL-сертификат, не делает бэкапы базы, не следит за местом на диске и не присылает алерт, когда приложение упало в три ночи. Это всё — отдельные задачи, которые в self-hosted-сетапе придётся настраивать и обслуживать поверх.
То есть supervised-процесс — это необходимый минимум для прода, но не вся эксплуатация. Где-то рядом всегда оказываются деплой, сертификаты, мониторинг и бэкапы.
Чеклист
- Процесс запускается через супервизор, а не
nohup/screen. - Включён автоматический перезапуск после краша (
Restart=always/restart: unless-stopped). - Включён автозапуск после перезагрузки сервера (
enable/pm2 save/ restart-политика). - Логи пишутся в стандартное место и доступны (
journalctl/docker logs). - Есть пауза между рестартами, чтобы не зациклиться при падении на старте.
Managed-платформа берёт супервайзинг на себя: процесс перезапускается автоматически, поднимается после сбоя и проходит health-check без unit-файлов и pm2 save. Например, на Hostim бот или воркер работают 24/7 без serverless-засыпания, а рядом сразу есть деплой по git push, SSL и managed-база — то есть весь тот «слой поверх супервизора», который иначе пришлось бы собирать вручную.