Навіщо обмежувати частоту запитів у 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.