Команда 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-база, то есть весь тот «слой поверх супервизора», который иначе пришлось бы собирать вручную.