Скрипт работает в терминале, а под systemd не находит файл. Почему?
Представим: app.py и config.json лежат в /opt/mybot. При запуске из этого каталога всё работает, а системный сервис падает с FileNotFoundError.
Причина может быть в такой строке:
with open("config.json", encoding="utf-8") as file:
...
Относительный путь отсчитывается от рабочей директории процесса. Даже абсолютный путь к app.py в ExecStart не означает, что systemd перейдёт в каталог скрипта.
У обычного системного сервиса без WorkingDirectory рабочая директория по умолчанию — /. У пользовательского сервиса, управляемого через systemctl --user, — домашний каталог пользователя. Указание User= в системном сервисе само по себе рабочую директорию не меняет.
Для диагностики можно временно добавить перед открытием файла:
from pathlib import Path
import logging
logging.warning(
"cwd=%s; config=%s",
Path.cwd(),
Path("config.json").resolve(),
)
Так в журнале будет видно, какой путь использует программа.
Если приложение должно запускаться из своего каталога, укажите его в существующем unit-файле:
[Service]
WorkingDirectory=/opt/mybot
ExecStart=/opt/mybot/.venv/bin/python /opt/mybot/app.py
После изменения системного unit-файла:
sudo systemctl daemon-reload
sudo systemctl restart mybot.service
Другой вариант — привязать путь к файлу скрипта, если конфигурация по устройству проекта лежит рядом с ним:
from pathlib import Path
config_path = Path(__file__).resolve().parent / "config.json"
with config_path.open(encoding="utf-8") as file:
...
Это устраняет зависимость данного пути от рабочей директории. Если ошибка остаётся, нужно проверить существование файла, права пользователя сервиса и ограничения доступа в unit-файле.
Итог: расположение скрипта и рабочая директория процесса — разные вещи. Явная точка отсчёта для путей делает запуск предсказуемее. Расскажите, продолжат ли работать ваши скрипты, если запустить их из другого каталога?