Зачем ограничивать частоту запросов в Nginx
Модули limit_req и limit_conn защищают сервер от перегрузки: от ботов, которые перебирают формы, от парсеров, которые сканируют каталог, и от простого всплеска трафика после рекламной рассылки. Без лимитов один клиент способен занять все воркеры PHP-FPM и положить сайт для остальных посетителей.
limit_req ограничивает частоту запросов в секунду с одного IP-адреса. limit_conn ограничивает число одновременных соединений. Это разные механизмы, и часто их применяют вместе.
Как настроить limit_req
Зону памяти для лимита объявляют один раз в секции http {}, а применяют — в нужном location:
http {
limit_req_zone $binary_remote_addr zone=perip:10m rate=5r/s;
}
server {
location /login.php {
limit_req zone=perip burst=10 nodelay;
}
}Зона perip размером 10 МБ хранит примерно 160 тысяч уникальных IP-адресов. Параметр rate=5r/s означает 5 запросов в секунду с одного адреса в среднем.
Параметры limit_req: что они значают
| Параметр | Значение | Эффект |
|---|---|---|
| rate | 5r/s, 10r/m | Средняя частота запросов с одного адреса |
| burst | число запросов | Сколько запросов сверх rate поставить в очередь |
| nodelay | флаг | Не задерживать запросы из burst, а сразу пропускать |
| limit_req_status | код ответа | Какой код вернуть при превышении, по умолчанию 503 |
Без nodelay Nginx придерживает лишние запросы и отдаёт их с задержкой, выравнивая поток. С nodelay запросы из burst обрабатываются сразу, а лишние — сбрасываются кодом 503.
Как настроить limit_conn
limit_conn ограничивает число одновременных соединений с одного адреса — полезно против скачивания больших файлов в несколько потоков или медленных ботов:
http {
limit_conn_zone $binary_remote_addr zone=connperip:10m;
}
server {
location /download/ {
limit_conn connperip 3;
}
}Эта настройка разрешает не больше трёх одновременных соединений с одного IP-адреса к каталогу /download/.
Как вернуть понятный код ошибки
По умолчанию Nginx отдаёт код 503 Service Unavailable при превышении лимита. Для API логичнее код 429 Too Many Requests:
limit_req_status 429;
limit_conn_status 429;Дополнительно настройте кастомную страницу ошибки через error_page 429 /rate-limit.html;, чтобы посетитель увидел понятное сообщение, а не голый код ответа.
Где применять лимиты, а где нет
Разумно ограничивать не весь сайт, а точечные адреса:
- формы входа и регистрации — от перебора паролей
- поиск по сайту — от парсеров, которые грузят базу данных
- API — от клиентов, которые шлют запросы чаще договорённого
- статику и главную страницу лучше не трогать: там лимиты чаще мешают, чем помогают
Итог
Чек-лист для внедрения лимитов:
- объявить зону памяти limit_req_zone и limit_conn_zone в http {}
- применить лимит точечно — к формам входа, поиску и API
- подобрать rate и burst под реальный трафик, а не наугад
- вернуть код 429 вместо 503 там, где лимит защищает API
Лимиты стоит сочетать с общей защитой сервера: посмотрите статью про общее укрепление безопасности Nginx и про диагностику ошибок 502 и 504, которые часто возникают из-за перегрузки бэкенда, а не из-за самого Nginx.