Linux

Создание systemd-сервиса в Linux: полное пошаговое руководство

Это руководство подробно объясняет, как создать собственный системный сервис (демон) в Linux с помощью systemd. Вы научитесь писать unit-файлы, управлять сервисом (старт/стоп/статус), настраивать автозагрузку и логирование.

Обновлено 15 февраля 2026 г.
15-20 мин
Средняя
FixPedia Team
Применимо к:systemd (Ubuntu 22.04+, Debian 11+, CentOS 8+, RHEL 8+, Fedora 35+)Linux с systemd

Введение / Зачем это нужно

Systemd — это современная система инициализации и менеджер служб для большинства дистрибутивов Linux. Создание собственного сервиса (демона) позволяет автоматически запускать ваши скрипты или программы при загрузке системы, управлять их жизненным циклом (старт, стоп, перезагрузка), централизованно логировать вывод и обеспечивать восстановление при сбоях. Это стандартный и надёжный способ развёртывания фоновых задач в Linux.

После выполнения этого гайда вы сможете создать работающий сервис для любой исполняемой программы (Python-скрипт, bash-скрипт, бинарный файл), который будет:

  • Автоматически стартовать при загрузке ОС.
  • Корректно завершаться при выключении.
  • Писать логи в journald (системный журнал).
  • Перезапускаться при аварийном завершении.

Требования / Подготовка

Перед началом убедитесь, что:

  1. У вас есть доступ к терминалу с правами sudo (для системных сервисов) или доступ к домашней директории (для пользовательских).
  2. На системе установлен systemd (актуально для всех современных дистрибутивов: Ubuntu 22.04+, Debian 11+, CentOS 8/RHEL 8+, Fedora 35+).
  3. Исполняемый файл или скрипт, который нужно сервисировать, уже готов, протестирован вручную и имеет права на выполнение (chmod +x /путь/к/файлу).
  4. Вы знаете абсолютный путь к этому исполняемому файлу.

Шаг 1: Подготовка исполняемого скрипта или программы

Предположим, у вас есть простой bash-скрипт для мониторинга дискового пространства, который должен работать в фоне. Он уже создан и расположен по пути /opt/scripts/disk_monitor.sh.

#!/bin/bash
# Пример скрипта /opt/scripts/disk_monitor.sh
while true; do
    DATE=$(date '+%Y-%m-%d %H:%M:%S')
    df -h / | tail -n1 | awk '{print "ROOT: " $5 " used"}' >> /var/log/disk_monitor.log
    sleep 300
done

Проверьте его работоспособность вручную:

sudo chmod +x /opt/scripts/disk_monitor.sh
sudo /opt/scripts/disk_monitor.sh

Нажмите Ctrl+C для тестовой остановки. Убедитесь, что в /var/log/disk_monitor.log появляются записи.

Шаг 2: Создание unit-файла

Создайте файл сервиса. Для системного сервиса (работающего от root или указанного пользователя) используйте /etc/systemd/system/.

sudo nano /etc/systemd/system/disk-monitor.service

💡 Совет: Имя файла обычно совпадает с именем сервиса. Используйте латинские буквы, цифры, дефисы. Точка в имени не требуется, но допустима.

Шаг 3: Написание базовой конфигурации Unit и Service

Вставьте в редактор следующую конфигурацию. Она покрывает большинство базовых сценариев.

[Unit]
Description=Сервис мониторинга свободного места на корневом разделе
Documentation=man:df(1)
After=network.target

[Service]
Type=simple
ExecStart=/opt/scripts/disk_monitor.sh
Restart=on-failure
RestartSec=10
User=root
Group=root

[Install]
WantedBy=multi-user.target

Разбор секций:

  • [Unit] — метаданные и зависимости.
    • Description — краткое описание сервиса (показывается в systemctl status).
    • After — указывает, что сервис должен стартовать после включения сети (network.target). Для не-сетевых сервисов можно убрать или указать local-fs.target (после монтирования локальных ФС).
  • [Service] — основная конфигурация процесса.
    • Type=simple (по умолчанию) — systemd считает, что процесс, указанный в ExecStart, является основным и работает в foreground. Подходит для большинства скриптов и современных программ.
    • ExecStartабсолютный путь к команде/скрипту для запуска. Все аргументы указываются здесь.
    • Restart=on-failure — автоматически перезапускать сервис, если он завершился с ненулевым кодом возврата.
    • RestartSec=10 — ждать 10 секунд перед перезапуском.
    • User/Group — от имени какой пользователя/группы запускать процесс. Безопаснее указывать не-root пользователя (например, User=monitoruser), если в этом нет необходимости. Для системных утилит может потребоваться root.
  • [Install] — инструкции для systemctl enable.
    • WantedBy=multi-user.target — создаст симлинк в /etc/systemd/system/multi-user.target.wants/, что означает "запускать при загрузке в многопользовательском режиме (стандартный)". Для графических сервисов может использоваться graphical.target.

Сохраните файл (Ctrl+O, Enter) и закройте редактор (Ctrl+X).

Шаг 4: Настройка автозагрузки и инициализация

После создания или изменения unit-файла обязательно выполните команду перезагрузки конфигурации systemd:

sudo systemctl daemon-reload

Теперь включите сервис в автозагрузку (создаст симлинк):

sudo systemctl enable disk-monitor.service

Вывод: Created symlink /etc/systemd/system/multi-user.target.wants/disk-monitor.service → /etc/systemd/system/disk-monitor.service.

Шаг 5: Запуск и проверка статуса

Запустите сервис вручную:

sudo systemctl start disk-monitor.service

Проверьте его статус:

sudo systemctl status disk-monitor.service

Ожидаемый вывод (упрощённо):

● disk-monitor.service - Сервис мониторинга свободного места на корневом разделе
   Loaded: loaded (/etc/systemd/system/disk-monitor.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2026-02-15 14:30:00 MSK; 5s ago
 Main PID: 12345 (bash)
    Tasks: 1 (limit: 4915)
   Memory: 1.2M
   CGroup: /system.slice/disk-monitor.service
           └─12345 /bin/bash /opt/scripts/disk_monitor.sh

Ключевые строки:

  • Loaded — файл загружен, enabled — включён в автозагрузку.
  • Active: active (running) — сервис работает.
  • Main PID — PID основного процесса.
  • CGroup — cgroup, в который помещён процесс.

Шаг N: Дополнительные операции управления

Теперь вы можете управлять сервисом стандартными командами:

  • Остановить: sudo systemctl stop disk-monitor.service
  • Перезапустить: sudo systemctl restart disk-monitor.service (используйте, если меняли конфиг).
  • Перезагрузить: sudo systemctl reload disk-monitor.service (если сервис поддерживает SIGHUP для перечитывания конфига без полной остановки).
  • Показать логи: sudo journalctl -u disk-monitor.service -f (-f — следить за новыми записями в реальном времени).
  • Проверить конфигурацию на синтаксис: sudo systemctl daemon-reload (выполняется автоматически при enable/start, но полезно после ручного редактирования файла).

Проверка результата

  1. Автозапуск: Перезагрузите систему (sudo reboot). После входа проверьте статус сервиса: systemctl status disk-monitor.service. Он должен быть active (running).
  2. Логирование: Убедитесь, что логи пишутся: sudo tail -f /var/log/disk_monitor.log или через journald: sudo journalctl -u disk-monitor.service.
  3. Автоматическое восстановление: Принудительно завершите процесс (например, sudo kill <PID> из status). Через несколько секунд проверьте статус снова — systemd должен его перезапустить.

Возможные проблемы

Проблема: systemctl status показывает failed (Result: exit-code). Решение: Посмотрите детали ошибки в том же выводе status (строка ...). Чаще всего это:

  • Неправильный путь в ExecStart. Убедитесь, что путь абсолютный и файл существует.
  • Нет прав на выполнение. sudo chmod +x /путь/к/скрипту.
  • Ошибка внутри скрипта. Запустите скрипт вручную от того же пользователя (sudo -u <user> /путь/к/скрипту) и проверьте вывод.
  • Зависимости. Если скрипту нужен доступ к сети или смонтированным дискам, проверьте After= и Requires= в секции [Unit].

Проблема: Сервис не включается в автозагрузку (systemctl is-enabled возвращает disabled). Решение: Выполните sudo systemctl enable disk-monitor.service ещё раз после daemon-reload. Убедитесь, что в [Install] есть секция WantedBy= или RequiredBy=.

Проблема: Логи сервиса пустые в journalctl. Решение: По умолчанию systemd перехватывает stdout/stderr. Если скрипт пишет напрямую в файл (как в примере), в journald его вывод не попадёт. Это нормально. Для логирования через journald уберите перенаправление в файл из скрипта, а для постоянного хранения логов настройте journalctl с ротацией или используйте StandardOutput=append:/var/log/disk_monitor.log в секции [Service].

Проблема: Сервис запускается, но сразу завершается. Решение: Это часто бывает при Type=simple, если основной процесс завершается. Для долгоживущих скриптов убедитесь, что в них есть бесконечный цикл или ожидание (sleep). Если программа сама демонизируется (fork), может потребоваться Type=forking и PIDFile=/var/run/имя.pid. Но для простых скриптов с циклом Type=simple — правильный выбор.

Часто задаваемые вопросы

Где правильно размещать пользовательские unit-файлы?
Почему мой сервис не запускается после создания?
Как сделать сервис, который запускается от конкретного пользователя, а не от root?
Что такое `Type=forking` и когда он нужен?

Полезное

Подготовка исполняемого скрипта или программы
Создание unit-файла
Написание базовой конфигурации [Unit] и [Service]
Настройка автозагрузки и инициализация
Запуск и проверка статуса