limit_req (ограничение запросов в nginx)
limit_req это директива nginx, которая включает ограничение частоты запросов для сервера или location. Она ссылается на зону общей памяти, объявленную через limit_req_zone, где хранится состояние по ключу, например по IP-адресу клиента, и задаёт максимальную скорость с необязательным burst. Запросы сверх лимита задерживаются или отклоняются с кодом ошибки.
Синтаксис: limit_req_zone и limit_req работают в паре
Модуль ngx_http_limit_req_module ограничивает скорость обработки запросов по ключу методом «дырявого ведра» (leaky bucket). Нужны две директивы:
limit_req_zone $key zone=name:size rate=rate;
limit_req zone=name [burst=number] [nodelay | delay=number];
limit_req_zone допустима только в контексте http. Ключом может быть текст, переменные или их сочетание, а запросы с пустым значением ключа не учитываются. Скорость задаётся в r/s, а если нужно меньше одного запроса в секунду, в r/m: 30r/m это пол-запроса в секунду, то есть один запрос в две секунды. limit_req допустима в http, server и location и значения по умолчанию не имеет.
У трёх связанных директив есть документированные значения по умолчанию: limit_req_status равна 503, limit_req_log_level равна error (задержки логируются уровнем ниже), limit_req_dry_run равна off. Состояние для $binary_remote_addr занимает 128 байт на 64-битных платформах, так что в зоне 1 МБ помещается около 8 тысяч состояний. Когда зона заполнена, удаляется наименее востребованное состояние.
Burst, nodelay и delay простыми словами
При burst по умолчанию, равном нулю, запрос, пришедший быстрее скорости зоны, отклоняется. Три параметра limit_req определяют судьбу таких избыточных запросов:
burst=Nдопускает до N избыточных запросов. Их обработка откладывается так, чтобы скорость оставалась заданной, а когда их число превысит N, запрос завершается с ошибкой.nodelayотключает задержку избыточных запросов, пока они ограничиваются. Запросы в пределах burst обслуживаются сразу, остальные отклоняются.delay=N(nginx 1.15.7 и новее) задаёт порог, с которого избыточные запросы начинают задерживаться. По умолчанию он равен нулю, то есть задерживаются все избыточные запросы.
Например, rate=1r/s с burst=5 означает в среднем не более одного запроса в секунду при всплесках до 5. nginx считает время в миллисекундах, поэтому 10r/s разносит запросы примерно на 100 мс. Берите nodelay для интерактивных страниц, где ожидание в очереди выглядит как зависание, и обычный burst, когда важнее сгладить нагрузку на бэкенд, чем задержку ответа.
Минимальный пример и проверка
Этот конфиг защищает страницу входа: примерно одна попытка в две секунды на адрес клиента с запасом на короткий всплеск, а в ответ отдаётся код, который для таких случаев определён в RFC 6585:
http {
limit_req_zone $binary_remote_addr zone=login:10m rate=30r/m;
server {
location = /login {
limit_req zone=login burst=5 nodelay;
limit_req_status 429;
}
}
}
Проверьте синтаксис и перезагрузите конфигурацию, не обрывая соединения:
sudo nginx -t && sudo systemctl reload nginx
for i in $(seq 1 12); do curl -s -o /dev/null -w "%{http_code}
" https://example.com/login; done
Запускайте цикл с машины, которую вы контролируете. Первые запросы вернут обычный код, остальные 429. Чтобы сначала подобрать значения на живом трафике, добавьте limit_req_dry_run on; (nginx 1.17.1 и новее): избыточные запросы считаются, но не ограничиваются, а переменная $limit_req_status принимает значения PASSED, DELAYED, REJECTED и варианты с суффиксом _DRY_RUN.
Подводные камни и место в защите сервера
Большинство неожиданностей с limit_req связано с ключом и наследованием:
- За CDN или обратным прокси
$binary_remote_addrэто адрес прокси, поэтому все делят один лимит. Сначала восстановите реальный адрес клиента, например модулем realip. - Лимиты наследуются с предыдущего уровня, только если на текущем уровне нет собственных
limit_req. К одному запросу могут применяться несколько директив, например на клиента и на сервер. - Одна загрузка страницы порождает много запросов, поэтому жёсткие лимиты ставьте на вход и API, а не на весь сайт.
- Код 503 по умолчанию в мониторинге выглядит как авария. Для ясности задайте
limit_req_status 429.
limit_req замедляет злоупотребления, но не выявляет их. Дополните его fail2ban для злостных нарушителей и прочитайте общую статью про ограничение частоты запросов. Руководство по безопасности nginx и руководство по защите от DDoS показывают, как это сочетается с другими мерами.
Связанные термины: Ограничение частоты запросов, nginx, fail2ban, Атака перебором, WAF.
Часто задаваемые вопросы
Что делает limit_req в nginx?
Она применяет к серверу или location лимит скорости из зоны, объявленной через limit_req_zone. Запросы быстрее заданной скорости задерживаются в пределах burst и отклоняются сверх него.
Чем отличаются burst и nodelay?
burst задаёт, сколько избыточных запросов терпится, и по умолчанию они задерживаются до заданной скорости. С nodelay запросы в пределах burst обслуживаются сразу, а остальные отклоняются.
Почему limit_req возвращает 503, а не 429?
nginx отклоняет запросы кодом 503, пока limit_req_status не задан иначе. Добавьте limit_req_status 429; чтобы отдавать Too Many Requests, который для этого случая определён в RFC 6585.
Где объявлять limit_req_zone?
Только в контексте http, вне блоков server. Затем зона подключается по имени директивой limit_req в http, server или location.
Почему лимит общий для всех пользователей?
Обычно ключ одинаков для всех: nginx стоит за прокси или CDN и видит один адрес. Восстановите реальный IP клиента, прежде чем использовать $binary_remote_addr как ключ.
Хотите увидеть, в каком состоянии ваш сервер?
Запустите бесплатную read-only проверку сервера или откройте Security Lab и посмотрите цикл обнаружение, сдерживание, восстановление, проверка в действии.
Получить бесплатную проверку сервераОткрыть Security Lab