Базовая настройка
# http { ... }
# Зоны: ключ — адрес клиента, 10 МБ памяти хватает на ~160 тыс. адресов
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=search:10m rate=30r/m;
limit_conn_zone $binary_remote_addr zone=conn:10m;
limit_req_status 429;
# server { ... }
limit_conn conn 30;
location / {
limit_req zone=general burst=40 nodelay;
# ...
}
location = /login {
limit_req zone=login burst=5;
# ...
}
location /search {
limit_req zone=search burst=10 nodelay;
# ...
}Как выбирать значения
- rate — средняя скорость, которую вы готовы разрешить. Смотрите на реальный трафик в журналах и закладывайте запас в 2–3 раза.
- burst — допустимый всплеск. Без него посетитель, открывший страницу с десятком ресурсов, получит отказ.
- nodelay — обрабатывать всплеск сразу, а не растягивать во времени. Обычно нужен для страниц и не нужен для форм входа.
Исключения
geo $limit_exempt {
default 0;
10.0.0.0/8 1; # внутренняя сеть
192.0.2.10 1; # офис (адрес условный)
}
map $limit_exempt $limit_key {
0 $binary_remote_addr;
1 ""; # пустой ключ — лимит не применяется
}
limit_req_zone $limit_key zone=general:10m rate=10r/s;Типичные ошибки
- Один жёсткий лимит на весь сайт: статика упирается в него и страницы ломаются.
- Лимит по $remote_addr за прокси или CDN: все посетители получают один адрес и упираются в общий лимит. Сначала настройте реальный IP.
- Директивы вида «limit_req off» не существуют: чтобы отключить лимит для части путей, используйте пустой ключ через map.
- Отсутствие limit_req_status 429: по умолчанию nginx отвечает 503, и это путают со сбоем.
Вопросы и ответы
Защитит ли limit_req от серьёзного DDoS?
Нет. Лимит отклоняет лишние запросы, но nginx всё равно принимает каждое соединение и тратит на него ресурсы. Это хорошая защита от переборов и небольших всплесков, а от крупной атаки нужна фильтрация перед сервером.
Как проверить лимиты, не рискуя посетителями?
Добавьте limit_req_dry_run on (nginx 1.17.1 и новее): запросы не отклоняются, но превышения пишутся в error.log. Посмотрите несколько дней журнала и только потом включайте блокировку.