rzaripov.kz

Как я настроил мониторинг сервера с PHP и Telegram

Когда сервер обслуживает сайт, API или внутренний сервис, одной проверки доступности в браузере недостаточно. Ошибка может возникнуть ночью, закончиться место на диске, зависнуть база данных или резко вырасти нагрузка на процессор. В такой ситуации важно узнать о проблеме до того, как её заметят пользователи.

Для небольших проектов я предпочитаю понятные инструменты без сложной инфраструктуры. PHP-скрипты легко разместить на обычном хостинге или виртуальном сервере, а Telegram подходит для быстрой доставки уведомлений на компьютер и смартфон. В результате получается компактная система контроля состояния сервера.

В этой статье я покажу, как организовал мониторинг сервера с PHP и Telegram: создал бота, настроил проверку ключевых параметров, добавил защиту от повторяющихся сообщений и запустил скрипт через планировщик заданий. Такой подход хорошо подходит для личных проектов, тестовых окружений и небольших коммерческих сервисов.

Что именно должен проверять мониторинг

Сначала я определил минимальный набор метрик. Скрипт проверяет доступность нужного HTTP-адреса, код ответа, время отклика, свободное место на файловой системе и загрузку процессора. При необходимости к этому набору можно добавить состояние службы, соединение с базой данных, срок действия SSL-сертификата и наличие свободной оперативной памяти.

Проверка сайта выполняется обычным HTTP-запросом через cURL. Важно учитывать тайм-аут: если сервер не отвечает за несколько секунд, PHP не должен зависать до бесконечности. Я задаю короткий лимит соединения и отдельный общий лимит выполнения запроса, после чего фиксирую результат в журнале.

Для дискового пространства подходит функция disk_free_space(). Процент занятого места рассчитывается относительно общего объёма раздела. При достижении порога, например 85 или 90 процентов, бот отправляет предупреждение. Такой сигнал особенно полезен перед резервным копированием, обновлением системы или загрузкой большого архива.

Создание Telegram-бота и безопасная конфигурация

Бота я создаю через официального помощника Telegram. После регистрации выдаётся токен, который используется для обращения к Bot API. Идентификатор чата можно получить через специальный служебный запрос после отправки сообщения боту. Для личного мониторинга достаточно знать собственный chat_id, а для команды можно использовать идентификатор группы.

Токен нельзя хранить в открытом репозитории или передавать через параметры командной строки. Я вынес секреты в конфигурационный файл за пределами публичной директории веб-сервера. Права доступа к этому файлу ограничены пользователем, от имени которого выполняется PHP-процесс. В Git репозиторий конфигурация добавлена в .gitignore.

Функция отправки сообщения обращается к адресу https://api.telegram.org/bot<TOKEN>/sendMessage. В запрос передаются идентификатор чата и текст уведомления. Для надёжности скрипт проверяет HTTP-код ответа и поле ok в JSON. Если Telegram временно недоступен, ошибка записывается локально, чтобы её можно было изучить позже.

function sendTelegram(string $token, string $chatId, string $message): bool
{
    $url = "https://api.telegram.org/bot{$token}/sendMessage";

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => [
            'chat_id' => $chatId,
            'text' => $message,
        ],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CONNECTTIMEOUT => 5,
        CURLOPT_TIMEOUT => 10,
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($response === false || $httpCode !== 200) {
        return false;
    }

    $data = json_decode($response, true);
    return is_array($data) && ($data['ok'] ?? false) === true;
}

Логика PHP-скрипта и пороговые значения

Чтобы уведомления оставались понятными, я разделил результаты на состояния: OK, WARNING и CRITICAL. Нормальное состояние не требует сообщения при каждом запуске. Предупреждение отправляется при пересечении заданного порога, а критическая ошибка — когда ресурс недоступен или показатель становится опасным.

Скрипт собирает данные в один отчёт. В него я включаю имя сервера, текущее время, URL проверяемого приложения, HTTP-код, время ответа и свободное место. Для времени использую часовой пояс сервера или явно задаю часовой пояс в PHP, чтобы отметки в Telegram совпадали с локальным временем в Алматы.

Проверка Нормальное значение Предупреждение Критическое состояние
HTTP-доступность Код 200 Код 3xx или долгий ответ Ошибка соединения или код 5xx
Время ответа До 1 секунды От 1 до 3 секунд Более 3 секунд или тайм-аут
Свободное место Более 20% От 10 до 20% Менее 10%
Загрузка процессора До 70% От 70 до 90% Более 90%
Служба базы данных Работает Замедление подключения Подключение невозможно

Для проверки HTTP я использую curl_getinfo() и сравниваю код ответа с ожидаемым значением. Однако один неудачный запрос ещё не всегда означает аварию: причиной может быть кратковременный сетевой сбой. Поэтому я запускаю несколько последовательных проверок или применяю задержку перед переводом состояния в критическое.

Отдельно храню последнее состояние в небольшом JSON-файле. Если предыдущий запуск завершился ошибкой, а текущий снова успешен, бот отправляет сообщение о восстановлении. Это удобнее, чем получать одинаковое уведомление каждую минуту. Для нескольких серверов состояние можно хранить в SQLite или MySQL.

Запуск по расписанию и контроль самой проверки

На Linux я добавил задачу в cron. Например, запуск каждые пять минут выглядит так:

*/5 * * * * /usr/bin/php /var/www/monitor/check.php >> /var/log/server-monitor.log 2>&1

Путь к интерпретатору и скрипту лучше указывать полностью. Окружение cron отличается от интерактивной оболочки: могут отсутствовать переменные PATH, рабочая директория и привычные права доступа. Поэтому конфигурационные файлы, временные каталоги и журналы должны подключаться по абсолютным путям.

На Windows аналогичную задачу можно создать в «Планировщике заданий», указав php.exe в качестве программы и путь к скрипту в аргументах. Если приложение работает на macOS или другой Unix-подобной системе, подойдёт системный планировщик. При выборе интервала я учитываю назначение сервиса: для личного сайта достаточно пяти минут, для критичного API нужен более частый контроль.

Сам мониторинг тоже необходимо проверять. Если cron перестанет работать, сервер может выглядеть здоровым только потому, что диагностика больше не выполняется. Поэтому я добавил файл-метку, который обновляется при каждом успешном запуске, и отдельную проверку его времени изменения. Для важных проектов полезно использовать внешний сервис, который обращается к специальному URL и сообщает, если тот давно не обновлялся.

Защита от ложных тревог и повторных сообщений

Главное практическое правило — не отправлять уведомление при каждом незначительном отклонении. Для каждого параметра я задаю порог срабатывания и порог восстановления. Например, предупреждение о диске появляется при заполнении 85 процентов, а сообщение о восстановлении отправляется только после снижения нагрузки до 80 процентов. Такой гистерезис предотвращает постоянное переключение между состояниями.

Текст уведомления должен быстро объяснять, что произошло. Я использую формат вроде: «Сервер web-01: HTTP-проверка не пройдена, код 502, время 14:35». Для диска добавляю раздел, свободный объём и процент использования. В критических событиях полезно указывать короткое действие: проверить службу nginx, журналы PHP или состояние базы данных.

Логирование помогает разбирать причины аварий. В журнал я записываю результат проверки, длительность выполнения, ошибки cURL и факт отправки сообщения в Telegram. При этом секретный токен и содержимое конфигурации туда не попадают. Старые логи нужно ротировать, иначе сам мониторинг постепенно заполнит диск, который он пытается контролировать.

Расширение системы для реальных проектов

После базовой версии я добавил проверки базы данных и отдельных бизнес-функций. Простое подключение к MySQL показывает, работает ли сервер базы, но не гарантирует исправность приложения. Поэтому дополнительно выполняю безопасный SQL-запрос и проверяю, что нужная таблица доступна, а результат соответствует ожидаемому диапазону.

Для контроля сертификата можно получить дату окончания срока действия через OpenSSL или внешнюю команду. Уведомление за 14 и за 3 дня до завершения помогает избежать внезапного отказа HTTPS. Для резервных копий я проверяю наличие последнего архива, его дату и минимальный размер. Пустой файл резервной копии формально существует, но пользы от него нет.

Полезные заготовки и собственные разработки я собрал в каталоге проектов, где можно ориентироваться при выборе инструментов для серверной автоматизации. Сам PHP-мониторинг при этом остаётся небольшим автономным компонентом: его легко перенести на другой сервер и адаптировать под конкретный набор проверок.

Если проект развивается в нескольких средах, конфигурацию лучше разделить на тестовую и рабочую. Для каждой среды задаются свои адреса, пороги, чат Telegram и уровень подробности сообщений. При работе с исходниками мне также важно быстро воспроизводить окружение; описание создания проекта в NetBeans может пригодиться при подключении существующего PHP-кода к рабочему проекту.

Такая схема не заменяет полноценную систему наблюдаемости с метриками и графиками, однако закрывает основные задачи небольшого сервера. PHP отвечает за сбор данных и простую бизнес-логику, cron — за регулярный запуск, а Telegram — за оперативную доставку событий. При аккуратной работе с секретами, журналами и порогами получается практичный мониторинг, который помогает узнать о проблеме раньше пользователей.