Как вести отдельные логи (журналы) доступа для запросов от автоматизированных систем ботов в nginx?
Из документации NGINX нужно знать о существовании двух модулей:
- Модуль ngx_http_log_module
- Модуль ngx_http_map_module
Первый отвечает за сами файлы логов и стиль наполнения. Второй задаёт правила фильтрации HTTP-запросов, которые должны будут попадать в нужный нам лог.
Первый пишем внутри настроек файла «виртуального хоста» — например «efim360.ru.conf«. Второй пишем в главном конфигурационном файле «nginx.conf«.
Первый попадает в директиву «server«. Второй попадает в директиву «http«.
Как фильтрация ботов по логам будет выглядеть в файлах?
папка «/etc/nginx/sites-available» —>> «efim360.ru.conf» —>> «server»
server { # какие-то ваши настройки access_log /var/log/nginx/efim360.ru_access_amazon_bot.log combined if=$ua_amazon_bot; access_log /var/log/nginx/efim360.ru_access_google_bot.log combined if=$ua_google_bot; access_log /var/log/nginx/efim360.ru_access_yandex_bot.log combined if=$ua_yandex_bot; access_log /var/log/nginx/efim360.ru_access_semrush_bot.log combined if=$ua_semrush_bot; # какие-то ваши настройки }
access_log — это само название директивы в NGINX. Это часть его синтаксиса.
/var/log/nginx/efim360.ru_access_amazon_bot.log — это путь до файла журнала, в который мы запишем нужный запрос
combined — это предопределённый формат записи элементов HTTP-запроса (значение по умолчанию). В вашем случаем могут быть любые дополнительные форматы, если их кто-то создавал.
if=$ua_amazon_bot — это условная конструкция, которая дёргает значение из переменной $ua_amazon_bot. В нашем примере получается так: если пользовательский агент содержит в своей строке что-то вида «amazonbot«, то в переменную $ua_amazon_bot попадает значение 1 в секции «http» основного конфигурационного файла. Когда проброс дойдёт до виртуального хоста до секции «server«, тогда там директива access_log распознает значение данной переменной и запишет его в соответствующий лог (журнал). Цифра 1 приведётся к логическому типу и вернёт true — значит нужно писать.
папка «/etc/nginx» —>> «nginx.conf» —>> «http»
http { # какие-то ваши настройки map $http_user_agent $ua_amazon_bot { default 0; ~*amazonbot 1; } map $http_user_agent $ua_google_bot { default 0; ~*googlebot 1; } map $http_user_agent $ua_semrush_bot { default 0; ~*semrushbot 1; } map $http_user_agent $ua_yandex_bot { default 0; ~*yandexbot 1; } # какие-то ваши настройки }
Вместо нескольких директив «map», можно сделать одну, если вы чётко понимаете каких ботов по каким логам нужно разложить.
Мы же рассмотрели пример, где каждый конкретный вид бота пишется в отдельный файл журнала. Это удобно, потому что можно сразу получить детальную статистику по количество совершённых запросов ботом.
Как отделить логи с ботами и без них в nginx?
Мы можем пойти немного дальше и добавить ещё две директивы «map» в директиву «http» файла «nginx.conf«.
map $http_user_agent $ua_bot { default 0; ~*googlebot 1; ~*yandexbot 1; ~*semrushbot 1; ~*amazonbot 1; } map $ua_bot $ua_notbot { 0 1; }
Первая частично дублирует логику предыдущих четырёх директив «map«. Её цель — точно определить ботов и все им расставить 1. Если запрос придёт от бота, то в переменной $ua_bot будет храниться значение 1.
Вторая директива «map» примет значение из этой переменной. Если будет 1 то в $ua_notbot ничего не попадёт и тогда в новый файл лога НЕБОТОВ мы не получим запись. Если примет 0, тогда $ua_notbot получит значение 1 — оно приведётся к true и мы запишем запись.
access_log /var/log/nginx/efim360.ru_access_notbot.log combined if=$ua_notbot;
Мы как бы реализовали отрицание вида «if not».