Ошибка code=exited status=203/EXEC в systemd: причины и решение

Ошибка code=exited, status=203/EXEC появляется в выводе systemctl status, когда systemd не смог запустить исполняемый файл, указанный в директиве ExecStart юнит-файла. Код 203 означает, что процесс даже не начал выполняться: ядро отказало на этапе вызова execve(), поэтому сама программа здесь ни при чём — искать нужно в путях, правах и окружении службы.

Типичный симптом выглядит так: служба падает сразу после systemctl start, в статусе видно Failed at step EXEC spawning /usr/bin/myapp: No such file or directory или Permission denied. Ниже разберём, как диагностировать причину и устранить её без риска для системы.

Что означает код 203/EXEC

В systemd каждому коду завершения соответствует своё значение. status=203/EXEC — это сигнал о том, что systemd не смог выполнить системный вызов запуска бинарного файла. Процесс форкнулся, но загрузить программу в память не удалось, и служба завершилась ещё до исполнения первой строки кода.

Ключевая подсказка всегда находится в строке журнала рядом с кодом. Там указывается конкретная причина отказа: отсутствующий файл, недостаток прав, неверный интерпретатор скрипта или ограничения безопасности. Именно эту строку нужно читать первой, а не сам код 203.

Основные причины ошибки

Чаще всего отказ на этапе EXEC вызван одной из нескольких типовых причин. Проверять их стоит в том порядке, в котором они перечислены ниже — от самых частых к более редким.

  • 📂 Неверный путь к исполняемому файлу — опечатка в ExecStart или программа установлена в другой каталог, чем указано в юните.
  • 🔒 Отсутствие права на исполнение — у файла не установлен бит +x, либо пользователь службы не имеет доступа к каталогу.
  • 📜 Битый shebang в скрипте — первая строка вида #!/bin/bash указывает на несуществующий интерпретатор или содержит символы Windows-переноса строк (CRLF).
  • 🛡️ Ограничения безопасности — SELinux, AppArmor или директивы юнита вроде ProtectSystem и NoNewPrivileges блокируют запуск.
  • 🏗️ Несовместимая архитектура — бинарник собран под другую платформу, например ARM-файл пытаются запустить на x86_64.
⚠️ Внимание: сообщение No such file or directory не всегда означает, что файла нет. Оно же появляется, когда отсутствует интерпретатор из shebang-строки скрипта или динамический загрузчик бинарника.

Диагностика: как найти точную причину

Первым делом посмотрите полный статус службы и свежие записи журнала. Команда systemctl status имя_службы покажет строку с причиной отказа, а более подробный вывод даст журнал:

journalctl -u имя_службы -n 50 --no-pager

Далее проверьте, существует ли файл из ExecStart и можно ли его запустить. Выполните ls -l /путь/к/файлу и убедитесь, что в правах присутствует x. Затем попробуйте запустить файл вручную от имени пользователя, под которым работает служба:

sudo -u имя_пользователя /путь/к/файлу

Если при ручном запуске программа стартует нормально, а через systemd падает с 203/EXEC, проблема почти наверняка в окружении юнита: переменных, рабочем каталоге или ограничениях безопасности. Если не запускается и вручную — смотрите на сам файл: его формат, shebang и зависимости.

📊 Где вы столкнулись с ошибкой 203/EXEC?
Собственный скрипт или программа
Служба после установки пакета
Docker/контейнерное окружение
После обновления системы

Пошаговое исправление

Ниже — безопасная последовательность действий, которая не требует пересборки пакетов и не затрагивает системные файлы за пределами вашего юнита.

  • ✅ Откройте юнит-файл командой systemctl cat имя_службы и сверьте путь в ExecStart с реальным расположением программы.
  • ✅ Установите право на исполнение: chmod +x /путь/к/файлу.
  • ✅ Проверьте владельца и права на все родительские каталоги — пользователь службы должен иметь туда доступ на чтение и вход.
  • ✅ Для скриптов проверьте первую строку и пересохраните файл в формате Unix (LF), например через dos2unix или настройки редактора.
  • ✅ После любых правок юнита выполните systemctl daemon-reload и только потом перезапускайте службу.

☑️ Проверка перед перезапуском службы

Выполнено: 0 / 5

Если служба использует EnvironmentFile или переменные в ExecStart, убедитесь, что файл окружения существует и читается. Отсутствующий EnvironmentFile без знака - перед путём тоже может приводить к сбою запуска.

Типовые сценарии и их решения

Разные сообщения в журнале при одном и том же коде 203 требуют разных действий. Сводная таблица поможет быстро сопоставить симптом и решение.

Сообщение в журналеВероятная причинаЧто делать
No such file or directoryНеверный путь или отсутствует интерпретаторПроверить путь и shebang скрипта
Permission deniedНет права на исполнение или доступ к каталогуchmod +x, проверить владельца и SELinux
Exec format errorБитый файл или чужая архитектураПроверить file, переустановить пакет
Failed at step EXEC с ProtectSystemОграничения sandbox-директив юнитаСкорректировать директивы безопасности
⚠️ Внимание: ослабляя директивы безопасности вроде ProtectSystem, PrivateTmp или NoNewPrivileges, делайте это точечно и понимайте, зачем они были включены. Полное их отключение ради «заработало» снижает защищённость системы.

Особые случаи: SELinux, контейнеры, обновления

На системах с SELinux (RHEL, CentOS, Fedora) файл может существовать и иметь все права, но запуск блокируется из-за неверного контекста безопасности. Проверить это можно командой ls -Z /путь/к/файлу и поиском отказов в ausearch -m avc -ts recent, если утилита audit установлена. Восстановить контекст для стандартных путей помогает restorecon -v /путь/к/файлу.

Отдельная ситуация — ошибка появилась после обновления пакета, который изменил расположение бинарника, а юнит-файл остался со старым путём. Такое бывает с кастомными юнитами, созданными вручную поверх пакетных. Решение — сверить ExecStart с актуальным путём из свежей версии пакета, например через which или whereis.

Почему скрипт с CRLF даёт ошибку 203

Если скрипт создан в Windows, строки завершаются символами \r\n. Ядро воспринимает shebang как #!/bin/bash\r — то есть ищет интерпретатор с невидимым символом возврата каретки в имени, не находит его и возвращает No such file or directory. Лечится пересохранением файла в формате LF.

Как предотвратить повторение ошибки

Большинство случаев 203/EXEC связано с ручным созданием юнитов и скриптов. Несколько привычек заметно снижают риск: всегда проверяйте новый юнит командой systemd-analyze verify /путь/к/юниту, которая укажет на синтаксические проблемы, и тестируйте запуск бинарника вручную от целевого пользователя до включения службы.

Для скриптов держите shebang корректным, сохраняйте файлы в Unix-формате и не кладите исполняемые файлы в каталоги, смонтированные с опцией noexec — проверить это можно в выводе mount | grep /точка/монтирования. После любых правок юнитов не забывайте про daemon-reload, иначе systemd продолжит использовать старую версию конфигурации.

Частые вопросы

Чем код 203/EXEC отличается от 203/EXIT?

203/EXEC означает, что программа не смогла запуститься на этапе системного вызова exec — файл не найден, нет прав или неверный формат. Код 203/EXIT встречается редко и означает, что программа запустилась, но завершилась с кодом возврата 203, который ей вернуло само приложение.

Файл существует и запускается вручную, но служба падает с 203 — почему?

Скорее всего, дело в окружении: служба работает от другого пользователя, у которого нет доступа к файлу или каталогам, либо запуск блокируют SELinux/AppArmor или sandbox-директивы юнита. Проверьте запуск через sudo -u пользователь_службы и журнал аудита безопасности.

Нужно ли делать daemon-reload после правки юнита?

Да. systemd кэширует содержимое юнит-файлов, и без systemctl daemon-reload служба будет запускаться по старой конфигурации. Это частая причина ситуации «я всё исправил, а ошибка осталась».

Может ли ошибка 203 появиться из-за docker или контейнера?

Да, если юнит запускает контейнер, а бинарник внутри образа отсутствует, не исполняемый или собран под другую архитектуру. В этом случае проверяйте команду запуска контейнера и точку входа образа, а также совпадение архитектуры образа и хоста.

Как понять, что виноват именно SELinux, а не права?

Если ls -l показывает корректные права, но запуск под systemd всё равно отклоняется, посмотрите контекст файла через ls -Z и поищите записи отказов (denied) в журнале аудита. Временный перевод в режим permissive помогает подтвердить диагноз, но постоянным решением должен быть правильный контекст файла, а не отключение защиты.