🔧 Полный гайд по systemctl и unit-файлам (systemd)
📑 Содержание
- Что такое systemd / systemctl
- Основные команды systemctl
- Где хранятся unit-файлы и их приоритеты
- Структура unit-файла (service) — разбираем секции
- Создание собственного .service — пошагово
- Шаблонные unit-файлы (instance units) —
@-юниты - Drop-in, override и
systemctl edit - Mask / Unmask — зачем маскировать службы
- Таймеры (
.timer) и socket-активация (.socket) - Жизненный цикл службы: start/stop/restart/reload и нюансы
- Параметры перезапуска и поведение при сбоях
- Безопасность и ограничение привилегий unit-ов
- Отладка и логирование (journalctl, systemctl status)
- Полезные приёмы и чеклист для продакшн-служб
- Примеры: несколько готовых unit-файлов
- Ссылки / ресурсы (коротко)
Что такое systemd / systemctl
systemd — это init-система и менеджер служб, которая управляет запуском системы, служб, сокетов, таймеров и т.д. systemctl — основной инструмент для взаимодействия с systemd (запуск/остановка/включение/отладка юнитов).
systemd использует unit-файлы (юниты) разного типа: .service, .socket, .timer, .target, .mount, .path и другие.
Основные команды systemctl
Краткий справочник — самое часто используемое:
systemctl start <unit>— запустить юнит сразу.systemctl stop <unit>— остановить юнит.systemctl restart <unit>— перезапустить (stop → start).systemctl reload <unit>— отправить службе сигнал для перечитывания конфигурации (если поддерживает).systemctl enable <unit>— включить автозапуск (при старте системы создаёт symlink).systemctl disable <unit>— отключить автозапуск.systemctl enable --now <unit>— включить и запустить сейчас.systemctl is-enabled <unit>— вернутьenabled/disabled/static/masked.systemctl is-active <unit>— вернутьactive/inactive/failed.systemctl status <unit>— статус + последние логи.systemctl list-units --type=service— список текущих юнитов (запущенных/активных).systemctl list-unit-files— список всех доступных unit-файлов и их состояний (enabled/disabled/…).systemctl daemon-reload— перечитать unit-файлы после изменений на диске.systemctl daemon-reexec— перезапустить сам systemd (редко используется).systemctl mask <unit>— замаскировать (сделать невозможным запуск).systemctl unmask <unit>— снять маску.systemctl reset-failed— сбросить состояние failed (по одному или всем).systemctl cat <unit>— показать содержимое юнита с drop-in’ами.systemctl edit <unit>— открыть drop-in для переопределения (без редактирования основного файла).systemctl link <path-to-unit>— зарегистрировать юнит из произвольного пути.systemctl kill <unit> --kill-who=main --signal=SIGTERM— послать сигнал процессам юнита.
Где хранятся unit-файлы и приоритет (важно)
Типичные пути (приоритет сверху вниз — чем выше, тем важнее):
/etc/systemd/system/— администратора: локальные изменения и overrides. (высокий приоритет)/run/systemd/system/— runtime-юниты, генерируются в процессе работы./lib/systemd/system/или/usr/lib/systemd/system/— поставщик пакета (поставляются дистрибутивом). (низкий приоритет)
Также пользовательские юниты:
~/.config/systemd/user/— юниты дляsystemd --user.systemctl --user— управляет юнитами пользователя.
Важно: правка файлов в /lib/systemd/system/ не рекомендуется — при обновлении пакета изменения могут быть перезаписаны. Правильный способ — поместить override в /etc/systemd/system/<unit>.d/ или использовать systemctl edit.
Структура unit-файла (на примере .service)
Unit-файл — обычный INI-файл с секциями:
[Unit]
Description=My background service
Documentation=man:myservice(8)
After=network.target
Requires=network.target
Wants=postgresql.service
[Service]
Type=simple
User=svcuser
Group=svcgroup
WorkingDirectory=/opt/myapp
Environment=ENV=prod
EnvironmentFile=/etc/default/myapp
ExecStart=/usr/bin/myapp --config /etc/myapp/config.yml
ExecStartPre=/usr/bin/myapp-prep
ExecStop=/bin/kill -TERM $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
PrivateTmp=true
ProtectSystem=full
[Install]
WantedBy=multi-user.target
Ключевые секции и опции:
-
[Unit]Description=— описание.Documentation=— ссылки на документацию.After=/Before=— порядок старта (логический, не зависит от зависимости).Requires=— жёсткая зависимость: если Required не запустился — и этот unit не будет запущен.Wants=— мягкая зависимость (не критична).Condition...— условия запуска (напримерConditionPathExists=).
-
[Service]Type=—simple(по умолчанию),forking,oneshot,notify,dbus.ExecStart=— команда запуска.ExecStartPre=/ExecStartPost=— команды до/после старта.ExecReload=— команда для reload.ExecStop=— команда для остановки.Restart=—no,on-success,on-failure,always,on-abnormal,on-abort.RestartSec=— пауза перед рестартом.User=/Group=— под каким пользователем запускать.Environment=/EnvironmentFile=— переменные окружения.- Ограничения/безопасность:
PrivateTmp=,ProtectSystem=,ProtectHome=,NoNewPrivileges=,CapabilityBoundingSet=,ReadOnlyDirectories=, и т.д.
-
[Install]WantedBy=— в какой таргет добавить symlink при enable (обычноmulti-user.target).Alias=— дополнительные имена.
Создание собственного .service — шаги и рекомендации
-
Создаём unit в
/etc/systemd/system/:sudo tee /etc/systemd/system/myapp.service > /dev/null <<'EOF' [Unit] Description=MyApp background service After=network.target [Service] Type=simple User=myapp Group=myapp WorkingDirectory=/opt/myapp ExecStart=/usr/bin/myapp --config /etc/myapp/config.yml Restart=on-failure RestartSec=5 LimitNOFILE=65536 PrivateTmp=true [Install] WantedBy=multi-user.target EOF -
Перечитать конфигурацию systemd:
sudo systemctl daemon-reload -
Включить автозапуск и запустить:
sudo systemctl enable --now myapp.service -
Проверить статус и логи:
sudo systemctl status myapp.service sudo journalctl -u myapp.service -b --no-pager
Советы:
- Не храните рабочие каталоги и логи в
/root— используйте отдельного пользователя. - Для демонов, которые форкают процесс, ставьте
Type=forking. Для программ, которые не форкают —Type=simple. - Для сервисов, которые сообщают systemd о готовности, используйте
Type=notifyи библиотеку sd_notify.
Шаблонные unit-файлы (instance units) — @-юниты
Шаблонный unit позволяет запускать несколько экземпляров одной службы с разными параметрами: myservice@instance.service.
Пример /etc/systemd/system/web@.service:
[Unit]
Description=Web instance %i
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/web --name %i --config /etc/web/%i.conf
[Install]
WantedBy=multi-user.target
Запуск экземпляра:
sudo systemctl start web@front.service
sudo systemctl enable --now web@front.service
В шаблоне %i — «instance name» (часть после @), %f — с escape, %n — полное имя юнита.
Drop-in и systemctl edit — безопасная кастомизация
Вместо изменения оригинальных файлов пакета используйте drop-in или systemctl edit:
systemctl edit myapp.service— откроет временный файл в$EDITORи создаст drop-in в/etc/systemd/system/myapp.service.d/override.confпосле сохранения.- Вы можете перекрывать отдельные строки, например:
[Service]
Environment=NEW_VAR=1
Restart=always
-
Чтобы посмотреть итоговый файл с учётом всех drop-in:
systemctl cat myapp.service
Mask / Unmask — зачем маскировать службы
mask создаёт символическую ссылку … -> /dev/null, после чего systemctl start и другие команды не смогут запустить юнит (даже если попытаться зависимостью). Это надёжный способ запретить запуск сервиса (вручную или автоматически).
sudo systemctl mask foo.service
# Проверка:
systemctl is-enabled foo.service # вернёт "masked"
# Снятие маски:
sudo systemctl unmask foo.service
Когда использовать:
- В проде, если служба конфликтует и её нельзя допустить к запуску.
- При миграциях, чтобы предотвратить случайный запуск.
Не путать с disable: disable лишь убирает автозапуск, mask — запрещает вообще.
Таймеры и socket-активация
.timer — планировщик systemd (замена cron для юнитов)
Создаёт юнит, который вызывает .service по расписанию или через OnBootSec/OnActiveSec.
Пример: /etc/systemd/system/backup.timer и backup.service
backup.timer:
[Unit]
Description=Daily backup timer
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
backup.service — обычный сервис, исполняющий бэкап.
Запуск:
sudo systemctl enable --now backup.timer
systemctl list-timers
.socket — socket-activated services
systemd слушает сокет и запускает службу по подключению. Это экономит ресурсы и полезно для on-demand сервисов.
myapp.socket:
[Socket]
ListenStream=12345
[Install]
WantedBy=sockets.target
myapp@.service — можно настроить StandardInput=socket или использовать шаблон.
Жизненный цикл службы: нюансы
start— запускает юнит.stop— останавливает.restart— stop → start; полезно, когда нельзя reload.reload— попросить службу перечитать конфигурацию (еслиExecReload=задан и программа поддерживает).try-restart— перезапустить только если служба запущена.condrestart— как try-restart.reload-or-restart— reload если поддерживает, иначе restart.
Про daemon-reload: После любого изменения unit-файла или добавления — выполнить systemctl daemon-reload. Это не перезапускает службы — только перечитывает конфигурацию systemd.
Параметры перезапуска и поведение при падении
Restart= — ключевой для надежности:
no— не перезапускатьon-success— при успешном завершенииon-failure— при не-нулевом коде, сигнале, таймаутеon-abnormal— если завершение из-за сигнала/ошибкиon-abortalways— всегда перезапускать
Полезные опции:
RestartSec=— время ожидания перед перезапуском.StartLimitIntervalSec=иStartLimitBurst=— лимиты попыток запуска (защищают от спама рестартов).
Если служба «падает» часто, systemd пометит её failed; systemctl reset-failed сбросит флаг.
Безопасность: ограничиваем привилегии unit-ов
Systemd предоставляет много опций безопасности — используй их по мере возможности:
- Пользователь/группа:
User=,Group=. NoNewPrivileges=true— запрет на повышение привилегий через execve.PrivateTmp=true— отдельный /tmp для сервиса.ProtectSystem=full|strict— делает/usrи/bootдоступными только для чтения.ProtectHome=true— делает/home,/rootи/run/userдоступными только для чтения (или недоступными).ReadOnlyDirectories=/ReadWriteDirectories=— тонкая настройка.CapabilityBoundingSet=— набор доступных Linux-capabilities.RestrictAddressFamilies=— ограничение семей сокетов.SystemCallFilter=— белый/чёрный список syscalls (при поддержке ядра).SELinuxContext=— задавать SELinux контекст (если используется).
Рекомендация: по умолчанию запускай сервисы от неправавного пользователя и используй ProtectSystem, PrivateTmp и NoNewPrivileges когда возможно.
Отладка и логирование
systemctl status <unit>— кратко статус + последние строки journal.-
journalctl -u <unit>— все логи юнита.journalctl -u <unit> -b— с текущей загрузки.journalctl -u <unit> -f— follow, какtail -f.journalctl -u <unit> --since "2025-10-01 10:00"— по времени.
systemctl --failed— показать все упавшие юниты.systemctl show <unit>— выводит свойства в формате key=value (удобно для скриптов).systemd-analyze blameиsystemd-analyze critical-chain— узнать, что тормозит загрузку (полезно дляbootоптимизаций).strace,gdb— при необходимости для самого процесса (не в systemd).
Проверка переменных окружения:
systemctl show-environment— для systemd-environment.- Логи часто содержат переменные среды, переданные сервису.
Полезные приёмы и чеклист для продакшн-служб
- Drop-in вместо редактирования пакета — используем
systemctl edit. - Unit должен корректно реагировать на SIGTERM/SIGINT — systemd шлёт SIGTERM при stop.
- Укажите
Restart=on-failureи корректныеRestartSec=. - Ограничте ресурсы:
LimitNOFILE=,LimitNPROC=,CPUQuota=при необходимости. - Логи: пишите в stdout/stderr — systemd capture через journal.
- Healthcheck: используйте
WatchdogSec=+Type=notifyдля автоматического обнаружения зависания. - Тестирование: проверяйте
systemctl daemon-reload→systemctl start→journalctl -u. - Документируйте
Description=иDocumentation=в unit-файле. - Тестовый режим:
systemctl start --no-blockпри асинхронных стартах, но чаще — избегать. - CI/CD: при доставке юнитов через пакетный менеджер используйте
systemctl presetилиsystemctl enableв postinst.
Примеры unit-файлов
1) Простая web-служба (/etc/systemd/system/myweb.service)
[Unit]
Description=Simple HTTP server
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/srv/myweb
ExecStart=/usr/bin/python3 -m http.server 8080
Restart=on-failure
PrivateTmp=true
ProtectSystem=full
[Install]
WantedBy=multi-user.target
2) Форкающийся демон (Type=forking)
[Unit]
Description=Legacy daemon
[Service]
Type=forking
ExecStart=/usr/sbin/legacy-daemon -D
PIDFile=/var/run/legacy.pid
Restart=on-failure
3) Таймер + service (backup.timer + backup.service)
backup.timer:
[Unit]
Description=Daily backup timer
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
backup.service — запускает скрипт бэкапа.
Короткие ресурсы для дальнейшего чтения
man systemd.unit,man systemd.service,man systemctl,man systemd.exec
Заключение
Этот гайд даёт фундамент для:
- безопасного и корректного создания unit-файлов;
- надежного управления службами (enable/disable, mask/unmask);
- использования шаблонов, таймеров и socket-активации;
- настройки безопасности и отладки через
journalctl.