В терминале работает, а под systemd нет
Разница между запуском в терминале и под systemd всегда сводится к окружению. У службы другой пользователь, короткий PATH, нет переменных профиля, другой рабочий каталог, нет терминала и, возможно, включена изоляция файловой системы.
Что это значит
Полезный приём для разбора: запустить программу ровно в том окружении, которое видит служба. Команда systemd-run создаёт временный unit с нужными параметрами, и поведение совпадает с настоящей службой.
Вероятные причины
По порядку: сверху то, что встречается чаще.
-
Другой пользователь
В терминале вы под собой или под root, служба — под
User=. Права, домашний каталог и доступ к файлам отличаются. -
Короткий PATH и отсутствие переменных профиля
Служба не читает .bashrc и .profile. Переменные, которые вы считаете «системными», для неё не существуют.
-
Другой рабочий каталог
В терминале вы находитесь в каталоге программы, у службы рабочий каталог — корень, если не задан явно.
-
Включена изоляция файловой системы
Параметры защиты делают часть путей недоступными или доступными только для чтения. В терминале таких ограничений нет.
-
Программа ждёт терминал
Запрос пароля, подтверждения или интерактивный вывод. У службы терминала нет, и она зависает или падает.
Диагностика
Команды идут в том порядке, в котором их стоит выполнять: каждая следующая проверяет то, что осталось после предыдущей.
Запуск в окружении, близком к службе: сразу видно, воспроизводится ли проблема.
sudo systemd-run --uid=app --property=WorkingDirectory=/opt/myapp --wait --pty /usr/local/bin/myapp --checkТри главных отличия окружения.
systemctl show myapp.service -p User -p Environment -p WorkingDirectoryОграничения изоляции, которых нет в терминале.
systemctl show myapp.service | grep -E "^Protect|^Private|Paths"Решение
Решение своё для каждой причины. Сначала определите, какая из них ваша, — иначе правки наложатся друг на друга.
- Почему происходит
- В терминале вы под собой или под root, служба — под
User=. Права, домашний каталог и доступ к файлам отличаются.
- Как проверить
-
Запустите программу от пользователя службы.
systemctl show myapp.service -p User sudo -u app /usr/local/bin/myapp --check
- Как исправить
-
Дайте пользователю службы нужные права или проверяйте всё через
sudo -u: картина сразу совпадёт с реальностью.
- Почему происходит
- Служба не читает .bashrc и .profile. Переменные, которые вы считаете «системными», для неё не существуют.
- Как проверить
-
Сравните окружение.
systemctl show-environment systemctl show myapp.service -p Environment
- Как исправить
-
Задайте нужные переменные через
Environment=илиEnvironmentFile=и указывайте полные пути к программам.
- Почему происходит
- В терминале вы находитесь в каталоге программы, у службы рабочий каталог — корень, если не задан явно.
- Как проверить
-
Посмотрите параметр.
systemctl show myapp.service -p WorkingDirectory
- Как исправить
-
Задайте
WorkingDirectory=или используйте абсолютные пути в настройках программы.
- Почему происходит
- Параметры защиты делают часть путей недоступными или доступными только для чтения. В терминале таких ограничений нет.
- Как проверить
-
Посмотрите параметры изоляции.
systemctl show myapp.service | grep -E "Protect|Private|Paths"
- Как исправить
-
Разрешите нужные пути через
ReadWritePaths=или временно ослабьте изоляцию, чтобы подтвердить причину.
- Почему происходит
- Запрос пароля, подтверждения или интерактивный вывод. У службы терминала нет, и она зависает или падает.
- Как проверить
-
Поищите приглашение ко вводу в журнале.
journalctl -u myapp.service -n 30 --no-pager | tail -10
- Как исправить
- Уберите интерактивность: передавайте пароли через учётные данные, а подтверждения — ключами.
Пример вывода
В терминале команда есть, у службы нет. Пример показательный: он собран на тестовой машине специально для этой страницы, а не взят из чужого журнала.
$ /usr/local/bin/myapp --version
myapp 2.4.1
$ sudo systemctl start myapp && systemctl status myapp --no-pager | head -6
× myapp.service - My application
Active: failed (Result: exit-code)
Process: 4400 ExecStart=myapp --serve (code=exited, status=203/EXEC)
Тут дело в том, что в ExecStart= указано имя команды без пути: systemd не ищет программу в PATH.
Связанные ошибки
- status=203/EXEC в systemd Код 203/EXEC означает, что systemd не смог выполнить программу из ExecStart=. Разбор причин: путь, права, интерпретатор, синтаксис оболочки.
- status=127 в systemd: команда не найдена Код 127 без имени: оболочка не нашла команду. Появляется, когда ExecStart запускает скрипт или sh -c, а внутри команды нет.
- Permission denied в журнале службы Отказ в доступе у службы systemd: права на файл, каталоги по пути, пользователь службы, параметры изоляции, SELinux и AppArmor.
- status=200/CHDIR в systemd Код 200/CHDIR означает, что systemd не смог перейти в каталог из WorkingDirectory= до запуска программы. Причины и решение.
- status=226/NAMESPACE в systemd Код 226/NAMESPACE: не удалось настроить пространства имён монтирования, UTS или IPC. Частая причина — путь в ReadOnlyPaths= или ProtectHome=.
- Failed to start … — что делать с общим сообщением Строка Failed to start сообщает только факт. Порядок разбора: найти настоящую причину выше по журналу.
- Job for myapp.service failed: с чего начинать разбор Сообщение systemctl при неудачном запуске: что в нём есть, чего в нём нет и какие три команды дают ответ.
- Переменная в unit-файле не разворачивается Запись со знаком доллара попадает в аргументы буквально. Где подстановка работает, а где нет.
Источники
-
systemd.exec(5)
Окружение процессов службы. -
systemd-run(1)
Запуск программы во временном unit. -
Воспроизведено на тестовой машине, systemd 255 (Ubuntu 24.04)
Проверено на пяти видах расхождения окружения: пользователь, PATH, каталог, изоляция, терминал.