В предыдущей статье я описал как установить и настроить Monit для мониторинга сервера, но помимо мониторинга параметров сервера Monit можно использовать и для многих других целей, в частности мониторинга web-сайтов.
У нас уже есть настроенный и работающий Monit, теперь давайте определимся мониторинг каких параметров сайта мы хотим и будем проверять:
1. Доступность сайта — будем проверять разными методами:
1.1 Проверка по протоколу ICMP — как правило такая проверка не несет полезной информации, но помогает в случае возникновения проблем на сетевом уровне, например ваш хостинг-провайдер выключил сервер или у него возникли проблемы в сетевой инфраструктуре;
1.2 Проверка подключения на 80 или 443 порт web-сервера — это просто проверка подключения на данные порты, в первую очередь она показывает жив ли наш вебсервер и принимает ли он подключения на указанные порты, а то вдруг наш хостинг-провайдер или новоиспеченный системный администратор закрыли порты на фаерволе;
1.3 Проверка кода ответа web-сервера — это не что иное как проверка доступности сайта по протоколу HTTP методами HEAD, GET;
1.4 Проверка контента на сайте — аналогично п.1.3, но помимо того что мы просто проверяем код ответа сервера, мы еще дополнительно анализирует наличие ключевых слов на странице;
2. Проверка доступности и работоспособности базы данных сайта;
3. Проверка истечение срока регистрации доменного имени;
4. Проверка SSL сертификата, срока его действия, издателя;
Исходные данные: Наш сайт mysite.ru, сайт открывается как по http, так и по https
Проверка доступности сайта по протоколу ICMP
Такой метод проверки несет мало полезной информации, но он жизненно необходим для диагностики доступности сайта на сетевом уровне. И если проверка по ICMP выдает сбой, то это первый признак того, что с вашим сайтом, вернее с сервером где Ваш сайт что-то не так.
Создадим файл конфигурации /etc/monit/conf.d/mysite
check host mysite.ru_ping with address mysite.ru group mysite if failed ping4 count 5 with timeout 10 seconds then alert
Здесь мы проверяем наш сайт по протоколу ICMPv4 отправляя ICMP Echo Request с таймаутом 10 секунд.
Более детально о всех опциях проверки можно почитать в официальной документации.
Проверку подключения на 80-й порт и на 443-й порт.
Не путайте эту проверку с проверкой по протоколу HTTP(S). Здесь мы просто проверяем доступность порта web-сервера, то есть открыт порт или нет, по сути это проверка работоспособности web-сервера.
Если к примеру предыдущая проверка по протоколу ICMP показывает что все хорошо, а данная проверка выдает сбой, то Вы сразу можете понять, что на сетевом уровне сервер доступен, но что-то случилось со службой web-сервера, возможно «упал» процесс apache2 или nginx или нагрузка на web-сервер такая высокая, что он перестал принимать сетевые подключения.
Пишем в файл /etc/monit/conf.d/mysite
check host mysite.ru_connect with address mysite.ru group mysite if failed port 80 protocol http and request / for 2 cycles then alert if failed port 443 protocol https and request / for 2 cycles then alert
Более детально о всех опциях проверки можно почитать в официальной документации.
Проверка SSL сертификата нашего сайта
Данная проверка является модифицированным аналогом предыдущего варианта проверки на подключение.
В файле /etc/monit/conf.d/mysite пишем:
check host mysite.ru_ssl with address mysite.ru group mysite if failed port 443 protocol https and certificate valid > 7 days then alert
Здесь все просто, мы создали новую проверку дав ей имя mysite.ru_ssl и проверяем срок действия ssl сертификата, если до окончания срока действия осталось менее 7 дней нам будет выслано оповещение.
Так же мы можем проверять контрольную сумму сертификата, что очень актуально если у Вас постоянный сертификат выданный на 1 или 2 года, дополнительная проверка сертификата по контрольной сумме гарантирует, что это точно Ваш сертификат, а не подделка.
Проверку по контрольной сумме можно сделать так:
Вначале посмотрим SHA1 fingerprint нашего SSL сертификата (посмотреть можно 2-мя способами), на самом web-сервере:
openssl x509 -fingerprint -sha1 -in /etc/letsencrypt/live/mysite.ru/cert.pem | head -1 | cut -f2 -d'=' | sed 's,:,,g'
или на удаленном сервере:
MYSITE="mysite.ru"; openssl s_client -servername ${MYSITE} -connect ${MYSITE}:443 </dev/null 2>/dev/null | openssl x509 -text | sed -n -e '/BEGIN\ CERTIFICATE/,/END\ CERTIFICATE/p' | openssl x509 -fingerprint -sha1 | head -1 | cut -f2 -d'=' | sed 's,:,,g'
В файле /etc/monit/conf.d/mysite пишем:
check host mysite.ru_ssl_checksum with address mysite.ru group mysite if failed port 443 protocol https and certificate checksum sha1 = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" then alert
Мы описали 4 проверки которые имеют каждая свое имя (mysite.ru_ping, mysite.ru_connect, mysite.ru_ssl, mysite.ru_ssl_checksum). На мой взгляд такой подход более более правильный, т.к. позволяет группировать проверки по разным группам и управлять оповещениями более гибко и индивидуально. Если есть желание, то все 4 проверки можно объединить в одну, так:
check host mysite.ru with address mysite.ru group mysite if failed ping4 count 5 with timeout 10 seconds then alert if failed port 80 protocol http and request / for 2 cycles then alert if failed port 443 protocol https and request / for 2 cycles then alert if failed port 443 protocol https and certificate valid > 7 days then alert if failed port 443 protocol https and certificate checksum sha1 = "02F0B3DFAF013556A0305D7815B7C605F61E3787" then alert
Теперь давайте проверим конфигурацию monit, сделаем перезагрузку настроек и посмотрим результаты проверки.
# monit -t Control file syntax OK # monit reload Reinitializing monit daemon # monit -g mysite summary Monit 5.24.0 uptime: 25m ┌─────────────────────────────────┬────────────────────────────┬───────────────┐ │ Service Name │ Status │ Type │ ├─────────────────────────────────┼────────────────────────────┼───────────────┤ │ mysite.ru_ping │ OK │ Remote Host │ ├─────────────────────────────────┼────────────────────────────┼───────────────┤ │ mysite.ru_connect │ OK │ Remote Host │ ├─────────────────────────────────┼────────────────────────────┼───────────────┤ │ mysite.ru_ssl │ OK │ Remote Host │ ├─────────────────────────────────┼────────────────────────────┼───────────────┤ │ mysite.ru_ssl_checksum │ OK │ Remote Host │ └─────────────────────────────────┴────────────────────────────┴───────────────┘ # monit -g mysite status Monit 5.24.0 uptime: 5h 14m Remote Host 'mysite.ru_ping' status OK monitoring status Monitored monitoring mode active on reboot start ping response time 33.014 ms data collected Tue, 10 Oct 2017 12:11:35 Remote Host 'mysite.ru_connect' status OK monitoring status Monitored monitoring mode active on reboot start port response time 258.556 m to mysite.ru:443/ type TCP/IP using TLS (certificate valid for 9 days) protocol HTTP port response time 174.378 m to mysite.ru:80/ type TCP/IP protocol HTTP data collected Tue, 10 Oct 2017 12:11:35 Remote Host 'mysite.ru_ssl' status OK monitoring status Monitored monitoring mode active on reboot start port response time 261.374 m to mysite.ru:443 type TCP/IP using TLS (certificate valid for 9 days) protocol HTTP data collected Tue, 10 Oct 2017 12:11:35 Remote Host 'mysite.ru_ssl_checksum' status OK monitoring status Monitored monitoring mode active on reboot start port response time 259.374 m to mysite.ru:443 type TCP/IP using TLS (certificate valid for 9 days) protocol HTTP data collected Tue, 10 Oct 2017 12:11:36
Как видим, все отлично, все проверки успешно отработали. Наш SSL сертификат валиден еще 9 дней.
Давайте поменяем параметр проверки валидации SSL сертификата c 7 на 10 дней и перезапустим проверку и выведем результат:
# monit -t Control file syntax OK # monit reload Reinitializing monit daemon # monit status mysite.ru_ssl Monit 5.24.0 uptime: 31m Remote Host 'mysite.ru_ssl' status Timestamp failed monitoring status Monitored monitoring mode active on reboot start port response time 255.184 m to mysite.ru:443 type TCP/IP using TLS (certificate valid for 9 days) protocol HTTP data collected Tue, 10 Oct 2017 12:17:48
Сейчас мы видим что Monit выдает статус «Timestamp failed» и на электронную почту пришло оповещение о том, что у нас сработала проверка валидации срока действия SSL сертификата.
Проверка кода ответа web-сервера, проверка отдачи контента на определенные ключевые слова.
Зачем вообще нужны такие проверки?
Все просто.
Проверка кода ответа web-сервер говорит о его корректной работе, при нормальной работе web-сервер должен отдавать HTTP код 200 для конкретной конечной страницы.
А зачем тогда проверять контент на предмет каких-то ключевых слов?
А контент нужно проверять чтобы:
1. Убедиться, что это именно Ваш сайт с Вашим контентом, а не какой-то подставной домен. Например если Вы забыли продлить срок регистрации Вашего домена, то регистратор снимает делегирование домена и отдает страницу-заглушку, на которой пишет, что срок регистрации домена закончился. Код ответа web-сервера регистратора будет 200 и предыдущая проверка не выявит ошибку, но вот проверка контента на уникальные слова выявит ошибку и вышлет Вам оповещение.
2. Дополнительная защита от кражи Вашего домена. К примеру злоумышленники могут получить доступ в управлению DNS записями Вашего домена и поменять там A-запись (IP адрес) на свой подставной сервер, поднять на этом сервере полную визуальную копию Вашего сайта, подменить на сайте Ваш email на свои и осуществлять какие-либо мошеннические действия от Вашего имени. От такого рода атаки поможет анализ контента Вашего сайта, Вы можете проверять наличие вашего email или номера телефона на нужных страницах и если их нет, то бить тревогу.
Можно еще усилить защиту сайта от кражи путем создания визуальной копии — это настроить web-сервер на отдачу специальных уникальных HTTP заголовков алгоритм формирования которых известен только Вам и даже если злоумышленники сделают полную визуальную копию Вашего сайта, даже сохранив уникальный контент который Вы проверяете, они не смогут разгадать алгоритм генерации уникальных HTTP заголовков, ведь чтобы его понять нужно взломать Ваш сервер и посмотреть логику создания этих заголовков.
Все эти проверки мы рассмотрим ниже.
Проверка кода ответа Web-сервера.
Здесь все предельно просто, проверяем код ответа на главной странице сайта, если он отличен от 200 — высылаем оповещение.
В файле /etc/monit/conf.d/mysite пишем:
check host mysite.ru_http with address mysite.ru group mysite if failed port 80 protocol http and request / status = 200 for 2 cycles then alert
Проверка контента на сайте.
Будем искать номер телефона на главной странице сайта.
В файле /etc/monit/conf.d/mysite пишем:
check host mysite.ru_content_tel with address mysite.ru group mysite if failed url http://mysite.ru with content = "XXX-XX-XX" for 2 cycles then alert
Проверим статус:
# monit status mysite.ru_content_tel Monit 5.24.0 uptime: 1h 29m Remote Host 'mysite.ru_content_tel' status OK monitoring status Monitored monitoring mode active on reboot start port response time 777.248 m to mysite.ru:80/ type TCP/IP protocol HTTP data collected Tue, 10 Oct 2017 13:15:03
Все нормально. А теперь поменяем на сайте номер телефона и подождем очередную проверку.
Снова проверяем:
# monit status mysite.ru_content_tel Monit 5.24.0 uptime: 1h 31m Remote Host 'mysite.ru_content_tel' status Connection failed monitoring status Monitored monitoring mode active on reboot start port response time FAILED to [mysite.ru]:80/ type TCP/IP protocol HTTP data collected Tue, 10 Oct 2017 13:17:03
У нас есть аларм в консоле, а так же пришло оповещение на email такого вида:
Connection failed Service mysite.ru_content_tel Date: Tue, 10 Oct 2017 13:17:03 Action: alert Host: myserver.ru Description: failed protocol test [HTTP] at [mysite.ru]:80/ [TCP/IP] -- HTTP error: Regular expression doesn't match: No match Your faithful employee, Monit
Теперь придумаем уникальный HTTP-заголовок который будет отдавать наш web-сервер и попробуем написать проверку этого заголовка.
У меня на сервере используется nginx, поэтому я напишу создание заголовка для него.
Заголовок будет X-Monit со статическим значением my_private_string
server { server_name mysite.ru; .... add_header X-Monit "my_private_string"; .... }
Теперь проверим наличие нашего заголовка в ответе сервера:
# curl -D - -o /dev/null -s mysite.ru HTTP/1.1 200 OK Server: nginx Date: Tue, 10 Oct 2017 08:33:48 GMT Content-Type: text/html; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive Last-Modified: Mon, 09 Oct 2017 10:02:36 GMT ETag: "514a52f150a79ffcede3aa4aefe777a7" Cache-Control: private, max-age=0 X-Monit: my_private_string
Все есть, пишем проверку для Monit.
К сожалению monit не умеет проверять HTTP заголовки и поэтому нам придется написать простенький скрипт на shell, который проверяет нужные нам заголовки и выдает результат, пишем:
Создаем файл /usr/sbin/monit_check_mysite_header.sh такого вида:
#!/usr/bin/env bash mysite="http://mysite.ru" myheader="X-Monit" mystring="my_private_string" shopt -s extglob while IFS=':' read key value; do value=${value##+([[:space:]])}; value=${value%%+([[:space:]])} case "$key" in ${myheader}) myresult="$value" ;; esac done < <(curl -sI "${mysite}") if [ -z "${myresult}" ]; then echo "X-Monit-Empty" exit 2 else if [[ "${myresult}" == "${mystring}" ]]; then echo "OK" else echo "X-Monit-Wrong" exit 2 fi fi
Не забываем сделать файл исполняемым
chmod a+x /usr/sbin/monit_check_mysite_header.sh chown root:root /usr/sbin/monit_check_mysite_header.sh
В файле /etc/monit/conf.d/mysite пишем:
check program mysite.ru_content_x_monit with path "/usr/sbin/monit_check_mysite_header.sh" group mysite if status != 0 then alert
Проверяем конфигурацию и перезагружаем её, потом ждем результатов проверки и смотрим:
# monit -t Control file syntax OK # monit reload Reinitializing monit daemon # monit status mysite.ru_content_x_monit Monit 5.24.0 uptime: 2h 41m Program 'mysite.ru_content_x_monit' status OK monitoring status Monitored monitoring mode active on reboot start last exit value 0 last output OK data collected Tue, 10 Oct 2017 14:27:42
Все есть, нужны нам заголовок присутствует.
А теперь давайте изменим содержимое нашего заголовка в nginx и подождем.
# monit status mysite.ru_content_x_monit Monit 5.24.0 uptime: 2h 49m Program 'mysite.ru_content_x_monit' status Status failed monitoring status Monitored monitoring mode active on reboot start last exit value 2 last output X-Monit-Wrong data collected Tue, 10 Oct 2017 14:36:00
Мы видим last output = X-Monit-Wrong, то есть наш заголовок стал не совпадать с тем что нужно.
Так же нам на почту пришло уведомление об этом:
Status failed Service mysite.ru_content_x_monit Date: Tue, 10 Oct 2017 14:35:56 Action: alert Host: myserver.ru Description: status failed (2) -- X-Monit-Wrong Your faithful employee, Monit
Можно вообще убрать наш секретный заголовок X-Monit в nginx и тогда при следующей проверке в Monit будет статус X-Monit-Empty, то есть заголовка нет вообще.
Конечно заголовок должен быть не статическим как сделал я для примера, а динамическим и формироваться по определенному секретному алгоритму и тогда без вскрытия настроек web-сервера злоумышленники никогда не смогут подделать его и даже если они взломают ftp аккаунт сервера и БД сервера и скопируют их содержимое чтобы запустить абсолютно полную копию Вашего сайта, то Ваша проверка тут же это выявит по отсутствию секретного заголовка.
Проверка доступности и работоспособности базы данных сайта.
Данный вид простой проверки мы реализует с помощью скрипта на php, который будет лежать в определенной папке сайта, скрипт делает подключение в БД MySQL сайта, если все хорошо, то выдает OK, если что-то не так, то ERR. Monit периодически будет делать запрос к этому скрипту и проверку контента. Конечно такой вид проверки очень далек от идеала и есть масса ограничений в его работе, например если «упадет» web-сервер то и проверка БД выдаст ошибку или если «зависнет» процесс php-fpm, то проверка тоже потерпит фиаско, но вот если «упадет» БД на сервере, то тут скрипт однозначно скажет об этом.
Скрипт не выполняет никаких проверочных SQL запросов к БД, он просто подключается к MySQL и выбирает нужную БД. Вы можете изменить скрипт так, чтобы он делал простой SQL-запрос, например выводил количество записей в какой-либо табличке, это даст дополнительную уверенность, что в БД есть какие-либо данные и она не пустая.
Итак, сам php скрипт будет таким (расположим его в корне сайта с именем mysqlcheck.php):
<?php $host='localhost'; $port='3306'; $user='debian-sys-maint'; $password='XXXXXXXX'; $db_name='mysite'; $link = @mysqli_connect($host.($port!='' ? ':'.$port : ''), $user, $password, $db_name); if (!$link) { echo "Ошибка: Невозможно установить соединение с MySQL." . PHP_EOL . "<br>"; echo "Код ошибки errno: " . mysqli_connect_errno() . PHP_EOL . "<br>"; echo "Текст ошибки error: " . mysqli_connect_error() . PHP_EOL . "<br>"; exit; } echo 'OK'; mysqli_close($link); ?>
В файле /etc/monit/conf.d/mysite пишем:
check host mysite.ru_mysql with address mysite.ru group mysite if failed url http://mysite.ru/mysqlcheck.php and content == "OK" timeout 2 seconds 3 cycles then alert
Проверяем конфигурацию и перезагружаем её, потом ждем результатов проверки и смотрим:
# monit -t Control file syntax OK # monit reload Reinitializing monit daemon # monit status mysite.ru_mysql Monit 5.24.0 uptime: 2h 41m Remote Host 'mysite.ru_mysql' status OK monitoring status Monitored monitoring mode active on reboot start port response time 88.695 ms to mysite.ru:80/mysqlcheck.php type TCP/IP protocol HTTP data collected Tue, 10 Oct 2017 15:21:56
Все отлично. Если хотите удостовериться в работе скрипта, то остановите БД MySQL и при очередной проверке Вы получите уведомление на email «HTTP error: Regular expression doesn’t match: No match».
Проверка истечение срока регистрации доменного имени.
Данный вид проверки так же не решается силами одного Monit, для проверки нам понадобиться сторонний скрипт на shell, но с ним все гораздо проще, он уже есть в моем репозитарии, остается только скачать его и написать небольшой shell-скрипт для анализа результата работы domain-check.pl.
wget https://raw.githubusercontent.com/CHERTS/linux-scripts/master/dns/domain-check/domain-check.pl -O /usr/sbin/domain-check.pl chmod a+x /usr/sbin/domain-check.pl chown root:root /usr/sbin/domain-check.pl
Пишем простой скрипт для monit для проверки истечение срока регистрации доменного имени:
Сохраняем его в /usr/sbin/monit_check_mysite_expire.sh
#!/usr/bin/env bash domain="mysite.ru" interval="10" domain_days_left=$(domain-check.pl -d=${domain} | grep ${domain} | sed '1,1d' | awk -F'/' '{print $2}' | sed 's, ,,g') if [ ${domain_days_left} -lt ${interval} ]; then echo "Registration of domain ${domain} will expire in ${domain_days_left} days." exit 2; elif [ ${domain_days_left} -eq 0 ]; then echo "Registration of the domain ${domain} has expired." exit 2; else echo "OK" fi exit 0;
Не забываем сделать файл исполняемым
chmod a+x /usr/sbin/monit_check_mysite_expire.sh chown root:root /usr/sbin/monit_check_mysite_expire.sh
В файле /etc/monit/conf.d/mysite пишем:
check program mysite.ru_domain with path "/usr/sbin/monit_check_mysite_expire.sh" group mysite if status != 0 then alert
Проверяем конфигурацию и перезагружаем её, потом ждем результатов проверки и смотрим:
# monit -t Control file syntax OK # monit reload Reinitializing monit daemon # monit status mysite.ru_domain Monit 5.24.0 uptime: 2h 41m Remote Host 'mysite.ru_domain' status OK monitoring status Monitored monitoring mode active on reboot start last exit value 0 last output OK data collected Tue, 10 Oct 2017 16:48:02
Все отлично. Проверка работает.
Чтобы убедиться в работоспособности измените в скрипте /usr/sbin/monit_check_mysite_expire.sh параметр interval с 10 до 1000 и подождите, при следующей проверке monit выдаст оповещение.
И в заключении я приведу всю конфигурацию для мониторинга сайта.
Это наш файл /etc/monit/conf.d/mysite который получился по результатам статьи:
check host mysite.ru_ping with address mysite.ru group mysite if failed ping4 count 5 with timeout 10 seconds then alert check host mysite.ru_connect with address mysite.ru group mysite if failed port 80 protocol http and request / for 2 cycles then alert if failed port 443 protocol https and request / for 2 cycles then alert check host mysite.ru_http with address mysite.ru group mysite if failed port 80 protocol http and request / status = 200 for 2 cycles then alert check host mysite.ru_ssl with address mysite.ru group mysite if failed port 443 protocol https and certificate valid > 7 days then alert check host mysite.ru_ssl_checksum with address mysite.ru group mysite if failed port 443 protocol https and certificate checksum sha1 = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" then alert check host mysite.ru_content_tel with address mysite.ru group mysite if failed url http://mysite.ru with content = "XXX-XX-XX" for 2 cycles then alert check program mysite.ru_content_x_monit with path "/usr/sbin/monit_check_mysite_header.sh" group mysite if status != 0 then alert check host mysite.ru_mysql with address mysite.ru group mysite if failed url http://mysite.ru/mysqlcheck.php and content == "OK" timeout 2 seconds 3 cycles then alert check program mysite.ru_domain with path "/usr/sbin/monit_check_mysite_expire.sh" group mysite if status != 0 then alert
Мы рассмотрели вопрос мониторинга работоспособности сайта с помощью системы Monit, данные виды проверок позволяют достаточно эффективно и быстро диагностировать перебои в работе сайта, а так же позволяют заблаговременно оповестить владельца сайта о наступлении возможных проблем.
На этом все, до скорых встреч. Если у Вас возникли вопросы или Вы хотите чтобы я помог Вам, то Вы всегда можете связаться со мной разными доступными способами.
Профессионально занимаюсь системным администрированием Linux -серверов и баз данных (MySQL, PostgreSQL) на протяжении последних 24 лет.
Очень полезная статья.
Как раз занимался вопросом мониторинга сайтов с помощью Monit, а тут такая помощь!