Nginx. Количество запросов с ip-адреса
В Nginx есть встроенный модуль ngx_http_limit_req_module, который позволяет ограничить количество запросов с одного ip-адреса.
1. Определение зоны для хранения ip-адресов
Сначала нужно определить «зону» в общей памяти, где Nginx будет хранить информацию о ip-адресах и времени их последнего запроса. Настройка добавляется в секцию http главного конфигурационного файла nginx.conf.
http { # ... прочие настройки ... # limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; # # Разбор директивы: # $binary_remote_addr — Переменная, содержащая IP-адрес клиента в бинарном формате. # Это экономит память по сравнению с текстовым $remote_addr. # zone=one:10m — Имя зоны «one» и ее размер «10m» (10 мегабайт). 10 МБ могут # хранить состояние примерно для 160 тысяч IP-адресов. # rate=1r/s — Устанавливает макс. среднюю скорость запросов, например # 1r/s = 1 запрос в секунду, 30r/m = 30 запросов в минуту. limit_req_zone $binary_remote_addr zone=perip:10m rate=5r/s; # ... прочие настройки ... }
2. Применение ограничения к нужным location
Теперь, когда зона определена, можно применить это ограничение к всему сайту или к отдельным его частям (например, к форме входа или API) в секции server файла конфигурации сайта.
server { # ... прочие настройки ... location / { # Применяем зону с именем «perip», которую мы определили выше. # burst=20 — «всплеск». Позволяет клиенту сделать до 20 запросов сверх лимита, прежде # чем он начнет получать ошибку 503 (Service Temporarily Unavailable). Это # полезно для браузеров, которые одновременно запрашивают много ресурсов # (CSS, JS, картинки, шрифты). # nodelay — Директива, которая в паре с burst=20 обрабатывает «лишние» запросы сразу, # а не с задержкой. После превышения burst запросы будут отклоняться. limit_req zone=perip burst=20 nodelay; # ... остальные настройки для location, например, proxy_pass ... proxy_pass http://backend; } # Можно применить более строгие правила, например, для страницы входа location /login.php { limit_req zone=perip burst=5 nodelay; # ... прочие настройки ... } }
3. Перезагрузка конфигурации Nginx
- Проверить синтаксис конфигурации командой
nginx -t - Перезагрузить конфигурацию Nginx командой
systemctl reload nginx
Начинать лучше с не слишком строгих ограничений (rate=5r/s, burst=20) и потом наблюдать за логами. Если в лог-файле ответов с кодом 429 (см. ниже) будет мало — можно установить более жесткие ограничения.
4. Код ответа 429 вместо 503
По умолчанию клиенты будут получать код ответа 503 Service Temporarily Unavailable, лучше вместо этого использовать 429 Too Many Requests.
server { # ... прочие настройки ... location / { limit_req zone=perip burst=20 nodelay; # Устанавливаем код ответа 429 для заблокированных запросов limit_req_status 429; # ... остальные настройки для location, например, proxy_pass ... proxy_pass http://backend; } # Можно применить более строгие правила, например, для страницы входа location /login.php { limit_req zone=perip burst=5 nodelay; # Устанавливаем код ответа 429 для заблокированных запросов limit_req_status 429; # ... прочие настройки ... } # ... прочие настройки ... }
5. Конфигурация с реверс-прокси
Допустим, веб-сервер находится под защитой, то есть, является бэкендом для сервера защиты от DDoS атак. Так что применяя типовую конфигурацию — мы заблокируем прокси-сервер защиты, поскольку наш Nginx получает все запросы от него.
Нужно в конфигурации использовать HTTP-заголовок, в который сервис защиты записывает реальный ip-адрес посетителя — X-Forwarded-For или X-Real-IP. Nginx должен «доверять» этому заголовку и использовать его для определения настоящего ip-адреса клиента.
5.1. Настройка модуля ngx_http_realip_module
Этот модуль обычно включен в стандартную сборку Nginx. Его задача — подменить внутреннюю переменную $remote_addr значением из указанного заголовка, но только для доверенных ip-адресов.
http { # ... прочие настройки ... # Указать ip-адрес прокси-сервера (защиты от DDoS). Nginx будет доверять # заголовку X-Forwarded-For только от этого ip-адреса или этой подсети. set_real_ip_from 192.0.2.1; # пример ip-адреса прокси set_real_ip_from 198.51.100.0/24; # пример подсети прокси # Указать, из какого заголовка брать реальный ip-адрес. Заголовок # X-Forwarded-For используется по умолчанию, но лучше указать явно. real_ip_header X-Forwarded-For; # Эта директива указывает, что Nginx должен брать самый левый (первый) IP # из списка в заголовке X-Forwarded-For, так как именно он является исходным # IP клиента. По умолчанию используется самый правый, что в данном случае # будет ошибкой. real_ip_recursive on; # ... прочие настройки ... }
5.2. Ограничение запросов по реальному ip-адресу
После настройки realip_module — Nginx будет автоматически помещать реальный ip-адрес клиента в переменные $remote_addr и $binary_remote_addr. Теперь исходная конфигурация ограничения будет работать правильно — не нужно ничего в ней менять.
http { # ... прочие настройки ... # Директивы для определения реального ip-адреса клиента set_real_ip_from 192.0.2.1; set_real_ip_from 198.51.100.0/24; real_ip_header X-Forwarded-For; real_ip_recursive on; # Настраиваем зону ограничения, $binary_remote_addr будет # содержать реальный ip клиента, а не ip прокси-сервера. limit_req_zone $binary_remote_addr zone=perip:10m rate=5r/s; # ... прочие настройки ... } server { # ... прочие настройки ... location / { limit_req zone=perip burst=20 nodelay; # Устанавливаем код ответа 429 для заблокированных запросов limit_req_status 429; # ... остальные настройки для location, например, proxy_pass ... proxy_pass http://backend; } # Можно применить более строгие правила, например, для страницы входа location /login.php { limit_req zone=perip burst=5 nodelay; # Устанавливаем код ответа 429 для заблокированных запросов limit_req_status 429; # ... прочие настройки ... } # ... прочие настройки ... }
Поиск: Сервер • Защита • Запрос • Модуль • ngx_http_limit_req_module • Настройка • Конфигурация • limit