- 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
6.3 KiB
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 │
└─────────────┘
- Контейнер каждые
check_interval_secсекунд выполняет набор проверок. - Если проверка падает — отправляется первый алерт.
- Пока сервис остаётся недоступным, каждые
reminder_interval_secсекунд приходит напоминание. - Когда сервис восстанавливается — приходит сообщение о recovery.
- Состояние хранится в
/data/state.json, поэтому перезапуск контейнера не вызывает повторной волны алертов.
Быстрый старт
cp .env.example .env
# отредактируй .env: добавь TELEGRAM_BOT_TOKEN и TELEGRAM_CHAT_ID
docker compose up -d --build
Как получить токен бота и chat_id
- Напишите @BotFather, создайте бота и скопируйте токен в
TELEGRAM_BOT_TOKEN. - Напишите @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).