Files
Sanders 465b27d673 ServerMonitor: Dockerized health-check service with Telegram alerts
- Pure stdlib Python (3.12), runs on python:3.12-alpine as non-root
- Checks: ping, HTTP (expected codes), TCP ports, Netdata alarms + metrics
- Netdata v2 compatible: system.cpu (no idle dim), system.ram, disk_space.* discovery
- AlertEngine dedup: first alert, reminders, recovery (only after real alert)
- Baseline first-run (no alert storm on deploy), atomic state file, --once mode
- 20 unit tests passing; verified live against 192.168.0.5
2026-08-05 22:28:20 +03:00

6.3 KiB
Raw Permalink Blame History

ServerMonitor

Docker-контейнер для мониторинга домашнего сервера (Unraid) с удалённого VPS. Периодически проверяет доступность сервисов и шлёт алерты в Telegram при падениях, напоминания, пока сервис не поднимется, и сообщения о восстановлении.

Что это

ServerMonitor — это лёгкий Python-сервис без сторонних зависимостей. Он работает на python:3.12-alpine, использует только стандартную библиотеку и предназначен для развёртывания на VPS. Сервис мониторит хост 192.168.0.5 по сети: пингует его, делает HTTP-запросы к веб-приложениям, проверяет TCP-порты и забирает алармы/метрики из Netdata.

Как это работает

┌─────────┐   ping / http / tcp / netdata   ┌──────────────┐
│   VPS   │ ───────────────────────────────→│  Unraid 192.  │
│ контейнер│                                 │   168.0.5    │
│ServerMonitor│                              │              │
└────┬────┘                                └──────────────┘
     │
     │ Telegram (alert / reminder / recovery)
     ▼
┌─────────────┐
│  Telegram   │
└─────────────┘
  1. Контейнер каждые check_interval_sec секунд выполняет набор проверок.
  2. Если проверка падает — отправляется первый алерт.
  3. Пока сервис остаётся недоступным, каждые reminder_interval_sec секунд приходит напоминание.
  4. Когда сервис восстанавливается — приходит сообщение о recovery.
  5. Состояние хранится в /data/state.json, поэтому перезапуск контейнера не вызывает повторной волны алертов.

Быстрый старт

cp .env.example .env
# отредактируй .env: добавь TELEGRAM_BOT_TOKEN и TELEGRAM_CHAT_ID
docker compose up -d --build

Как получить токен бота и chat_id

  1. Напишите @BotFather, создайте бота и скопируйте токен в TELEGRAM_BOT_TOKEN.
  2. Напишите @userinfobot, получите свой ID и вставьте его в TELEGRAM_CHAT_ID.

Настройка чеков в config.json

Секция Поле Описание
host строка IP или имя мониторимого хоста
check_interval_sec число Интервал между циклами проверок, сек
reminder_interval_sec число Интервал между напоминаниями, сек
timeout_sec число Таймаут сетевых операций, сек
state_file строка Путь к файлу состояния
telegram.bot_token строка Токен Telegram-бота
telegram.chat_id строка ID чата для алертов
thresholds.cpu_percent число Порог загрузки CPU, %
thresholds.ram_avail_mb число Минимум доступной RAM, МБ
thresholds.disk_percent число Порог занятости диска, %
http_checks массив {name, url, expected}
tcp_checks массив {name, host, port}
netdata.base_url строка URL Netdata

expected — список допустимых HTTP-кодов, например [200] или [200, 401].

Формат алертов

Первый падение:

⚠️ <b>Server alert</b> · 192.168.0.5

🔴 <b>Gitea</b>: HTTP 502 (expected 200), 12ms

Напоминание:

⏰ <b>Still down</b> · 192.168.0.5

🔴 <b>Gitea</b>: HTTP 502 (expected 200), 12ms

Восстановление:

✅ <b>Recovered</b> · 192.168.0.5

🟢 <b>Gitea</b>: HTTP 200, 10ms

Алармы Netdata:

⚠️ <b>Server alert</b> · 192.168.0.5

🔴 <b>Netdata alarms</b>: CPU_USAGE [CRITICAL]: 95 — ...

Лог-режим без токена

Если TELEGRAM_BOT_TOKEN пустой, сообщения не отправляются, а пишутся в лог [TELEGRAM LOG-ONLY]. Это удобно для отладки.

Локальный запуск без Docker

# состояние пишется в ./state.json, а не в /data
STATE_FILE=./state.json python3 monitor.py --once

Флаг --once запускает один цикл проверок и завершает работу. Без STATE_FILE сервис попытается писать в /data (вне Docker это обычно недоступно — в этом случае состояние просто не сохранится, а первый запуск будет считаться baseline-прогоном).

Запуск тестов

python3 -m unittest discover -s tests -v

Troubleshooting

Контейнер не видит хост:

  • Убедитесь, что у VPS есть маршрут к 192.168.0.5.
  • Проверьте firewall на Unraid/VPS.
  • Для тестов можно запустить docker run --rm --network host ....

Ping в контейнере:

  • Внутри python:3.12-alpine может не быть прав на ICMP.
  • ping_check деградирует gracefully: возвращает ok=True с сообщением ping unavailable, чтобы не ломать весь цикл.

Состояние не сохраняется:

  • Проверьте, что volume monitor-state смонтирован в /data.
  • В образе /data принадлежит пользователю app (uid 10001).