Unit-файл для Python-приложения
Два частых случая: веб-приложение за gunicorn и долгоживущий скрипт (бот, воркер) из venv.
Веб-приложение на gunicorn
[Unit]
Description=myapp (gunicorn)
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
NotifyAccess=main
User=myapp
Group=myapp
WorkingDirectory=/srv/myapp
EnvironmentFile=-/etc/myapp/env
ExecStart=/srv/myapp/venv/bin/gunicorn --workers 4 --bind 127.0.0.1:8000 myapp.wsgi:application
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=30
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Type=notify — gunicorn сам сообщает systemd, что готов принимать запросы, и systemctl start ждёт именно этого.
ExecReload с сигналом HUP перезапускает воркеры без потери соединений: systemctl reload myapp.
Бот или воркер из venv
[Unit]
Description=Telegram-бот
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=bot
WorkingDirectory=/srv/tgbot
Environment=PYTHONUNBUFFERED=1
EnvironmentFile=/etc/tgbot/env
ExecStart=/srv/tgbot/venv/bin/python bot.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
На чём спотыкаются
- Нет логов. Python буферизует вывод, когда пишет не в терминал.
PYTHONUNBUFFERED=1или ключ-u— и вывод сразу виден вjournalctl -u tgbot -f. - Не тот Python. Указывайте интерпретатор из venv полным путём, а не
python3: у службы нет вашегоsource venv/bin/activate. - Каталог. Если
WorkingDirectory=не существует или недоступен пользователю службы, запуск падает с кодом 200 — разбор status=200/CHDIR. - Пользователь. Пользователя из
User=нужно создать заранее:useradd --system --home /srv/myapp --shell /usr/sbin/nologin myapp. Иначе — ошибка 217/USER. - Секреты. Токены и пароли — в
EnvironmentFile=с правами 600, а не в сам unit-файл: его может прочитать любой черезsystemctl cat.