Запустил скрипт через nohup python bot.py & — при ребуте всё пропало, при падении не перезапустится. Правильный способ — systemd unit. Ниже — типовой прод-конфиг для Python и Node.js приложений на Ubuntu.
Python-приложение: пример FastAPI
Кладём в /etc/systemd/system/myapi.service.
[Unit]
Description=MyAPI FastAPI application
After=network.target postgresql.service
[Service]
Type=exec
User=deploy
Group=deploy
WorkingDirectory=/opt/myapi
Environment="PATH=/opt/myapi/venv/bin"
Environment="DATABASE_URL=postgresql://user:pass@localhost/db"
EnvironmentFile=/opt/myapi/.env
ExecStart=/opt/myapi/venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000
# рестарт при падении
Restart=always
RestartSec=5
# ограничения ресурсов
MemoryMax=1G
CPUQuota=200%
# безопасность
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/myapi/var
PrivateTmp=true
[Install]
WantedBy=multi-user.targetNode.js-приложение
Аналогично, /etc/systemd/system/mybot.service.
[Unit]
Description=MyBot Telegram bot
After=network.target
[Service]
Type=exec
User=deploy
Group=deploy
WorkingDirectory=/opt/mybot
Environment="NODE_ENV=production"
EnvironmentFile=/opt/mybot/.env
ExecStart=/usr/bin/node --max-old-space-size=512 index.js
Restart=on-failure
RestartSec=10
StartLimitBurst=5
StartLimitIntervalSec=60
MemoryMax=768M
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
# stdout/stderr → journald
StandardOutput=journal
StandardError=journal
SyslogIdentifier=mybot
[Install]
WantedBy=multi-user.targetАктивация и управление
Стандартные команды.
sudo systemctl daemon-reload # после правки unit-файла
sudo systemctl enable --now myapi
# статус
sudo systemctl status myapi
sudo systemctl is-active myapi # active/inactive
sudo systemctl is-enabled myapi # enabled/disabled
# логи
sudo journalctl -u myapi -f # tail -f
sudo journalctl -u myapi --since "1 hour ago"
sudo journalctl -u myapi -p err # только errors
# рестарт
sudo systemctl restart myapi
sudo systemctl reload myapi # если сервис поддерживает SIGHUPТипичные грабли
На чём чаще всего спотыкаются.
- "status=203/EXEC" — путь к бинарнику неверный.
which node, вписать полный путь вExecStart. - "Failed to start" без деталей** —
sudo journalctl -u service -n 50покажет реальную ошибку. - Приложение зависит от .env — используйте
EnvironmentFile=/path/.env(неEnvironment=). - `Type=simple` vs `Type=exec` — используйте
exec(доступно с systemd 240+), точнее отслеживает падение. - Sudo нужен внутри — плохая идея; правильно — дать нужные capabilities через
AmbientCapabilities.