Почему не работает ограничение запросов в Nginx
Решение проблем с rate limiting в Nginx. Основные причины неработающего ограничения запросов и правильная настройка конфигурации.
Почему не работает ограничение запросов в Nginx? Я новичок в Nginx и пытаюсь настроить rate limiting для защиты своего VDS от перегрузки. В конфигурации ниже я указал лимит в 30 запросов в секунду, но при тестировании с помощью Python-скрипта сервер не блокирует избыточные запросы. В чём может быть проблема?
Конфигурация Nginx:
# Редирект с HTTP на HTTPS
server {
listen 80;
server_name example.ru www.example.ru;
return 301 https://$host$request_uri;
}
limit_req_zone $http_your_auth_token zone=mylimit:10m rate=30r/s;
# HTTPS сервер
server {
listen 443 ssl;
server_name example.ru www.example.ru;
# SSL сертификаты
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.key;
# Базовые SSL настройки
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Логи
access_log /var/log/nginx/backend_access.log;
error_log /var/log/nginx/backend_error.log;
location / {
limit_req zone=mylimit burst=1 nodelay;
proxy_pass http://service:8080;
# Заголовки для backend
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Таймауты
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
}
}
Тестовый Python-скрипт:
from requests import get
import warnings
from urllib3.exceptions import InsecureRequestWarning
# Отключаем предупреждения о небезопасных запросах
warnings.simplefilter('ignore', InsecureRequestWarning)
for i in range(1000):
res = get("https://localhost/sight/", verify=False)
print(res.status_code)
Если ваше ограничение запросов в Nginx не работает, несмотря на корректную конфигурацию, проблема обычно кроется в одной из частых ошибок настройки. Рассмотрим основные причины и решения.
Содержание
- Основные причины неработающего rate limiting
- Проблема с ключом зоны
- Неправильное расположение директив
- Отсутствие параметра nodelay
- Конфликты location-блоков
- Необходимая перезагрузка Nginx
- Дополнительные проверки
- Рабочий пример конфигурации
- Мониторинг rate limiting
- Источники
Основные причины неработающего rate limiting в Nginx
Nginx rate limiting часто не работает из-за нескольких типичных ошибок в конфигурации. В вашем случае проблема может быть связана с неправильным выбором ключа для ограничения, расположением директив или отсутствием обязательных параметров. Давайте разберем каждую детально.
Проблема с ключом зоны limit_req_zone
Главная ошибка в вашей конфигурации — использование $http_your_auth_token в качестве ключа для rate limiting:
limit_req_zone $http_your_auth_token zone=mylimit:10m rate=30r/s;
Проблема в том, что заголовок your_auth_token может отсутствовать в запросах:
- Тестовый скрипт не отправляет этот заголовок — ваш Python-код не включает кастомные заголовки
- Ключ должен быть уникальным для каждого клиента — без заголовка все запросы попадают в одну группу
- Вместо этого используйте
$binary_remote_addr— это IP-адрес клиента в двоичном формате, который всегда присутствует:
# Правильный вариант
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=30r/s;
Для использования JWT токенов или других идентификаторов убедитесь, что заголовок всегда отправляется клиентами. Официальная документация Nginx рекомендует $binary_remote_addr для базового ограничения.
Неправильное расположение директив в location-блоке
В вашей конфигурации директива limit_req стоит после proxy_pass:
location / {
limit_req zone=mylimit burst=1 nodelay;
proxy_pass http://service:8080;
...
}
Это неправильный порядок. Nginx обрабатывает директивы последовательно, и proxy_pass немедленно перенаправляет запрос. Rate limiting должен проверяться до перенаправления:
location / {
limit_req zone=mylimit burst=1 nodelay;
proxy_pass http://service:8080;
...
}
Важно: Если вы используете
try_files, разместитеlimit_reqперед ним. Директивы обработки запросов должны идти в начале location-блока.
Отсутствие параметра nodelay при высоких нагрузках
В вашей конфигурации есть параметр nodelay, но при тестировании с 1000 запросами он критически важен. Без nodelay Nginx будет накапливать избыточные запросы в очереди и задерживать их вместо немедленного отклонения.
limit_req zone=mylimit burst=1 nodelay;
Как это работает:
- Без
nodelay: запросы ставятся в очередь (доburst), обрабатываются с задержкой - С
nodelay: избыточные запросы отклоняются немедленно (код 429)
Для защиты от ботов и атак nodelay — обязательный параметр. Блог NGINX подчеркивает его важность для реальных сценариев.
Конфликты location-блоков и совпадение URL
Убедитесь, что ваш тестовый URL /sight/ точно совпадает с location-блоком. Небольшие различия могут привести к тому, что rate limiting не применится:
- Добавление/удаление слэша:
/sight≠/sight/ - Наличие индексного файла:
/sightможет обрабатываться отдельно от/sight/ - Конфликт с другими location-блоками: более специфичные блоки имеют приоритет
Проверка в логах:
tail -f /var/log/nginx/backend_access.log
Ищите записи о rate limiting (код 429) и проверяйте точный URL из запроса.
Необходимая перезагрузка Nginx после изменений
Важно помнить, что изменения в конфигурации Nginx требуют перезагрузки:
sudo nginx -t # проверка конфигурации
sudo systemctl reload nginx # перезагрузка без разрыва соединений
Без этого изменения не применяются. По данным ServerFault, это одна из самых частых причин неработающих настроек.
Дополнительные проверки
-
Проверка заголовка в запросах:
bashcurl -H "your_auth_token: test" https://example.ru/sight/Убедитесь, что заголовок приходит на бэкенд.
-
Проверка логов на ошибки:
bashgrep -i "limit_req" /var/log/nginx/error.log -
Проверка зоны shared memory:
bashsudo nginx -T 2>&1 | grep mylimit -
Тестирование с IP-адресом вместо localhost:
pythonres = get("https://your_server_ip/sight/", verify=False, headers={'your_auth_token': 'test'})
Рабочий пример конфигурации
# Базовое ограничение по IP
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=30r/s;
server {
listen 443 ssl;
server_name example.ru;
location /sight/ {
# Применяем ограничение ДО проксирования
limit_req zone=mylimit burst=5 nodelay;
proxy_pass http://service:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Мониторинг rate limiting
Для отладки добавьте метрики в лог:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'limit_status=$limit_status';
Затем анализируйте поле $limit_status в логах. При срабатывании rate limiting его значение будет LIMITED.
Заключение
Nginx rate limiting не работает чаще всего из-за:
- Неправильного ключа (используйте
$binary_remote_addr) - Некорректного расположения директив (
limit_reqпередproxy_pass) - Отсутствия
nodelayдля немедленного отклонения - Конфликта location-блоков
- Отсутствия перезагрузки Nginx
Для защиты VDS от перегрузки рекомендуется комбинировать IP-ограничение с аутентификацией через заголовки, но всегда тестируйте конфигурацию на реальном трафике и анализируйте логи.