Уведомление о перезагрузке сервера
Сервер перезагрузился ночью — а вы узнали об этом только утром, когда пользователи
пожаловались на «отвалившиеся» сессии. Внезапный ребут почти всегда означает что-то
серьёзное: паника ядра, watchdog, отключение питания или чьё-то reboot по SSH.
Уведомление в момент загрузки экономит часы расследования.
Что мы будем делать
Заголовок раздела «Что мы будем делать»Создадим systemd-юнит типа oneshot, который запускается один раз при каждой
загрузке (WantedBy=multi-user.target). Скрипт:
- собирает
uptime, время последней загрузки и причину; - отличает плановую перезагрузку от неожиданной через маркер-файл: перед
штатным
reboot/shutdownмы кладём маркер, при загрузке — проверяем его; - при неожиданном ребуте шлёт сообщение с высоким приоритетом, при плановом — обычное «сервер вернулся».
Сохраните как /usr/local/bin/notifly-reboot-check:
#!/usr/bin/env bashset -euset -a; source /etc/notifly.env; set +a
HOST=$(hostname -s)MARKER=/var/lib/notifly-reboot/planned
# Время последней загрузки и аптайм в человекочитаемом видеBOOT_TIME=$(uptime -s)UPTIME_H=$(uptime -p)
# Последние строки о причинах прошлого выключения — часто видно panic/power lossLAST_REBOOT=$(last -x -n 5 reboot shutdown 2>/dev/null | head -5 || true)
if [ -f "$MARKER" ]; then # Маркер на месте — значит выключение было штатным rm -f "$MARKER" /usr/local/bin/notifly-send \ "🔄 $HOST перезагрузился (планово)" \ "Загрузка: $BOOT_TIMEАптайм: $UPTIME_H" 4else # Маркера нет — перезагрузка была неожиданной DMESG_ERR=$(journalctl -k -b -1 -p err --no-pager 2>/dev/null | tail -5 || true) /usr/local/bin/notifly-send \ "⚠️ $HOST перезагрузился НЕОЖИДАННО" \ "Загрузка: $BOOT_TIMEАптайм: $UPTIME_H
Последние ребуты:$LAST_REBOOT
Ошибки прошлого сеанса:$DMESG_ERR" 9fiСделайте исполняемым:
sudo chmod +x /usr/local/bin/notifly-reboot-checkМаркер плановой перезагрузки
Заголовок раздела «Маркер плановой перезагрузки»Перед штатным выключением нужно положить маркер. Проще всего сделать это отдельным юнитом, который срабатывает на остановку системы:
/etc/systemd/system/notifly-reboot-marker.service:
[Unit]Description=Mark planned reboot for NotiflyDefaultDependencies=noBefore=shutdown.target reboot.target halt.target
[Service]Type=oneshotRemainAfterExit=yesExecStart=/bin/mkdir -p /var/lib/notifly-rebootExecStop=/bin/touch /var/lib/notifly-reboot/planned
[Install]WantedBy=multi-user.targetЮнит держится «поднятым» всё время работы системы, а маркер создаёт ExecStop —
то есть ровно в момент штатного systemctl reboot/shutdown. При внезапном
падении питания ExecStop не отработает, маркера не будет — и мы поймём, что
ребут был неожиданным.
Запуск при загрузке
Заголовок раздела «Запуск при загрузке»/etc/systemd/system/notifly-reboot.service:
[Unit]Description=Notifly reboot notificationAfter=network-online.targetWants=network-online.target
[Service]Type=oneshotExecStart=/usr/local/bin/notifly-reboot-check
[Install]WantedBy=multi-user.targetАктивируем оба юнита:
sudo systemctl daemon-reloadsudo systemctl enable --now notifly-reboot-marker.servicesudo systemctl enable notifly-reboot.serviceПроверить вручную:
sudo systemctl start notifly-reboot.serviceWindows: PowerShell + Task Scheduler
Заголовок раздела «Windows: PowerShell + Task Scheduler»На Windows момент загрузки виден в System Event Log: Event ID 6005 («The Event
log service was started» — штатный старт), 6008 («The previous system shutdown
was unexpected» — неожиданный) и 6009 (версия ОС при загрузке). Подпишемся на
эти события. Используется общая функция Send-Notifly из
шаблона sysadmin/index.
. C:\scripts\Notifly.ps1
$Host = $env:COMPUTERNAME$uptime = (Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime$boot = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
# Было ли предыдущее выключение неожиданным? (Event 6008 в System)$unexpected = Get-WinEvent -FilterHashtable @{LogName='System'; Id=6008} -MaxEvents 1 -ErrorAction SilentlyContinue$isUnexpected = $unexpected -and $unexpected.TimeCreated -gt (Get-Date).AddMinutes(-15)
if ($isUnexpected) { Send-Notifly -Title "⚠️ $Host перезагрузился НЕОЖИДАННО" ` -Message "Загрузка: $boot`nАптайм: $([int]$uptime.TotalMinutes) мин.`nПредыдущее выключение было аварийным (Event 6008)." ` -Priority 9} else { Send-Notifly -Title "🔄 $Host перезагрузился (планово)" ` -Message "Загрузка: $boot`nАптайм: $([int]$uptime.TotalMinutes) мин." ` -Priority 4}Регистрация задачи на старт системы:
$Trigger = New-ScheduledTaskTrigger -AtStartup$Trigger.Delay = "PT1M" # подождать минуту после загрузки$Action = New-ScheduledTaskAction -Execute "powershell.exe" ` -Argument "-NoProfile -ExecutionPolicy Bypass -File C:\scripts\Notifly-Reboot-Check.ps1"$Princ = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel HighestRegister-ScheduledTask -TaskName "Notifly Reboot Check" ` -Action $Action -Trigger $Trigger -Principal $Princ -Description "Notifly: уведомление о перезагрузке"- Ноль внезапных ребутов «в тишине». Любая перезагрузка сразу видна на телефоне.
- Планово или нет — понятно сразу. Маркер-файл отделяет ваши собственные
rebootот аварийных, так что вы не привыкаете игнорировать зелёные сообщения. - Контекст в кармане. В сообщении сразу время загрузки, аптайм и ошибки прошлого сеанса — часто этого достаточно, чтобы понять причину.
Что улучшить дальше
Заголовок раздела «Что улучшить дальше»- Прикладывать полный вывод
journalctl -k -b -1 -p warningчерез полеextras, чтобы разбирать panic прямо в приложении. - Связать с heartbeat-проверкой: если после ребута сервер так и не прислал сигнал жизни — значит, он не поднялся.
- Считать частоту ребутов: три неожиданных перезагрузки за час — это уже
железная проблема, стоит поднять приоритет до
10.