# 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`, поэтому перезапуск контейнера не вызывает повторной волны алертов. ## Быстрый старт ```bash cp .env.example .env # отредактируй .env: добавь TELEGRAM_BOT_TOKEN и TELEGRAM_CHAT_ID docker compose up -d --build ``` ## Как получить токен бота и chat_id 1. Напишите [@BotFather](https://t.me/BotFather), создайте бота и скопируйте токен в `TELEGRAM_BOT_TOKEN`. 2. Напишите [@userinfobot](https://t.me/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]`. ## Формат алертов **Первый падение:** ``` ⚠️ Server alert · 192.168.0.5 🔴 Gitea: HTTP 502 (expected 200), 12ms ``` **Напоминание:** ``` ⏰ Still down · 192.168.0.5 🔴 Gitea: HTTP 502 (expected 200), 12ms ``` **Восстановление:** ``` ✅ Recovered · 192.168.0.5 🟢 Gitea: HTTP 200, 10ms ``` **Алармы Netdata:** ``` ⚠️ Server alert · 192.168.0.5 🔴 Netdata alarms: CPU_USAGE [CRITICAL]: 95 — ... ``` ## Лог-режим без токена Если `TELEGRAM_BOT_TOKEN` пустой, сообщения не отправляются, а пишутся в лог `[TELEGRAM LOG-ONLY]`. Это удобно для отладки. ## Локальный запуск без Docker ```bash # состояние пишется в ./state.json, а не в /data STATE_FILE=./state.json python3 monitor.py --once ``` Флаг `--once` запускает один цикл проверок и завершает работу. Без `STATE_FILE` сервис попытается писать в `/data` (вне Docker это обычно недоступно — в этом случае состояние просто не сохранится, а первый запуск будет считаться baseline-прогоном). ## Запуск тестов ```bash 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).