
Как ограничить частоту запросов и соединений в Nginx
Настраиваем limit_req и limit_conn в Nginx: выбираем ключ, rate и burst, учитываем CDN и NAT, включаем dry run, проверяем 429 и читаем журнал.
Содержание
Форма входа получает сотни попыток за несколько секунд, а обычный пользователь отправляет один-два запроса. Nginx может ограничить частоту для одного адреса и сгладить короткий всплеск до того, как он займёт все рабочие процессы приложения.
Такой лимит защищает конкретный дорогой маршрут и уменьшает последствия ошибки клиента. Он не заменяет аутентификацию, блокировку учётной записи и внешнюю защиту от DDoS: трафик уже дошёл до вашего сервера.
Сначала выберите операцию и ключ
Не начинайте с глобального ограничения всего сайта. Статика, API, загрузка файла и вход имеют разную нормальную частоту. Запишите обычный пик, допустимый всплеск, стоимость одного запроса и желаемый ответ при превышении.
Чаще всего ключом служит IP-адрес в бинарном виде — $binary_remote_addr. Если перед Nginx стоит CDN или балансировщик, сначала настройте исходный IP и границу доверия. Иначе тысячи посетителей разделят один адрес proxy и попадут под общий лимит.
IP тоже не всегда равен одному человеку: офис, мобильный оператор и домашняя сеть используют NAT. Для авторизованного API приложение может ограничивать по учётной записи, а Nginx — дополнительно сдерживать грубый всплеск по адресу.
Объявите общую зону
В контексте http создайте область памяти для состояний клиентов. Следующая зона называется login_per_ip, использует бинарный IP как ключ и допускает в среднем пять запросов в секунду на один ключ:
limit_req_zone $binary_remote_addr zone=login_per_ip:10m rate=5r/s;
Размер 10 МБ хранит ключи и счётчики, а не тела запросов. Требуемая память зависит от числа одновременно отслеживаемых адресов. Если зона переполнится, новые записи создать не получится; следите за журналом и не назначайте размер случайно маленьким.
Примените предел к одному маршруту
Внутри точного location подключите зону. burst=10 разрешает короткий всплеск до десяти запросов сверх устойчивой скорости, а nodelay не заставляет допустимые запросы ждать в очереди:
location = /api/login {
limit_req zone=login_per_ip burst=10 nodelay;
limit_req_status 429;
proxy_pass http://127.0.0.1:3000;
}
Код 429 означает Too Many Requests и понятнее клиенту, чем стандартный для модуля код отказа. API должно показывать ясное сообщение и не обещать точное время ожидания, если оно не рассчитывается.
burst не превращает скорость 5 r/s в постоянные 15 r/s. Он лишь допускает краткий наплыв. Без nodelay часть запросов задерживается для выравнивания потока; это может занять соединения и ухудшить отклик интерактивного API.
Сначала наблюдайте без блокировки
Если ваша версия Nginx поддерживает dry run, временно включите его рядом с limit_req. Модуль посчитает превышения и запишет их, но не отклонит запросы:
limit_req_dry_run on;
limit_req_log_level notice;
Проверьте поддержку директивы через документацию установленной версии и nginx -t. Соберите нормальный период, включая рабочий пик. Затем оцените, сколько законных пользователей превысили порог и почему.
Dry run нельзя оставлять как единственную «защиту»: он нужен для настройки. Перед включением блокировки зафиксируйте измеренный rate, burst, область действия и способ быстрого отключения.
Ограничьте параллельные соединения отдельно
limit_req считает частоту запросов. Для долгих загрузок или потоков дополнительно может понадобиться число одновременных соединений. Зона соединений также объявляется в http:
limit_conn_zone $binary_remote_addr zone=connections_per_ip:10m;
В нужном server или location подключите предел. Следующая строка разрешает одному ключу до двадцати учитываемых соединений:
limit_conn connections_per_ip 20;
limit_conn_status 429;
Число 20 — пример. При HTTP/2 и HTTP/3 параллельные запросы учитываются модулем отдельно, хотя используют одно транспортное соединение. WebSocket и длительные скачивания тоже меняют картину. Проверяйте реальный протокол и сценарий, а не только число вкладок.
Не ограничивайте служебные проверки случайно
Мониторинг, health-check балансировщика и webhook внешнего сервиса могут обращаться чаще пользователя. Не добавляйте широкое исключение по заголовку, который может подделать клиент. Выделите служебный маршрут, ограничьте сеть и примените отдельную политику.
Не отключайте лимит для всех «известных ботов» по User-Agent. Заголовок свободно меняется и не подтверждает владельца запроса.
Проверьте в контролируемой среде
После nginx -t и reload сначала выполните несколько обычных запросов. Затем в staging отправьте короткую параллельную серию и выведите только HTTP-коды:
seq 1 20 | xargs -P5 -I{} \
curl -sS -o /dev/null -w '%{http_code}\n' \
'https://staging.example.com/api/login?probe={}'
Команда запускает до пяти curl одновременно. Не используйте её против чужого сервиса или production без окна и наблюдения. В результате должны быть видны успешные коды и, при превышении выбранной границы, 429.
Сопоставьте тест с error log и access log. Запишите $limit_req_status в диагностический формат: значения PASSED, DELAYED, REJECTED и их dry-run варианты показывают решение модуля.
Разберите ложные срабатывания
Если блокируется офис целиком, причиной может быть NAT. Если блокируются все посетители, проверьте $remote_addr за CDN. Если ограничение легко обходится сменой IPv6-адреса или распределённой сетью, не пытайтесь бесконечно уменьшать rate: нужна защита на другом уровне и прикладная проверка поведения.
При резком росте 429 смотрите одновременно нагрузку приложения и число уникальных ключей. Один ошибочный клиент и распределённая атака требуют разных действий.
Откат и дальнейшее наблюдение
Чтобы быстро вернуть прежнее поведение, удалите только limit_req или включите dry run, затем проверьте конфигурацию и выполните reload:
sudo nginx -t
sudo systemctl reload nginx
sudo tail -n 50 /var/log/nginx/error.log
Объявленная, но не используемая зона сама запросы не блокирует. После отката убедитесь, что законный сценарий снова работает и 429 исчезли. Затем исправьте ключ или значения на основании журналов.
Таймауты и размеры запроса настраиваются отдельно по руководству о лимитах Nginx, а результаты удобнее анализировать через расширенный access log.
Первоисточники
- Nginx: ngx_http_limit_req_module — зона, rate, burst, dry run и статус запроса.
- Nginx: ngx_http_limit_conn_module — ограничение параллельных соединений и особенности HTTP/2/3.
Самопроверка
Проверьте, что материал усвоен
Ответьте на все вопросы. Результат сохранится только в этом браузере и будет учтён в статистике прочитанных материалов.
Разбираем коротко
Частые вопросы
Защищает ли limit_req от любой DDoS-атаки?
Нет. Ограничение Nginx действует после достижения сервера и расходует его сеть и ресурсы. Крупные атаки требуют фильтрации у провайдера или внешнего защитного сервиса.
Чем rate отличается от burst в limit_req?
Rate задаёт устойчивую частоту обработки для одного ключа, а burst — размер допустимой очереди или краткого всплеска. Параметр nodelay пропускает burst сразу, но не отменяет общий предел.
Почему нельзя включать лимит по remote_addr за CDN без real IP?
Nginx увидит адрес CDN и объединит множество посетителей в один ключ. Сначала настройте доверенные сети и восстановление исходного адреса, затем проверьте журнал.


