Чому саме systemd: watchdog, Restart і timers
Systemd — це не лише менеджер служб, а й гнучкий інструмент для автоматизації задач і Linux моніторинг. Нам потрібні три механізми:
- Restart= — базове автоперезапускання, якщо процес аварійно завершується.
- Watchdog — якщо сервіс періодично надсилає «пульс» (WATCHDOG=1), systemd вважає його здоровим; інакше перезапускає.
- Timers — планувальник перевірок (аналог cron), який запускає bash скрипти для health-check’ів і реакцій.
Працюємо в термінал Linux, використовуючи зрозумілі linux команди, і будуємо рішення шар за шаром.
Покроково: налаштовуємо автоматичне відновлення
Крок 1. Базова самовідновлюваність через Restart=
Почніть з безпечного автоперезапуску, якщо процес падає. Замість редагування системного юніта напряму створіть drop-in конфіг:
sudo systemctl edit nginx.service
Додайте:
[Service]
Restart=on-failure
RestartSec=5s
StartLimitIntervalSec=2min
StartLimitBurst=5
Потім перезавантажте конфіг і застосуйте:
sudo systemctl daemon-reload
sudo systemctl restart nginx.service
Тепер, якщо nginx упаде з помилкою, systemd спробує його підняти з розумним бекоффом. Це проста, але вже дієва страховка.
Крок 2. Watchdog для служб, які вміють повідомляти
Якщо сервіс може надсилати сповіщення systemd (sd_notify), додайте watchdog. Ідея: поки процес регулярно каже «я живий», systemd не чіпає його; якщо замовк — перезапуск.
Приклад юніта з підтримкою watchdog:
[Unit]
Description=MyApp (notify + watchdog)
After=network.target
[Service]
Type=notify
WatchdogSec=30s
ExecStart=/usr/local/bin/myapp --notify
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
Додаток має раз на <30s надсилати sd_notify("WATCHDOG=1"). Якщо це ваша програма на C/Go/Rust — додайте підтримку sd_notify. Для скриптів можна скористатися systemd-notify.
Крок 3. Watchdog-wrapper для «німого» сервісу
Що робити, якщо ваш демон не вміє sd_notify? Обгорнемо його у скрипт, який:
- Стартує процес.
- Регулярно перевіряє health (порт/HTTP).
- Надсилає WATCHDOG=1, якщо все добре, або завершується з помилкою, щоб systemd перезапустив.
Скрипт:
sudo tee /usr/local/bin/myapp-watchdog.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
APP_CMD="${1:-/usr/local/bin/myapp}"
HEALTH_URL="${2:-http://127.0.0.1:8080/health}"
systemd-notify --ready || true
"$APP_CMD" &
APP_PID=$!
trap 'kill $APP_PID 2>/dev/null || true' EXIT
while kill -0 "$APP_PID" 2>/dev/null; do
if curl -fsS --max-time 2 "$HEALTH_URL" >/dev/null; then
systemd-notify WATCHDOG=1 || true
else
exit 1
fi
sleep 5
done
exit 1
EOF
sudo chmod +x /usr/local/bin/myapp-watchdog.sh
Юніт із watchdog:
sudo tee /etc/systemd/system/myapp.service >/dev/null <<'EOF'
[Unit]
Description=MyApp wrapped with watchdog
After=network.target
[Service]
Type=notify
WatchdogSec=30s
ExecStart=/usr/local/bin/myapp-watchdog.sh "/usr/local/bin/myapp" "http://127.0.0.1:8080/health"
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
Тут ми отримали watchdog без змін у самому сервісі, використавши bash скрипти.
Крок 4. Перевірка здоров'я через systemd timer + bash
Як додатковий рівень захисту зробимо періодичний health-check, який перезапускає сервіс, якщо HTTP/порт недоступний. Це ідеальна зона для cron та systemd timers (але ми віддамо перевагу timers для інтеграції з журналами).
sudo tee /usr/local/bin/healthcheck.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
SERVICE="${1:-nginx}"
URL="${2:-http://127.0.0.1/}"
LOGTAG="healthcheck-$SERVICE"
if curl -fsS --max-time 5 "$URL" >/dev/null; then
logger -t "$LOGTAG" "OK $URL"
else
logger -t "$LOGTAG" "FAIL $URL — restarting $SERVICE"
systemctl restart "$SERVICE"
fi
EOF
sudo chmod +x /usr/local/bin/healthcheck.sh
Сервіс і таймер:
sudo tee /etc/systemd/system/healthcheck@.service >/dev/null <<'EOF'
[Unit]
Description=Healthcheck for %i
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/healthcheck.sh %i http://127.0.0.1/
EOF
sudo tee /etc/systemd/system/healthcheck@nginx.timer >/dev/null <<'EOF'
[Unit]
Description=Healthcheck timer for nginx
[Timer]
OnBootSec=2m
OnUnitActiveSec=1m
AccuracySec=15s
Unit=healthcheck@nginx.service
[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now healthcheck@nginx.timer
systemctl list-timers --all | grep healthcheck
Тепер щохвилини скрипт перевірятиме доступність сторінки і, за потреби, перезапустить сервіс. Логи дивіться в journalctl -u healthcheck@nginx.service та через logger у системному журналі — зручно для Linux моніторинг.
Альтернативні способи
- cron + bash: якщо вам принципово cron, додайте запис у
/etc/cron.d/з викликомhealthcheck.sh. Але systemd timers дають кращу інтеграцію з юнітами й журналами. - Monit: окремий наглядач із правилами health-check, перезапусками і алертами. Добре, але ще один демоник у системі.
- Hardware watchdog: апаратний «собачок» через /dev/watchdog для всього ядра/системи. Для критично важливих серверів — топ, але складніше у конфігурації.
GUI-спосіб (Cockpit)
Якщо вам зручніше через веб-інтерфейс, встановіть Cockpit — він уміє керувати службами і таймерами. Це зручно для «живої» діагностики без складних команд.
# Debian/Ubuntu
sudo apt update && sudo apt install -y cockpit
sudo systemctl enable --now cockpit.socket
# Відкрийте https://<IP-сервера>:9090 у браузері, перейдіть до System -> Services/Timers
У Cockpit легко вмикати/вимикати таймери, дивитися статуси та журнали, не виходячи з браузера 🙂
FAQ
Сервіс не перезапускається, хоч Restart= задано.
Перевірте, чи не «вибили» ліміти: systemctl status <svc> покаже StartLimitHit. Підвищте StartLimitBurst або інтервал, і перегляньте причину падіння в journalctl -u <svc>.
Watchdog не працює.
Для watchdog потрібен Type=notify і регулярне sd_notify("WATCHDOG=1"). Якщо ваш процес цього не робить — використайте wrapper, як у прикладі.
Як протестувати перезапуск без реального крашу?
Тимчасово зробіть health-check, який гарантовано фейлиться (URL 127.0.0.1:1), або зупиніть сокет/порт. Для watchdog-wrapper просто поверніть ненульовий код у скрипті.
Timer не запускається.
Перевірте systemctl status healthcheck@nginx.timer. Не забудьте daemon-reload після створення юнітів і enable --now для таймера. Також звірте час системи.
Де дивитись логи?journalctl -u myapp.service -e, journalctl -u healthcheck@nginx.service -e, а також системний журнал для записів logger. Логи — ваш найкращий друг у діагностиці.
Порада від Kernelka
Не робіть інтервали занадто агресивними. Надто частий перезапуск може погіршити ситуацію і створити петлю. Краще стабільний Linux моніторинг плюс помірні таймаути та автоматизація задач у кілька рівнів: Restart=, watchdog і незалежний health-check таймер. І завжди тестуйте зміни на staging перед продом ⚙️
Підсумок
- Почніть із
Restart=on-failureі безпечних лімітів запусків. - Додайте watchdog там, де сервіс може або де його обгортає скрипт.
- Створіть зовнішній перевіряючий таймер для HTTP/портів.
- Використовуйте bash скрипти для простих health-check’ів та реакцій.
- Для наочності можна керувати всім через Cockpit.
- Регулярно перевіряйте журнали й метрики — це основа стабільності.

Прокоментувати
На сайті відображається лише твоє ім'я та коментар. Електронна пошта зберігається виключно для зв'язку з тобою за потреби та в жодному разі не передається стороннім особам.