Анализ access логов NGINX.

У нас на хосте развернут стек LEMP использующий NGINX в качестве веб сервера. А для NGINX настроено логирование и ротация логов. Пришло время заглянуть непосредственно в access лог и разобраться, какую информацию он нам дает.

[root@waky ~]# tail /var/log/nginx/waky.ru/access.log
...
5.255.253.36 - - [17/Mar/2025:14:09:23 +0700] "GET /sitemap.xml HTTP/1.1" 200 4733 "-" "Mozilla/5.0 (compatible; YandexWebmaster/2.0; +http://yandex.com/bots)"
176.55.35.233 - - [17/Mar/2025:14:30:29 +0700] "GET / HTTP/2.0" 200 62058 "https://waky.ru/%d0%b2%d1%81%d0%b5-%d0%b7%d0%b0%d0%bc%d0%b5%d1%82%d0%ba%d0%b8/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36"
...

По умолчанию в NGINX используется именно такой формат. Он задан в файле конфигурации /etc/nginx/nginx.conf

...
log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
...

Теперь имея под рукой пару примеров и шаблон, разберем каждый аргумент в строке лога.

$remote_addr176.55.35.233 / 5.255.253.36 — адрес, с которого пришел запрос, в большинстве случаев это IP адрес, а иногда доменное имя

первый прочерк, не несет смысловой нагрузки, может немного путать, так как таким же прочерком может обозначаться отсутствие значения аргумента, но в данном случае это лишь прочерк в шаблоне

$remote_user — в обоих примерах на месте данного аргумента стоит прочерк , так как значение отсутствует, такую картину вы будете видеть в подавляющем количестве случаев, $remote_user отображает имя пользователя, под которым была пройдена Basic Auth авторизация

[$time_local][17/Mar/2025:14:09:23 +0700] / [17/Mar/2025:14:30:29 +0700] — время поступления запроса, время указано локальное серверное.

«$request»«GET /sitemap.xml HTTP/1.1» / «GET / HTTP/2.0» 200 — сам запрос, состоит из трех частей: тип запроса для обычного сайта это либо GET, либо POST; страница запроса, путь указан локальный, где / это корневая веб директория; версия HTTP протокола по которому происходит подключение.

$status200 / 200код статуса ответа от веб сервера, где 200 это успешно обработанный запрос

$body_bytes_sent4733 / 62058 объем данных в байтах отправленных по запросу

«$http_referer»«-« / «https://waky.ru/%d0%b2%d1%81%d0%b5-%d0%b7%d0%b0%d0%bc%d0%b5%d1%82%d0%ba%d0%b8/» — страница с которой пришел запрос, может быть как внешней, так и внутренней, в случае прямого обращения к странице — прочерк

«$http_user_agent»«Mozilla/5.0 (compatible; YandexWebmaster/2.0; +http://yandex.com/bots)» / «Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36» — юзер агент содержит информацию о клиентском браузере, либо название бота и информацию о нем если его создатели используют бота в открытую.

«$http_x_forwarded_for» — в примерах отсутствует, отображает реальный IP с которого пришел запрос, если тот поступил через прокси либо балансировщик нагрузки.

Понимая, что значит каждый элемент в логах, мы можем использовать это в повседневных задачах. Например, при всплеске нагрузки мы можем проверить с каких адресов в это время было сделано больше всего запросов.

[root@waky ~]# grep "17/Mar/2025:14" /var/log/nginx/waky.ru/access.log | awk '{print $1}' | sort | uniq -c | sort -n | tail
      11 196.251.90.93
      11 209.172.2.50
      16 45.157.54.155
      16 47.119.16.237
      17 5.255.253.36
      22 82.52.20.36
      25 95.214.53.106
      31 95.214.53.107
      52 185.242.226.10
    114 176.55.35.233

Мы ищем в лог файле все строки с датой 17/Mar/2025 и часом 14, и от каждой строки берем только первую часть (адрес) с помощью команды awk, сортируем по количеству и оставляем топ 10 значений.
Меняя значение в awk ‘{print $1}’ можно сортировать, например по странице обращения {print $7} или коду ответа {print $9}.

Если обнаружили подозрительный адрес, проверьте, какие запросы от него исходили за последнее время:

grep "17/Mar/2025:14" /var/log/nginx/waky.ru/access.log | grep "176.55.35.233" | awk '{print $7}' | sort | uniq -c | sort -n | tail

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

Основа работы с логами состоит в том, чтобы из всего объема информации выудить ту, которая связана непосредственно с решаемой задачей. Если это скачки нагрузки — найти адреса с которых приходит больше всего запросов. Если сайт стал чаще выдавать ошибки — собрать список страниц, которые возвращают соответствующие коды ответов.

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