SSD Nodes Learn Hosting plans →
Посібники Matt ConnorВід Matt Connor

Як керувати службами Linux через systemctl: гід для VPS

Запуск, зупинка й перезапуск служб, reload проти restart, enable, mask, daemon-reload і перевірки для скриптів. Усе показано на власному демо-юніті, який легко прибрати.

Як керувати службами Linux через systemctl

Керувати службами Linux через systemctl просто. Одна команда запускає, зупиняє й перезапускає службу, вмикає автозапуск після перезавантаження і показує стан. Нижче кожну команду показано на маленькій демо-службі, тому нічого важливого на сервері ви не зламаєте.

Команди однакові на Ubuntu 24.04 і Ubuntu 26.04. Вони працюють і на інших дистрибутивах із systemd, бо systemctl входить до самого systemd.

Що таке systemd і чим він відрізняється від systemctl?

systemd це система ініціалізації (init), тобто перша програма, яку запускає ядро після старту. Вона отримує PID 1 (process identifier, номер процесу) і запускає все інше: мережу, журнал, базу даних, вашу програму. Після запуску systemd і далі стежить за кожною службою. Якщо процес служби завершився, systemd це бачить і записує причину в журнал.

systemctl не те саме, що systemd. Це клієнт: невелика програма, яка надсилає запит до systemd і друкує відповідь. Коли ви пишете sudo systemctl restart, перезапуск виконує сам systemd. systemctl лише передає йому прохання.

systemd керує юнітами (unit). Юніт це опис одного об'єкта, яким керує systemd. Служба (service) це юніт із суфіксом .service. Є й інші типи юнітів, наприклад .timer, .socket і .target, але тут ми працюємо лише зі службами. Якщо не вказати суфікс, systemctl сам додасть .service, тож demo-sleep і demo-sleep.service означають одне й те саме.

Звідки systemd узявся, що він замінив і чому навколо нього стільки суперечок, розповідає історія systemd від SysV init до сьогодні.

Демо-юніт: безпечне місце для вправ

Вчитися на справжній службі ризиковано. Якщо зупинити SSH на віддаленому сервері, нові підключення перестануть працювати. Тому створимо власну службу, яка нічого не робить. Вона запускає sleep infinity і просто чекає. Зламати нею нічого не вийде, а прибрати її можна трьома командами наприкінці.

Свої юніти зазвичай кладуть у /etc/systemd/system. Демо-юніт ми свідомо кладемо в /usr/local/lib/systemd/system. systemd читає й цей каталог, і там юніт поводиться як служба, встановлена з пакета. Це потрібно для розділу про mask: ця команда створює файл-посилання в /etc/systemd/system під іменем юніта. Якщо там уже лежить справжній файл юніта, створити посилання на тому самому місці не вийде.

sudo install -d -m 755 /usr/local/lib/systemd/system
sudo tee /usr/local/lib/systemd/system/demo-sleep.service > /dev/null <<'EOF'
[Unit]
Description=Demo service for systemctl practice

[Service]
ExecStart=/usr/bin/sleep infinity

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
systemctl cat demo-sleep.service --no-pager

ExecStart каже, яку програму запустити. WantedBy=multi-user.target каже, до якої цілі (target) приєднати службу, коли ви ввімкнете автозапуск. systemctl cat друкує юніт так, як його бачить systemd, разом зі шляхом до файлу.

Для зовсім нового файлу daemon-reload не завжди обов'язковий, бо невідомий юніт systemd читає з диска при першому зверненні. Але для змінених файлів він потрібен. Тому виконуйте його після кожної зміни файлів юнітів. Це звичка, яка нічого не ламає.

Деякі команди нижче в певному стані відповідають «ні» ненульовим кодом повернення. Щоб блок, вставлений у термінал або в скрипт із set -e, дійшов до кінця, після таких команд стоїть || true.

Як запустити, зупинити й перезапустити службу

Команди, які змінюють стан служби, потребують sudo. Команди, які лише читають стан, працюють і без нього.

sudo systemctl start demo-sleep.service
systemctl status demo-sleep.service --no-pager

status показує, чи служба працює, з якого часу, який у неї головний процес, і кілька останніх рядків журналу. --no-pager друкує все одразу. Без нього довгий вивід у терміналі відкривається в програмі перегляду less, і треба натиснути q, щоб вийти.

Тепер перезапустимо службу й подивимося на номер її головного процесу до і після:

systemctl show -p MainPID --value demo-sleep.service
sudo systemctl restart demo-sleep.service
systemctl show -p MainPID --value demo-sleep.service
sudo systemctl stop demo-sleep.service
systemctl status demo-sleep.service --no-pager || true

systemctl show -p MainPID --value друкує лише номер головного процесу. Після restart номер інший, бо restart зупиняє старий процес і запускає новий.

stop надсилає процесу сигнал SIGTERM і чекає, поки той завершиться. systemd тримає всі процеси служби в окремій cgroup (control group, група процесів у ядрі). Тому stop зупиняє й дочірні процеси, які служба запустила сама.

Є ще try-restart. Вона перезапускає службу лише тоді, коли та вже працює. Зупинену службу вона не чіпає.

Чим reload відрізняється від restart і коли брати reload-or-restart

restart завершує процес і запускає новий. На час перезапуску служба недоступна, а відкриті з'єднання обриваються. reload просить процес, що вже працює, перечитати свою конфігурацію без зупинки. Номер процесу не змінюється, з'єднання залишаються.

Але reload працює лише тоді, коли юніт описує, як саме перезавантажити програму. Для цього є рядок ExecReload=. У нашому демо-юніті такого рядка немає:

sudo systemctl start demo-sleep.service
sudo systemctl reload demo-sleep.service || true
systemctl is-active demo-sleep.service || true

systemctl відмовиться виконати reload, бо юніт не каже, як це зробити. Сама служба при цьому працює далі. Для такої ситуації є reload-or-restart. Ця команда робить reload, якщо юніт його підтримує, а інакше робить restart:

systemctl show -p MainPID --value demo-sleep.service
sudo systemctl reload-or-restart demo-sleep.service
systemctl show -p MainPID --value demo-sleep.service

Порівняйте номери процесу. reload тут недоступний, тому systemctl виконав restart.

Яку команду обрати для справжньої служби? Після зміни конфігурації програми, яка підтримує reload (nginx, PostgreSQL), беріть reload: користувачі нічого не помітять. Після оновлення самої програми потрібен restart, бо reload не завантажує новий виконуваний файл. У скриптах і в автоматизації, де ви не знаєте, що підтримує служба, беріть reload-or-restart.

Ви змінили юніт-файл: навіщо daemon-reload

systemd читає юніт-файл і тримає його опис у пам'яті. Якщо ви змінили файл на диску, systemd працює зі старим описом, доки ви не виконаєте daemon-reload. Перевіримо це: додамо в демо-юніт рядок ExecReload=. Програма /usr/bin/true нічого не робить і завершується успішно. У справжньої служби тут стоїть команда, яка просить програму перечитати конфігурацію.

sudo sed -i '/^ExecStart=/a ExecReload=/usr/bin/true' /usr/local/lib/systemd/system/demo-sleep.service
systemctl show -p NeedDaemonReload demo-sleep.service
sudo systemctl daemon-reload
systemctl show -p NeedDaemonReload demo-sleep.service

Властивість NeedDaemonReload показує, чи файл на диску новіший за опис у пам'яті systemd. Порівняйте значення до і після daemon-reload. systemctl status теж попереджає про таку ситуацію окремим рядком. Побачили там попередження про зміну файлу на диску, отже, пора виконати daemon-reload.

Тепер reload працює:

systemctl show -p MainPID --value demo-sleep.service
sudo systemctl reload demo-sleep.service
systemctl show -p MainPID --value demo-sleep.service

Цього разу номер процесу той самий, бо служба не перезапускалася.

Запам'ятайте одну річ: daemon-reload не перезапускає служби. Він оновлює лише описи юнітів. Якщо ви змінили ExecStart, процес, що працює, далі працює зі старою командою, доки ви не зробите restart.

Як увімкнути автозапуск: enable, disable і enable --now

start запускає службу зараз. Після перезавантаження сервера вона сама не запуститься, доки ви не ввімкнете автозапуск. Це робить enable. Команда створює символьне посилання в каталозі /etc/systemd/system/multi-user.target.wants/. Коли сервер завантажується до multi-user.target, systemd запускає все, на що вказують посилання в цьому каталозі.

Якщо у вас удома є ще й власний сервер, ви добре знаєте ціну цієї різниці після кожного вимкнення світла. Служба без enable після перезавантаження просто не запуститься, і ніхто вам про це не скаже.

systemctl is-enabled demo-sleep.service || true
sudo systemctl enable demo-sleep.service
systemctl is-enabled demo-sleep.service || true
ls -l /etc/systemd/system/multi-user.target.wants/demo-sleep.service

enable не запускає службу, а start не вмикає автозапуск. Це дві окремі дії. Щоб виконати обидві однією командою, додайте --now:

sudo systemctl disable --now demo-sleep.service
systemctl is-active demo-sleep.service || true
sudo systemctl enable --now demo-sleep.service
systemctl is-active demo-sleep.service || true

disable --now прибирає посилання і зупиняє службу. disable без --now прибирає лише автозапуск. Служба, яка працює, працюватиме далі до наступного перезавантаження.

Важливо: disable не забороняє запуск. Перевірте самі:

sudo systemctl disable --now demo-sleep.service
sudo systemctl start demo-sleep.service
systemctl is-active demo-sleep.service || true
systemctl is-enabled demo-sleep.service || true

Автозапуск вимкнено, але служба працює, бо ви запустили її вручну. Так само її може запустити інша служба через Wants= чи Requires=. Якщо служба не повинна запускатися взагалі, потрібен mask.

Чим mask відрізняється від disable

mask робить юніт таким, що його неможливо запустити. Команда створює в /etc/systemd/system посилання з іменем юніта, яке вказує на /dev/null. Файли в /etc мають пріоритет над файлами в /usr/lib і /usr/local/lib. Тому systemd бачить порожній юніт і відмовляється його запускати: вручну, через залежність, будь-як.

sudo systemctl mask --now demo-sleep.service
ls -l /etc/systemd/system/demo-sleep.service
systemctl is-enabled demo-sleep.service || true
sudo systemctl start demo-sleep.service || true

--now разом із mask ще й зупиняє службу. Без нього mask лише забороняє наступні запуски, а процес, що вже працює, залишається. Спроба start для замаскованого юніта завершується помилкою, і systemctl пояснює причину.

Коли маскувати службу? Коли дві служби хочуть один порт і одну з них треба вимкнути назавжди. Або коли пакет установив службу, яка вам не потрібна, а інша служба її підтягує.

Щоб зняти заборону, виконайте unmask:

sudo systemctl unmask demo-sleep.service
systemctl is-enabled demo-sleep.service || true

unmask видаляє посилання на /dev/null. Він не вмикає автозапуск і не запускає службу. Це треба зробити окремо.

Як перевірити стан служби у скрипті: is-active, is-enabled і is-failed

Кожна з цих команд відповідає на одне питання. is-active перевіряє, чи юніт працює зараз. is-enabled перевіряє автозапуск. is-failed перевіряє, чи юніт у стані помилки. Кожна друкує коротку відповідь і повертає код, який зручно перевіряти в скрипті.

Подивіться, що друкує is-active і який код повертає, коли служба працює і коли зупинена:

sudo systemctl start demo-sleep.service
systemctl is-active demo-sleep.service || true
systemctl is-active --quiet demo-sleep.service && echo $? || echo $?
sudo systemctl stop demo-sleep.service
systemctl is-active demo-sleep.service || true
systemctl is-active --quiet demo-sleep.service && echo $? || echo $?

Конструкція && echo $? || echo $? друкує код повернення в обох випадках і не зупиняє скрипт із set -e. --quiet прибирає текстову відповідь, залишаючи тільки код. Те саме для is-enabled:

sudo systemctl enable demo-sleep.service
systemctl is-enabled demo-sleep.service && echo $? || echo $?
sudo systemctl disable demo-sleep.service
systemctl is-enabled demo-sleep.service && echo $? || echo $?

Текст відповіді призначений для людини. Скрипт має дивитися на код повернення, і саме його перевіряє if у bash:

if systemctl is-active --quiet demo-sleep.service; then
  echo 'demo-sleep працює'
else
  echo 'demo-sleep не працює, запускаю'
  sudo systemctl start demo-sleep.service
fi

Щоб побачити is-failed у дії, службу треба «зламати». systemctl kill надсилає сигнал процесам служби. SIGKILL завершує процес миттєво, і systemd вважає таке завершення аварійним, тому юніт переходить у стан failed:

sudo systemctl kill --signal=SIGKILL demo-sleep.service
sleep 1
systemctl is-failed demo-sleep.service && echo $? || echo $?
systemctl --failed --no-pager
sudo systemctl reset-failed demo-sleep.service
systemctl is-failed demo-sleep.service && echo $? || echo $?

sleep 1 дає systemd час обробити завершення процесу. reset-failed очищає стан помилки. Служба після нього не запускається, вона лише зникає зі списку тих, що впали.

Чому справжня служба впала і що означає її код виходу, пояснює розбір кодів виходу, коли юніт systemd не стартує. Щоб systemd сам запускав службу знову після падіння, потрібен рядок Restart=, і про це є пояснення політик перезапуску в systemd.

Як побачити всі служби: list-units, list-unit-files і --failed

list-units показує юніти, які systemd зараз тримає в пам'яті. Без --all у списку лише активні юніти й ті, що впали. list-unit-files показує всі встановлені файли юнітів і стан автозапуску кожного, навіть якщо юніт ніколи не запускався.

systemctl list-units --type=service --no-pager
systemctl list-units --type=service --state=running --no-pager
systemctl list-unit-files 'demo-*' --no-pager
systemctl --failed --no-pager

Шаблон 'demo-*' обмежує список нашою службою. Лапки потрібні, щоб shell не розгорнув * у назви файлів поточного каталогу.

systemctl --failed це коротка форма systemctl list-units --state=failed. Запускайте її після кожного оновлення й перезавантаження. Порожній список означає, що жоден юніт не впав. Решту регулярних перевірок зібрано в чеклисті обслуговування Linux-сервера.

Як подивитися журнал служби: journalctl -u

sudo journalctl -u demo-sleep.service -n 20 --no-pager
sudo journalctl -u demo-sleep.service --since '10 min ago' --no-pager

-u фільтрує журнал за юнітом. -n 20 показує останні 20 записів. --since розуміє зрозумілі людині вирази, наприклад '10 min ago' або today. Наша служба сама нічого не пише, тому в журналі будуть лише записи systemd про запуски, зупинки й аварійне завершення. У справжньої служби там будуть і рядки самої програми: усе, що вона пише в stdout і stderr.

Чому sudo? Звичайний користувач без групи adm або systemd-journal бачить лише власні записи, а журналу системних служб не бачить. systemctl status показує хвіст того самого журналу. Тому порожній хвіст у status часто має ту саму причину: бракує прав.

Щоб стежити за журналом у реальному часі, запустіть sudo journalctl -u demo-sleep.service -f. Вийти можна через Ctrl+C.

Команда service ще працює

У старих інструкціях часто трапляється sudo service nginx restart. На Ubuntu це досі працює. service тепер обгортка для сумісності: вона передає виклик у systemctl. Для нашого юніта це було б sudo service demo-sleep restart. Для щоденної роботи краще звикнути до systemctl, бо в service немає аналогів для enable, mask чи is-failed. Як старі runlevel відповідають цілям systemd, пояснює порівняння цілей systemd і runlevel.

Як прибрати демо-юніт

sudo systemctl disable --now demo-sleep.service
sudo rm /usr/local/lib/systemd/system/demo-sleep.service
sudo systemctl daemon-reload

Після daemon-reload systemd більше не знає про цю службу. Порожній каталог /usr/local/lib/systemd/system можна залишити, він нічому не заважає.

Що читати далі

Цей посібник про керування службами, які вже існують. Як написати власну службу і таймер замість cron, показує посібник зі служби й таймера systemd на VPS. Чим Type=simple відрізняється від Type=notify і чому це впливає на start, розібрано в поясненні типів служб systemd.

FAQ

Чим systemctl restart відрізняється від reload?

restart зупиняє процес служби і запускає новий, тому на кілька секунд служба недоступна, а відкриті з'єднання обриваються. reload просить процес, що вже працює, перечитати конфігурацію, і номер процесу не змінюється. reload працює лише тоді, коли в юніті є рядок ExecReload=. Якщо ви не знаєте, чи служба підтримує reload, використовуйте sudo systemctl reload-or-restart ІМ'Я.

Чим systemctl mask відрізняється від disable?

disable прибирає лише автозапуск. Службу все одно можна запустити вручну або через іншу службу, яка від неї залежить. mask створює в /etc/systemd/system посилання на /dev/null, і після цього службу неможливо запустити жодним способом, доки ви не виконаєте unmask. Для юніта, чий файл лежить саме в /etc/systemd/system, mask не спрацює, бо це місце вже зайняте справжнім файлом.

Чи працює ще команда service на Ubuntu?

Так. sudo service ІМ'Я restart, start, stop і status досі працюють на Ubuntu 24.04 і 26.04. Команда service стала обгорткою для сумісності, яка передає виклик у systemctl. Для автозапуску, маскування й перевірок у скриптах потрібен сам systemctl.

Як у bash-скрипті перевірити, що служба запущена?

Використайте if systemctl is-active --quiet ІМ'Я.service; then ... fi. --quiet прибирає текст відповіді, а if перевіряє код повернення. Не порівнюйте надрукований текст зі словом, бо текст призначений для людини, а код повернення для скриптів. Для автозапуску є is-enabled, а для стану помилки is-failed.

Чому зміни в юніт-файлі не діють?

systemd тримає опис юніта в пам'яті й не перечитує файл сам. Після будь-якої зміни виконайте sudo systemctl daemon-reload. systemctl show -p NeedDaemonReload ІМ'Я.service показує, чи файл на диску новіший за опис у пам'яті. daemon-reload не перезапускає служби, тож якщо ви змінили ExecStart, після нього потрібен ще sudo systemctl restart ІМ'Я.service.

#systemd#systemctl#linux#ubuntu#services#journalctl