Короткий ответ
До правки unit-файла снимите четыре артефакта: systemctl status, systemctl cat, systemctl list-dependencies --failed, journalctl -u и при dumped — coredumpctl info. Код 203/EXEC почти всегда «бинарника нет или нет +x», 226/NAMESPACE — PrivateTmp/ProtectSystem, SEGV — баг или библиотека, а не «надо Restart=always». Vendor-файл в /lib/systemd/system не редактируют: только drop-in в /etc/systemd/system/<unit>.d/.
Пример: хост host.example (10.0.20.10), пользователь admin. Подставьте имя своего unit вместо app.service.
Симптомы и как отличить
Сервис «не запускается», если:
systemctl is-active app.serviceдаётfailedилиinactive;Job for app.service failed because the control process exited with error code;- после reboot
systemctl --failedсодержит unit; - таймер зелёный, а service красный — это не cron, это тот же systemd.
Отличия:
| Наблюдение | Не этот кейс | Статья |
|---|---|---|
| Вся машина в emergency | загрузка | Сервер не загружается |
Unit dead, таймер не стреляет | timer | Не выполняется systemd timer |
| Exec стартует и пишет Permission denied | права/ACL/AppArmor | Permission denied |
| start висит минутами, диск 100% | ENOSPC | Закончился диск |
| Служба жила и внезапно SIGKILL | OOM | OOM Killer |
Возможные причины
ExecStart=указывает на путь, которого нет послеapt upgrade(Python venv,/opt/app/binне смонтирован).- Unit ждёт
After=network-online.target/Requires=postgresql.service, зависимость failed. - Drop-in с опечаткой: два
ExecStart=безExecStart=пустой строки — systemd не склеивает так, как кажется. User=appне существует, домашний каталог не создан,ProtectHome=trueзакрывает сокет.- AppArmor profile
deny, namespace (PrivateDevices,NoNewPrivileges) — код 226. - Бинарь падает с SIGSEGV; без
coredumpctlэто выглядит как «systemd его убивает». - Диск или inode кончились — запись PIDFile/RuntimeDirectory невозможна.
Диагностика
Все команды от admin с sudo на host.example.
1. Состояние и свойства, не файл с форума
systemctl status app.service --no-pager -l
systemctl show app.service -p FragmentPath,DropInPaths,ActiveState,SubState,Result,ExecMainStatus,ExecMainCode,NRestarts
systemctl cat app.serviceFragmentPath скажет, откуда unit: /lib (пакет) или /etc (ваш). DropInPaths — что реально наложено. Если cat показывает не то, что вы правили в nano, вы правили копию не того имени (app.service vs app@.service).
2. Зависимости
systemctl list-dependencies app.service --all
systemctl list-dependencies app.service --reverse
systemctl list-units --failed --no-pagerКрасный Requires= тянет вниз весь граф. Wants= не должен валить сервис; если валит — у вас скорее Requires или BindsTo.
Для сокетов Ubuntu 24.04: ssh.socket активирует ssh.service по запросу. Не путайте inactive (dead) у service до первого коннекта с поломкой.
3. Журнал именно этого unit
journalctl -u app.service -b --no-pager
journalctl -u app.service -o verbose --since 'today' | headИщите status=203/EXEC, Executable not found, Permission denied, Failed to set up mount namespacing. Параллельно диск:
df -h / /var /tmp
df -i / /var4. Coredump до теории «надо ulimit»
coredumpctl list app.service
coredumpctl info $(coredumpctl list -1 --no-legend | awk '{print $2}')Если Storage=none в /etc/systemd/coredump.conf, дампов нет — это настройка, не доказательство, что падения не было. Result=core-dump в systemctl show достаточный сигнал не крутить Restart= в цикле.
5. Ручной запуск тем же User и окружением
systemctl show app.service -p User,Group,Environment,EnvironmentFiles,WorkingDirectory,ExecStart
sudo -u app -H /usr/bin/app --config /etc/app/app.yamlЕсли вручную работает, а под systemd нет — смотрите ProtectSystem, ReadWritePaths, PrivateTmp, AppArmor:
aa-status
journalctl -t apparmor --since '1 hour ago' --no-pagerРешение
Сценарий A. 203/EXEC
Проверьте путь и shebang:
ls -l /usr/local/bin/app
head -n 1 /usr/local/bin/app
namei -l /usr/local/bin/appИнтерпретатор из shebang (/usr/bin/python3) должен существовать. После правки:
sudo systemctl daemon-reload
sudo systemctl start app.serviceСценарий B. Зависимость не встала
Поднимите нижний unit, не верхний. Пример: Requires=network-online.target при сломанном systemd-networkd-wait-online держит приложение вечно.
systemctl status systemd-networkd-wait-online.service --no-pager
systemctl show app.service -p After,Requires,WantsОслабьте через drop-in, не вырезая сеть целиком:
sudo systemctl edit app.service[Unit]
Requires=
Wants=network-online.target
After=network-online.targetПустой Requires= сбрасывает vendor-значение в override — документируйте это в заявке.
Сценарий C. Namespace / Protect*
Временно (на диагностику, не навсегда) добавьте drop-in с ProtectSystem=off только чтобы подтвердить гипотезу, затем верните защиту и точечно ReadWritePaths=/var/lib/app.
Сценарий D. SEGV
Сохраните coredumpctl dump -o /var/tmp/app.core. Обновление пакета или откат apt-get install app=предыдущая — после чтения changelog. Не ставьте ulimit -c unlimited в ExecStartPre «чтобы зажило».
Сценарий E. Vendor unit правили руками
dpkg -S $(systemctl show -p FragmentPath --value app.service)
apt-get install --reinstall <пакет>Ваши изменения перенесите в /etc/systemd/system/app.service.d/override.conf.
Как проверить, что проблема устранена
systemctl reset-failed app.service
systemctl start app.service
systemctl is-active app.service
systemctl show app.service -p NRestarts,ActiveEnterTimestamp
journalctl -u app.service -n 30 --no-pager
ss -tlnp | grep appNRestarts=0 после часа под нагрузкой важнее зелёного start. Если это сокет-активируемый сервис — проверка клиентским коннектом, не только is-active.
Перезагрузка контрольная:
sudo reboot
ssh admin@10.0.20.10 'systemctl is-active app.service'Если не помогло
- Unit активен, приложение не отвечает: это уже сеть, bind на
127.0.0.1, UFW. - Падение через 90 секунд:
TimeoutStartSec, скрипт ждёт сеть/DNS — DNS. Failed to create cgroup: лимиты контейнера/Proxmox, не systemd на хосте.- Логи оборваны vacuum: journald занял диск.
Профилактика
- Только drop-in в
/etc, vendor в/libне трогать. Restart=on-failureсRestartSec=и потолкомStartLimitBurst, не бесконечный цикл.- Мониторинг
systemctl is-failedи coredump, не только TCP-порт. - После
apt upgrade—systemctl catна кастомные сервисы.
FAQ
Чем systemctl edit лучше nano в /lib?
edit создаёт override, переживает обновление пакета. Правка /lib всплывёт при следующем apt.
Нужно ли daemon-reload после изменения бинарника?
Нет, только после изменения unit/drop-in. Бинарь подхватится на следующем start.
Почему enable есть, а после reboot сервис dead?
WantedBy не тот target, или ConditionPathExists ложен, или сокет-активация. Смотрите systemctl show -p UnitFileState,ActiveState,ConditionResult.
Можно ли KillMode=process, чтобы дети жили?
Только если вы понимаете orphan-процессы. Для обычного демона оставляйте control-group.
systemd пишет success, а код приложения ненулевой?
Type=simple считает start успешным в момент fork. Для уведомляющих сервисов нужен Type=notify и sd_notify.