Введение / Зачем это нужно
Systemd — это система инициализации и менеджер служб, который используется по умолчанию в большинстве современных дистрибутивов Linux (Ubuntu, Fedora, Debian, CentOS). Вместо скриптов в /etc/init.d/ вы работаете с декларативными юнит-файлами (unit files). Этот подход даёт мощные возможности: управление зависимостями, параллельный запуск, автоматический перезапуск упавших процессов и централизованное логирование через journald.
В этом гайде вы научитесь создавать собственные systemd-сервисы для запуска ваших приложений, скриптов или демонов в фоне с контролем над их жизненным циклом.
Требования / Подготовка
Перед началом убедитесь, что:
- У вас есть доступ к терминалу Linux с правами sudo (администратора).
- Вы знакомы с базовыми командами редактирования файлов (
nano,vim). - Путь к исполняемому файлу или скрипту, который вы хотите запустить как сервис, известен и доступен.
- Дистрибутив использует systemd (проверить можно командой
pidof systemd).
Шаг 1: Создайте юнит-файл сервиса
Все пользовательские юнит-файлы сервисов размещаются в /etc/systemd/system/. Имя файла должно заканчиваться на .service и обычно совпадает с логическим именем сервиса.
# Перейдите в системную директорию для юнитов
cd /etc/systemd/system/
# Создайте файл сервиса (замените myapp на своё имя)
sudo nano myapp.service
⚠️ Важно: Не создавайте файлы напрямую в
/lib/systemd/system/— эта директория предназначена для пакетов дистрибутива. Ваши ручные правки в/etc/systemd/system/будут приоритетнее.
Шаг 2: Напишите конфигурацию юнит-файла
Юнит-файл состоит из нескольких секций. Вот минимальный, но рабочий шаблон:
[Unit]
Description=Мой кастомный сервис
Documentation=man:myapp(1)
After=network.target
[Service]
Type=simple
User=ваш_пользователь
Group=ваша_группа
ExecStart=/полный/путь/к/вашему/скрипту_или_бинарнику
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Разбор секций:
[Unit]— метаданные и зависимости.Description— краткое описание сервиса.After=— указывает, что этот сервис должен запускаться после указанных.network.target— частый вариант для сетевых приложений.Requires=— жёсткая зависимость (если указанный сервис упадёт, упадёт и этот).
[Service]— ядро конфигурации.Type=— тип сервиса.simple(по умолчанию) — процесс запускается и работает в foreground.forking— для демонов, которые делаютfork().User=/Group=— от имени кого запускать процесс. Крайне рекомендуется не запускать всё от root.ExecStart=— обязательная директива. Полный путь к исполняемому файлу или скрипту. Скрипт должен быть исполняемым (chmod +x скрипт.sh).Restart=— политика перезапуска.on-failure— перезапускать при ненулевом коде выхода.always— всегда.RestartSec=— задержка перед перезапуском в секундах.
[Install]— инструкции дляsystemctl enable.WantedBy=— определяет, в каком целевом состоянии (target) должен быть включён сервис.multi-user.target— стандартный многопользовательский режим (аналог runlevel 3/5).
💡 Совет: Для простых скриптов часто достаточно шаблона выше. Для Java-приложений или сложных сред может понадобиться
EnvironmentFile=(загрузка переменных окружения из файла) илиExecStartPre=(команда перед запуском).
Шаг 3: Перезагрузите конфигурацию systemd
После сохранения файла systemd должен «увидеть» новый юнит. Выполните:
sudo systemctl daemon-reload
Эта команда заставляет systemd перечитать все юнит-файлы с диска. Без неё systemctl будет работать со старой копией конфигурации.
Шаг 4: Включите и запустите сервис
Теперь можно активировать сервис.
- Включите для автозапуска (создаст симлинк в
/etc/systemd/system/multi-user.target.wants/):sudo systemctl enable myapp.service
ВыводCreated symlink /etc/systemd/system/multi-user.target.wants/myapp.service → /etc/systemd/system/myapp.service.означает успех. - Запустите немедленно без перезагрузки:
sudo systemctl start myapp.service
Шаг 5: Проверьте статус и логи
Убедитесь, что сервис работает штатно.
# Основная команда проверки
systemctl status myapp.service
Что искать в выводе:
Active: active (running)— сервис жив.Loaded: loaded (/etc/systemd/system/myapp.service; enabled; vendor preset: enabled)— файл загружен и включён.- Никаких красных строк
Failedилиinactive (dead).
Для детального просмотра логов используйте journalctl:
# Показать все логи сервиса (с самого начала)
sudo journalctl -u myapp.service
# Отслеживать логи в реальном времени (как tail -f)
sudo journalctl -u myapp.service -f
# Показать логи за последние 10 минут
sudo journalctl -u myapp.service --since "10 minutes ago"
Возможные проблемы
1. Ошибка Failed to start... или сервис сразу падает
- Причина: Ошибка в самом приложении/скрипте, который запускает
ExecStart. - Решение: Запустите команду из
ExecStartвручную в терминале, чтобы увидеть её вывод. Проверьте права на файл и пути к зависимым библиотекам/файлам. - Диагностика:
journalctl -u myapp.service -n 50 --no-pagerпокажет последние 50 строк логов сервиса.
2. Сервис не включается (enable создаёт symlink, но после reload статус disabled)
- Причина: В секции
[Install]отсутствуетWantedBy=илиRequiredBy=, либо указан неверный target. - Решение: Добавьте
WantedBy=multi-user.target(для фоновых служб) илиWantedBy=graphical.target(для GUI-приложений). Перевыполнитеdaemon-reloadиenable.
3. Сервис запускается, но не работает как ожидается (нет доступа к сети, файлам)
- Причина: Проблема с контекстом безопасности. Сервис запускается в изолированном окружении.
- Решение:
- Убедитесь, что
User=иGroup=указаны правильно. - Для доступа к сетевым портам <1024 могут потребоваться дополнительные capabilities (
AmbientCapabilities=CAP_NET_BIND_SERVICE) или запуск от root (не рекомендуется). - Проверьте, что у указанного пользователя есть права на чтение/запись в нужные директории.
- Убедитесь, что
4. Ошибка Dependency failed for...
- Причина: Сервис имеет зависимость (
After=,Requires=) от другой службы, которая не запустилась или не существует. - Решение: Проверьте статус зависимых служб (
systemctl status network.targetили вашей_зависимости.service). Убедитесь, что имена зависимостей написаны правильно.