Сервис systemd не запускается: status, journalctl, коды выхода и зависимости
Команда KAI Lab · · 8 мин чтения
Если сервис systemd не запускается, начните с systemctl status имя: там результат запуска (Result:), код выхода процесса и последние строки журнала, а полный журнал с момента загрузки покажет journalctl -u имя -b. Код вида status=203/EXEC или status=217/USER значит, что systemd не смог даже запустить программу, а status=1/FAILURE — что программа запустилась и сама завершилась с ошибкой, и причину надо искать в её собственных сообщениях.
Ниже — порядок проверки и разбор типичных ошибок. Перезапускать сервис по кругу в надежде, что «само пройдёт», бессмысленно: после нескольких быстрых неудач systemd сам перестанет пытаться.
Симптом → команда → что смотреть
| Симптом | Команда | Что смотреть |
|---|---|---|
Сервис в failed | systemctl status app | Active: и Result:, status= у Main PID:, последние строки журнала |
| Нужна полная картина | journalctl -u app -b | первую ошибку после запуска, а не последнюю строку |
status=203/EXEC | systemctl cat app | путь в ExecStart=, право на исполнение файла |
status=217/USER | id имя | существует ли пользователь из User= |
status=200/CHDIR | ls -ld каталог | есть ли каталог из WorkingDirectory= и доступ к нему |
При запуске пишет changed on disk | systemctl daemon-reload | systemd работает со старой версией unit-файла |
Result: start-limit-hit | systemctl reset-failed app | сначала причину падений, потом сброс счётчика |
A dependency job ... failed | systemctl --failed | какая из зависимостей упала |
Unit ... is masked | systemctl unmask app | кто и зачем замаскировал сервис |
| Сомнения в unit-файле | systemd-analyze verify | опечатки в ключах и секциях |
Шаг 1. systemctl status
$ systemctl status orders-worker
× orders-worker.service - Orders worker
Loaded: loaded (/etc/systemd/system/orders-worker.service; enabled; preset: enabled)
Active: failed (Result: exit-code) since Thu 2026-09-24 03:12:41 UTC; 2min 3s ago
Duration: 812ms
Process: 48213 ExecStart=/opt/orders/bin/worker --config /etc/orders/worker.yml (code=exited, status=1/FAILURE)
Main PID: 48213 (code=exited, status=1/FAILURE)
CPU: 790ms
Sep 24 03:12:41 app-01 worker[48213]: FATAL: open /etc/orders/worker.yml: permission denied
Sep 24 03:12:41 app-01 systemd[1]: orders-worker.service: Main process exited, code=exited, status=1/FAILURE
Sep 24 03:12:41 app-01 systemd[1]: orders-worker.service: Failed with result 'exit-code'.Как это читать:
Loaded:— откуда загружен unit-файл и включён ли автозапуск (enabled). Если здесьnot-found,maskedилиbad-setting, до запуска дело не дошло.Active: failed (Result: exit-code)— сервис упал из-за ненулевого кода выхода. Другие частые результаты:timeout(не уложился вTimeoutStartSec=, по умолчанию 90 секунд),signal(процесс убит сигналом),core-dump,oom-kill,start-limit-hit.Main PID: ... status=1/FAILURE— код выхода самой программы.- Внизу — хвост журнала, по умолчанию десять строк. Длинные строки обрезаются, целиком их покажет
systemctl status -l.
Здесь причина видна сразу: программа не может прочитать свой конфиг. Проверяем, от кого она работает и какие права у файла:
$ ls -l /etc/orders/worker.yml
-rw------- 1 root root 1184 Sep 24 02:58 /etc/orders/worker.yml
$ systemctl show -p User orders-worker
User=ordersФайл читает только root, а сервис запущен от orders. Исправление — дать доступ группе сервиса, а не открывать файл всем: sudo chown root:orders /etc/orders/worker.yml и sudo chmod 640 /etc/orders/worker.yml.
Шаг 2. journalctl: полная история
status показывает только хвост. Если сервис перезапускался несколько раз или упал давно, нужен журнал целиком:
$ journalctl -u orders-worker -b # всё о сервисе с момента загрузки
$ journalctl -u orders-worker --since "1 hour ago"
$ journalctl -u orders-worker -b -p warning # только предупреждения и ошибки
$ journalctl -xeu orders-worker # конец журнала с пояснениямиИщите первую ошибку после запуска. Последние строки обычно описывают последствия, вроде Failed with result, а причина выше. Флаг -x добавляет пояснения из каталога сообщений systemd, -e сразу переходит в конец журнала.
Если приложение пишет лог в свой файл, а не в stdout, в журнале останутся только записи systemd о коде выхода. Тогда открывайте файл приложения. У многих демонов есть и собственная проверка конфигурации, которая называет строку с ошибкой: nginx -t, sshd -t, apachectl configtest.
Коды выхода: кто упал — systemd или программа
Коды от 200 и выше выставляет сам systemd: он не смог подготовить окружение, и до запуска программы дело не дошло. Коды 1–7 описаны в спецификации LSB, но их возвращает сама программа, и она может вкладывать в них свой смысл.
| Код | Что значит на практике |
|---|---|
1/FAILURE | программа запустилась и упала: читайте её сообщения |
2/INVALIDARGUMENT | чаще всего неверные аргументы: опечатка в ExecStart=, неизвестный флаг |
200/CHDIR | нет каталога из WorkingDirectory= или нет прав на него |
203/EXEC | не удалось выполнить файл: его нет, нет бита x или неверный интерпретатор в первой строке скрипта |
217/USER | пользователя из User= нет в системе |
226/NAMESPACE | не удалось настроить изоляцию: часто не существует путь из ReadWritePaths= или похожей настройки |
Так выглядит 203/EXEC в журнале:
$ journalctl -u orders-worker -b -p warning -o cat
orders-worker.service: Failed at step EXEC spawning /opt/orders/bin/worker: No such file or directory
orders-worker.service: Failed with result 'exit-code'.-o cat убирает время и имя хоста — удобно, когда важен только текст. Типичные причины: файла нет по этому пути (опечатка, релиз не докатился, симлинк ведёт в пустоту), у файла нет права на исполнение, у скрипта неверная строка #!. Отдельная ловушка — скрипт, сохранённый с окончаниями строк Windows: ядро ищет интерпретатор /bin/bash с невидимым \r на конце и возвращает ту же No such file or directory.
А так — 217/USER:
$ journalctl -u orders-worker -b -p warning -o cat
orders-worker.service: Failed to determine user credentials: No such process
orders-worker.service: Failed at step USER spawning /opt/orders/bin/worker: No such process
orders-worker.service: Failed with result 'exit-code'.No such process здесь сбивает с толку: так systemd сообщает, что пользователь не найден. Проверка — id orders.
Ещё одна ловушка. Для Type=simple, типа по умолчанию, systemctl start вернёт успех, даже если бинарника нет или пользователя из User= не существует, — это прямо написано в документации. Сервис упадёт через долю секунды, а команда запуска промолчит. Поэтому после старта всегда смотрите status, а в своих unit-файлах выбирайте Type=exec: с ним systemctl start сразу сообщит об ошибке.
Правили unit-файл, а ничего не изменилось: daemon-reload
systemd читает unit-файлы при загрузке и по команде daemon-reload. Если отредактировать файл и сразу сделать restart, запустится старая версия, и systemd об этом предупредит:
$ sudo systemctl restart orders-worker
Warning: The unit file, source configuration file or drop-ins of orders-worker.service changed on disk. Run 'systemctl daemon-reload' to reload units.
$ sudo systemctl daemon-reload
$ sudo systemctl restart orders-workerПорядок после любой ручной правки: daemon-reload, потом restart. Исключение — systemctl edit orders-worker: команда создаёт drop-in override.conf в каталоге orders-worker.service.d и перечитывает конфигурацию сама. Итоговую конфигурацию со всеми drop-in показывает systemctl cat:
$ systemctl cat orders-worker
# /etc/systemd/system/orders-worker.service
[Unit]
Description=Orders worker
[Service]
User=orders
WorkingDirectory=/opt/orders
ExecStart=/opt/orders/bin/worker --config /etc/orders/worker.yml
[Install]
WantedBy=multi-user.target
# /etc/systemd/system/orders-worker.service.d/override.conf
[Service]
Environment=LOG_LEVEL=debugОпечатку в ключе systemd не считает фатальной: пишет предупреждение и игнорирует строку. Если ошибиться в ExecStart=, сервис окажется вовсе без команды запуска. Проверяйте файл до перезапуска:
$ sudo systemd-analyze verify /etc/systemd/system/orders-worker.service
/etc/systemd/system/orders-worker.service:7: Unknown key name 'ExecStar' in section 'Service', ignoring.
orders-worker.service: Service has no ExecStart=, ExecStop=, or SuccessAction=. Refusing.Лимит запусков: start-limit-hit
С Restart=on-failure упавший сервис перезапускается, а пауза RestartSec= по умолчанию — всего 100 мс. При этом systemd по умолчанию разрешает не больше пяти запусков за 10 секунд. Сервис, который падает сразу после старта, исчерпывает лимит за секунду: в журнале появится Start request repeated too quickly., статус станет failed (Result: start-limit-hit), и перезапуски прекратятся.
Сначала найдите в журнале причину падений. Потом сбросьте счётчик и запустите:
$ sudo systemctl reset-failed orders-worker
$ sudo systemctl start orders-workerЧтобы временная проблема — например, база ещё поднимается — не исчерпывала лимит мгновенно, задайте паузу побольше: RestartSec=5s. Пока сервис ждёт очередного перезапуска, status показывает Active: activating (auto-restart). Тот же цикл «упал — перезапустился» в контейнерах разобран в статьях контейнер Docker постоянно перезапускается и CrashLoopBackOff в Kubernetes.
Зависимости: сервис ждёт другой
Requires= и Wants= говорят, какие юниты запустить вместе с сервисом, а After= — в каком порядке. Это разные вещи: без After= зависимые юниты стартуют одновременно. Если указаны Requires= и After=, а зависимость не поднялась, сервис не запустится:
$ sudo systemctl start orders-worker
A dependency job for orders-worker.service failed. See 'journalctl -xe' for details.
$ systemctl --failed --plain --no-legend
db-migrate.service loaded failed failed Orders DB migrationsЧинить нужно упавшую зависимость, а не сам сервис. Wants= мягче: сервис запустится, даже если зависимость не поднялась, — документация systemd советует выбирать его чаще, чем Requires=.
Сервис замаскирован или не найден
$ sudo systemctl start orders-worker
Failed to start orders-worker.service: Unit orders-worker.service is masked.mask связывает unit с /dev/null, чтобы его нельзя было запустить никаким способом. Обычно это делают сознательно, поэтому перед systemctl unmask выясните, кто и зачем. Сообщение Unit orders-worker.service not found. означает, что файла нет или в имени опечатка: проверьте systemctl list-unit-files 'orders*'.
Руками запускается, из systemd — нет
Частая ситуация: из консоли программа работает, а как сервис падает. Отличается окружение:
- пользователь: systemd запускает от
User=, а вы проверяли от своего или от root; - рабочий каталог: без
WorkingDirectory=системный сервис стартует в/, и относительные пути ломаются; - переменные: ваш
.bashrcсервис не читает, переменные для него задают черезEnvironment=илиEnvironmentFile=; - песочница: настройки вроде
ProtectSystem=не дают писать туда, куда пишет программа.
Бывает, что сервис ни при чём. nginx не стартует с ошибкой bind() to 0.0.0.0:80 failed (98: Address already in use) — порт держит другой процесс, разбор в статье порт уже занят. Сервис не может создать pid-файл или временный файл — проверьте, не закончилось ли место на диске.
Во втором месяце симулятора DevOps KAI Lab есть тикет «nginx не стартует после переезда сертификатов»: сайт лежит, и причину нужно найти по статусу, журналу и конфигурации, а не перезапуском наугад. Консоль отвечает реальными выводами команд, так что порядок из этой статьи можно пройти руками.
Частые вопросы
Почему systemctl start ничего не вывел, а сервис не работает? Для Type=simple systemd считает сервис запущенным сразу после создания процесса, ещё до запуска программы. Если бинарника нет или пользователь не существует, команда вернёт успех, а сервис упадёт через долю секунды. Смотрите systemctl status после каждого старта или используйте Type=exec.
Что значит status=203/EXEC? systemd не смог выполнить файл из ExecStart=: его нет по указанному пути, у него нет права на исполнение или у скрипта неверный интерпретатор в первой строке.
Нужно ли делать daemon-reload после каждой правки unit-файла? После правки файлов руками — да. systemctl edit перечитывает конфигурацию сам.
Как запустить сервис после start-limit-hit? Найти и устранить причину падений, затем выполнить systemctl reset-failed имя и systemctl start имя. Сброс без исправления вернёт вас в ту же точку через несколько секунд.
Что делать, если в journalctl о сервисе пусто? Проверьте, куда пишет приложение: в свой файл, в syslog или в stdout. Если в журнале только строки systemd о коде выхода, приложение пишет в другое место или упало раньше, чем успело что-то записать.
Источники
- man7.org: systemctl(1) —
status,cat,edit,daemon-reload,reset-failed,mask. - man7.org: journalctl(1) —
-u,-b,-p,-x,-e,-o. - man7.org: systemd.exec(5) — раздел Process Exit Codes,
WorkingDirectory=,User=. - man7.org: systemd.service(5) —
Type=simpleиType=exec,Restart=,RestartSec=,TimeoutStartSec=. - man7.org: systemd.unit(5) —
Requires=,Wants=,After=,StartLimitIntervalSec=, drop-in файлы. - man7.org: systemd-system.conf(5) — лимит запусков и таймауты по умолчанию.
- man7.org: systemd-analyze(1) —
verify. - systemd. Исходный код — тексты сообщений
Failed at step,Start request repeated too quickly,changed on disk.