VK Cloud

systemctl и journalctl: управление сервисами и логами в Linux

12 октября 2026 г.
Александр Иванов
Автор статьи
_blog_head_13.png

systemd управляет запуском и работой процессов в большинстве современных Linux-дистрибутивов и работает как первый процесс системы с PID 1 (документация systemd). systemctl — основной инструмент взаимодействия с systemd, journalctl читает его централизованный журнал. Без этих двух команд администрирование сервера на Ubuntu, CentOS, Debian или Fedora превращается в угадывание: непонятно, почему сервис не поднялся после перезагрузки, куда делись логи приложения и чем reload отличается от restart в три часа ночи во время инцидента.

Разберём модель юнитов systemd, команды, сгруппированные по задачам, и пошаговый сценарий диагностики упавшего сервиса.

systemd пришёл на смену SysV init и Upstart и стал основной системой инициализации в большинстве распространённых дистрибутивов. Он запускается первым процессом (PID 1) и дальше запускает и контролирует остальные процессы системы. Отсюда и логика systemctl: вы обращаетесь не к скрипту в /etc/init.d/, а к менеджеру, который держит у себя полную картину зависимостей и состояний.

Юнит (unit) — ресурс, которым systemd управляет и за которым следит. Конфигурация юнита описывается в unit-файле определённого формата, а тип юнита определяется суффиксом имени файла (systemd.unit(5)).

Тип юнитаЧто описывает
*.service*Процесс или демон: как запустить, как остановить, как перезапустить
*.socket*Сокет IPC или сетевой сокет для socket-активации
*.mount*Точка монтирования файловой системы
*.timer*Таймер, который активирует другой юнит по расписанию
*.target*Группа юнитов для синхронизации точек запуска, аналог runlevel

Источник правды — unit-файлы на диске. Файлы системных пакетов лежат в /usr/lib/systemd/system/ (на части дистрибутивов этот каталог доступен по симлинку /lib/systemd/system/), а файлы, которые создаёт администратор или устанавливает вручную, в /etc/systemd/system/. При совпадении имён побеждает файл из /etc. Практический вывод: пакетный юнит не правят на месте, его переопределяют своей версией в /etc/systemd/system/, и обновление пакета не затрёт изменения.

Отдельного внимания заслуживает .target. Это аналог runlevel из SysV: группа юнитов, которую systemd поднимает как единую точку синхронизации. multi-user.target отвечает за многопользовательский режим без графики, типовое состояние сервера. graphical.target добавляет к нему графическую сессию. rescue.target поднимает минимальный режим восстановления. Когда в секции [Install] своего сервиса вы пишете WantedBy=multi-user.target, вы говорите: «подними меня, когда система дойдёт до многопользовательского режима».

Запуск, остановка, перезапуск

# Запустить сервис sudo systemctl start nginx # Остановить сервис sudo systemctl stop nginx # Перезапустить сервис (с прерыванием работы) sudo systemctl restart nginx # Перечитать конфигурацию без остановки процесса sudo systemctl reload nginx # Перечитать конфиг, а если reload не поддерживается — перезапустить sudo systemctl reload-or-restart nginx

Разница между restart и reload критична на боевом сервере. restart останавливает процесс и запускает его заново: все текущие соединения рвутся. reload посылает процессу сигнал перечитать конфигурацию без полной остановки и запуска, но работает это только тогда, когда в unit-файле задана директива ExecReload (systemctl(1)). Для nginx и PostgreSQL это рабочий сценарий правки конфигурации под нагрузкой: клиенты не замечают изменений.

Если вы пишете скрипт развёртывания и не уверены, поддерживает ли сервис перечитывание конфига, берите reload-or-restart: команда перечитает конфигурацию там, где это возможно, и выполнит полный перезапуск там, где нет.

Статус сервиса

sudo systemctl status nginx

Типовой вывод выглядит так:

● nginx.service - A high performance web server and a reverse proxy server Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled) Active: active (running) since Mon 2026-03-02 09:14:21 MSK; 2h 11min ago Main PID: 1284 (nginx) Tasks: 5 (limit: 4631) Memory: 12.4M CPU: 1.203s CGroup: /system.slice/nginx.service ├─1284 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; └─1285 nginx: worker process Mar 02 09:14:21 web-01 systemd[1]: Starting nginx.service... Mar 02 09:14:21 web-01 systemd[1]: Started nginx.service.

Что читать построчно:

  • Loaded: — найден ли unit-файл, по какому пути он загружен и включён ли автозапуск (enabled / disabled / masked). Если здесь not-found, вы ошиблись в имени юнита либо забыли daemon-reload после создания файла.
  • Active: — текущее состояние и время с момента перехода в него.
  • Main PID — PID основного процесса, с которым systemd сопоставляет жизненный цикл сервиса.
  • Нижние строки — хвост журнала по этому юниту, тот же, что отдаёт journalctl -u nginx.

Состояния в строке Active::

СостояниеЧто означает
active (running)Процесс запущен и работает
active (exited)Команда отработала и завершилась; нормальное состояние для одноразовых юнитов типа oneshot
inactive (dead)Юнит не запущен
activatingЮнит в процессе запуска, готовность ещё не подтверждена
failedПроцесс завершился с ошибкой; рядом будет код выхода или сигнал

В скриптах удобнее не парсить вывод, а опираться на код возврата: systemctl is-active, systemctl is-enabled и systemctl is-failed отвечают коротко и предсказуемо.

Автозапуск

# Включить автозапуск при старте системы sudo systemctl enable nginx # Включить и сразу запустить sudo systemctl enable --now nginx # Отключить автозапуск sudo systemctl disable nginx # Отключить и сразу остановить sudo systemctl disable --now nginx # Запретить запуск полностью (маскировка) sudo systemctl mask nginx # Снять маскировку sudo systemctl unmask nginx

enable создаёт символические ссылки, которые включают юнит в целевые target-юниты согласно секции [Install]: так сервис и попадает в автозапуск при загрузке. disable эти ссылки удаляет. Важное следствие: enable не запускает сервис здесь и сейчас, для этого нужен флаг --now или отдельный start.

mask работает жёстче: юнит заменяется символической ссылкой на /dev/null, после чего запустить его невозможно ни автоматически, ни вручную, пока не выполнен unmask. Это инструмент против «воскресающих» сервисов, которые поднимаются зависимостями других юнитов или скриптами пакета. Если systemctl start отвечает, что юнит замаскирован, ищите причину в чьём-то давнем mask, а не в конфиге сервиса.

Шпаргалка: управление сервисом

КомандаДействие
systemctl start <unit>Запустить
systemctl stop <unit>Остановить
systemctl restart <unit>Перезапустить с прерыванием
systemctl reload <unit>Перечитать конфигурацию
systemctl reload-or-restart <unit>Перечитать конфиг или перезапустить
systemctl status <unit>Статус и хвост журнала
systemctl enable <unit>Включить автозапуск
systemctl enable --now <unit>Включить автозапуск и запустить
systemctl disable <unit>Отключить автозапуск
systemctl mask <unit>Заблокировать запуск
systemctl unmask <unit>Снять блокировку
systemctl is-active <unit>Активен? (код возврата)
systemctl is-enabled <unit>Включён автозапуск? (код возврата)
systemctl is-failed <unit>Упал? (код возврата)

Когда на сервере несколько десятков сервисов, точечные status помогают плохо. Нужен обзор.

# Список активных юнитов systemctl list-units # Все юниты, включая неактивные systemctl list-units --all # Только сервисы systemctl list-units --type=service # Только упавшие юниты systemctl list-units --state=failed # Все установленные unit-файлы и их состояние (enabled/disabled/masked) systemctl list-unit-files # Дерево зависимостей юнита systemctl list-dependencies nginx

Разница между list-units и list-unit-files часто сбивает с толку. Первая команда показывает юниты, которые systemd загрузил в память, вторая — файлы на диске вместе с состоянием автозапуска. Если сервис установлен, но никогда не запускался и не включён, искать его стоит во второй выдаче.

list-units --state=failed стоит выполнять первой после любого инцидента и после перезагрузки сервера: она за секунду показывает, что не поднялось.

list-dependencies разворачивает дерево того, что должно быть поднято до юнита. Для сервиса, который «иногда стартует, иногда нет», это основной инструмент: почти всегда проблема в порядке запуска относительно сети или базы данных.

# Перечитать unit-файлы с диска после их изменения sudo systemctl daemon-reload # Перезагрузить систему sudo systemctl reboot # Выключить sudo systemctl poweroff # Перевести систему в режим восстановления sudo systemctl rescue # Текущий target по умолчанию (аналог runlevel) systemctl get-default # Сменить target по умолчанию sudo systemctl set-default multi-user.target

set-default multi-user.target на сервере со случайно установленным графическим окружением экономит и память, и время загрузки.

Важно знать

daemon-reload перезагружает конфигурацию systemd из файлов на диске. Без него демон продолжает работать с ранее загруженной версией конфигурации, поэтому команда обязательна после каждого создания или ручного изменения unit-файла (systemctl(1)). Самая частая ошибка новичка выглядит так: файл отредактирован, systemctl restart выполнен, поведение прежнее — потому что systemd перезапустил старую версию юнита из памяти.


journalctl показывает содержимое журнала systemd, который ведёт служба systemd-journald и хранит в структурированном бинарном формате (journalctl(1)). По умолчанию журнал лежит в /var/log/journal/ при постоянном хранении либо в /run/log/journal/, если выбран режим хранения только в памяти до перезагрузки; режим задаётся директивой Storage= в конфигурации journald (journald.conf(5)).

Отсюда главное отличие от плоского /var/log/syslog: запись в журнале не строка текста, а структура с метаданными (PID, UID, имя юнита, приоритет). Поэтому фильтрация встроена в сам инструмент, и связки grep | awk | sed для базовых задач не нужны.

Базовый просмотр

# Весь журнал с начала journalctl # Последние 50 записей journalctl -n 50 # Следить за новыми записями в реальном времени journalctl -f # Журнал в обратном порядке: свежие записи сверху journalctl -r

journalctl -f работает как tail -f: выводит новые записи по мере поступления. Связка -n 100 -f удобна при развёртывании: сначала контекст последних ста строк, дальше поток в реальном времени.

Фильтрация по сервису

# Логи конкретного сервиса journalctl -u nginx # Логи сервиса в реальном времени journalctl -u nginx -f # Логи нескольких сервисов в одной ленте journalctl -u nginx -u postgresql

Опция -u фильтрует записи по конкретному юниту и может указываться несколько раз, объединяя логи нескольких сервисов в общую хронологическую ленту. Для отладки связки «веб-сервер + база» это ценно: видно, что запросы nginx начали падать ровно в момент, когда PostgreSQL ушёл в перезапуск.

Фильтрация по времени

# За сегодня journalctl --since today # С конкретного момента journalctl --since "2026-03-02 10:00:00" # За интервал journalctl --since "2026-03-02 10:00:00" --until "2026-03-02 11:00:00" # За последний час journalctl --since "1 hour ago" # С текущей загрузки системы journalctl -b # С предыдущей загрузки journalctl -b -1 # Список всех зафиксированных загрузок journalctl --list-boots

Опции --since и --until принимают и абсолютные даты формата YYYY-MM-DD HH:MM:SS, и относительные выражения вида yesterday, now, 1 hour ago. Опция -b ограничивает вывод одной загрузкой: без аргумента или с 0 показывает текущую, с -1 предыдущую. Команда --list-boots выводит перечень загрузок с идентификаторами.

Пара -b -1 незаменима после внезапной перезагрузки: журнал текущей загрузки о причинах падения не расскажет, а предыдущий расскажет.

Фильтрация по приоритету

# Ошибки и всё более критичное journalctl -p err # Предупреждения и выше journalctl -p warning # Диапазон приоритетов: от err до info journalctl -p 3..6

Опция -p фильтрует записи по уровню важности в терминах syslog. Указание одного уровня включает его и все более критичные; поддерживается и диапазон вида 3..6.

ЧислоУровеньКогда применяется
0emergСистема неработоспособна
1alertТребуется немедленное вмешательство
2critКритические условия
3errОшибки
4warningПредупреждения
5noticeНормальные, но значимые события
6infoИнформационные сообщения
7debugОтладочная информация

На боевом сервере с разговорчивым приложением journalctl -u myapp -p err -b сокращает тысячи строк до десятка значимых.

Форматы вывода

# Компактный формат по умолчанию journalctl -o short # С точностью до микросекунд journalctl -o short-precise # JSON — для парсинга и пересылки во внешние системы journalctl -o json # JSON с отступами — для чтения глазами journalctl -o json-pretty # Только текст сообщения, без метаданных journalctl -o cat

Опция -o задаёт формат вывода: доступны short (по умолчанию), short-precise с микросекундами, json, json-pretty, cat и другие. Формат json служит мостом к внешнему сбору логов: вывод уходит в конвейер обработки без разбора текстовых строк регулярными выражениями. Формат cat удобен, когда нужно показать разработчику стек-трейс приложения без служебных префиксов.

Управление размером журнала

# Сколько места занимает журнал journalctl --disk-usage # Сжать журнал до указанного размера sudo journalctl --vacuum-size=500M # Удалить записи старше 30 дней sudo journalctl --vacuum-time=30d # Оставить не более 5 файлов журнала sudo journalctl --vacuum-files=5

--disk-usage показывает суммарный объём всех файлов журнала. Три опции --vacuum-* удаляют старые архивные файлы: по общему размеру, по возрасту записей или по количеству файлов.

Разовая очистка решает проблему на сегодня, но не на завтра. Постоянные ограничения задаются в /etc/systemd/journald.conf: директива SystemMaxUse= ограничивает максимальный объём дискового пространства под постоянный журнал, MaxRetentionSec= задаёт максимальный срок хранения записей (journald.conf(5)). После правки конфигурации службу журналирования нужно перезапустить:

sudo systemctl restart systemd-journald

Сервис myapp.service не отвечает. Последовательность ниже доводит до причины за несколько минут и не требует припоминания редких флагов.

  1. Статус.
sudo systemctl status myapp.service

Смотрим три вещи: строку Active: (ожидаем увидеть failed и код выхода или сигнал), строку Loaded: (не замаскирован ли юнит, включён ли автозапуск) и хвост журнала внизу вывода. Часто этого хватает: в последних строках лежит сообщение об отсутствующем файле конфигурации или занятом порте.

  1. Полный журнал текущей загрузки.
journalctl -u myapp.service -b

Хвост из status обрезан, здесь видна вся история юнита с момента загрузки системы.

  1. Сузить до ошибок.
journalctl -u myapp.service -p err -b

Если приложение пишет много информационных сообщений, фильтр по приоритету отсекает шум.

  1. Момент старта.
journalctl -u myapp.service --since "5 minutes ago"

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

  1. Зависимости.
systemctl list-dependencies myapp.service

Проверяем, активны ли юниты, от которых сервис зависит. Типичная картина: приложение стартует раньше, чем PostgreSQL принимает соединения, и падает на инициализации пула.

  1. Синтаксис unit-файла.
systemd-analyze verify /etc/systemd/system/myapp.service

Команда проверяет корректность указанного unit-файла и сообщает об ошибках конфигурации, причём запускать юнит для этого не требуется (systemd-analyze(1)). Опечатка в имени директивы ловится здесь, а не методом перебора.

  1. Ручной запуск под наблюдением.
# В первом терминале journalctl -u myapp.service -f # Во втором sudo systemctl start myapp.service

Два терминала дают точную картину: видно, в каком порядке идут сообщения и на какой секунде процесс умирает. После правки unit-файла не забывайте sudo systemctl daemon-reload, иначе вы перезапускаете прежнюю конфигурацию.


Минимальный рабочий unit-файл для Python-приложения. Путь: /etc/systemd/system/myapp.service.

[Unit] Description=My Python Application After=network.target postgresql.service Requires=postgresql.service [Service] Type=simple User=myapp WorkingDirectory=/opt/myapp ExecStart=/opt/myapp/venv/bin/python app.py Restart=on-failure RestartSec=5 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target

Что делает каждая ключевая директива:

  • After= задаёт только порядок запуска относительно других юнитов и сам по себе зависимости активации не создаёт. Чтобы требуемый юнит действительно был поднят, нужна отдельная директива Requires= или Wants= (systemd.unit(5)). Пара After=postgresql.service и Requires=postgresql.service читается так: «базу поднять обязательно и раньше меня». Строчка After= без Requires= — распространённая причина сервиса, который работает после ручного старта и не работает после перезагрузки.
  • Type= описывает модель процесса. При simple процесс считается запущенным сразу после запуска исполняемого файла. При forking процесс делает fork, родитель завершается, а основным считается дочерний процесс. При notify процесс сам сообщает systemd о готовности через sd_notify (systemd.service(5)). Для приложения, которое остаётся в переднем плане, подходит simple; для классического демона, уходящего в фон, forking.
  • Restart=on-failure перезапускает процесс при ненулевом коде выхода, получении сигнала, таймауте или неудачной проверке готовности, а RestartSec= задаёт паузу перед следующей попыткой. Пауза в пять секунд избавляет от цикла мгновенных перезапусков, когда база ещё не готова принимать соединения.
  • StandardOutput=journal и StandardError=journal направляют стандартный вывод и поток ошибок процесса в журнал systemd, откуда они доступны через journalctl (systemd.exec(5)). Отдельный файл лога приложению при этом не нужен: ротацию и ограничение объёма берёт на себя journald.

После создания файла:

sudo systemctl daemon-reload sudo systemctl enable --now myapp.service sudo systemctl status myapp.service

Первая команда заставляет systemd перечитать файлы с диска, вторая включает автозапуск и сразу поднимает сервис, третья подтверждает результат.

КомандаДействие
journalctl -u nginxЛоги сервиса nginx
journalctl -u nginx -fСледить за логами nginx в реальном времени
journalctl -bЛоги текущей загрузки
journalctl -b -1Логи предыдущей загрузки
journalctl -p errТолько ошибки и более критичное
journalctl --since todayЛоги за сегодня
journalctl -n 100Последние 100 записей
journalctl -o jsonВывод в JSON для парсинга
journalctl --disk-usageОбъём журнала на диске
journalctl --vacuum-size=1GСжать журнал до 1 ГБ

Частые вопросы про systemctl и journalctl

Чем journalctl отличается от просмотра /var/log/syslog?

journalctl читает бинарный журнал systemd, который ведёт служба systemd-journald и хранит записи в структурированном виде. Благодаря метаданным (PID, UID, имя юнита, приоритет) фильтрация по сервису, времени и уровню важности встроена в сам инструмент. /var/log/syslog — плоский текстовый файл, в который часть сообщений пишет rsyslog; структура там теряется, и работать приходится текстовым поиском.

Почему после изменения .service-файла сервис работает по-старому?

Потому что пропущен sudo systemctl daemon-reload. Эта команда перезагружает конфигурацию systemd из файлов на диске, и без неё демон продолжает использовать ранее загруженную версию. Правильная последовательность: отредактировать файл, выполнить daemon-reload, затем sudo systemctl restart myapp.

Как не дать логам занять весь диск?

Задать постоянные ограничения в /etc/systemd/journald.conf: SystemMaxUse= ограничивает объём дискового пространства под постоянный журнал, MaxRetentionSec= задаёт срок хранения записей. После правки выполнить sudo systemctl restart systemd-journald. Для разовой чистки подойдут journalctl --vacuum-size=, --vacuum-time= и --vacuum-files=, которые удаляют старые архивные файлы журнала.

В чём разница между systemctl reload и systemctl restart?

restart останавливает процесс и запускает его заново, поэтому текущие соединения обрываются. reload посылает процессу сигнал перечитать конфигурацию без остановки, но работает только если в unit-файле определена директива ExecReload. Поддержку перечитывания конфига стоит сверять с документацией конкретного сервиса; универсальный вариант для скриптов — reload-or-restart.

Почему сервис не поднимается автоматически при старте системы?

Сначала проверьте systemctl is-enabled myapp: если ответ disabled, автозапуск не включён и нужен systemctl enable; если masked, юнит заблокирован ссылкой на /dev/null и требуется unmask. Если автозапуск включён, а сервис всё равно падает, смотрите journalctl -u myapp -b и systemctl status myapp. Частая причина кроется в порядке запуска: директива After= задаёт только очерёдность, а фактический запуск требуемого юнита обеспечивают Requires= или Wants=.

systemctl и journalctl закрывают основной объём задач по управлению сервисами на современном Linux: запуск и остановку, автозапуск, разбор зависимостей, чтение и фильтрацию логов. Команды запоминаются легче, когда за ними видна модель: юнит описан файлом на диске, состояние хранит systemd в памяти, журнал пишет journald, а daemon-reload синхронизирует диск с памятью. Если эта модель уже уложилась, следующий шаг — таймеры .timer как замена cron и переопределение пакетных юнитов через systemctl edit.

Для запуска собственных сервисов нужен сервер, который не придётся чинить вместе с приложением. Подойдут облачные серверы Cloud Servers в VK Cloud: развёртывание инфраструктуры за несколько минут, открытые ОС Linux из каталога платформы и загрузка собственных образов, управление через веб-консоль, CLI или Terraform-провайдер, SLA 99,95% с финансовыми гарантиями. Конфигурацию виртуальной машины можно изменить и после запуска: добавить CPU, RAM или увеличить диск, при этом машина перезагружается.

Оставьте заявку, чтобы получить консультацию

Наши специалисты свяжутся с вами в ближайшее время и ответят на все вопросы.

            Узнавайте о выходе новых статей в блоге первыми!

            Будем держать в курсе новостей и облачных трендов

            section-subscribe_2x.png
              section-subscribe_2x.png
              Теги: Linux, systemd, systemctl, journalctl, VK Cloud
              Ссылка скопирована
              Поделиться
              40+ готовых сервисов