sadrix logoSadriX
Минцифры готовит обязательную регистрацию IMEI смартфонов, купленных за границей
Гайды

Как ограничить частоту запросов в Nginx: пошаговая настройка rate limiting

Настройка limit_req_zone и limit_req для контроля нагрузки

01 874 просмотров5 мин
0
Поделиться:TelegramVK

Введение

Ограничение частоты запросов (rate limiting) — важный инструмент защиты веб-сервера от перегрузок, брутфорс-атак, парсинга и простейших DDoS. Nginx предоставляет встроенный модуль ngx_http_limit_req_module, который позволяет гибко настраивать лимиты для разных зон (по IP, по ключу, по расположению). В этом руководстве мы разберём, как правильно настроить ограничение частоты запросов в Nginx, чтобы не блокировать легитимных пользователей и при этом эффективно отсекать вредоносный трафик.

Требования

  • Установленный Nginx версии 1.10 и выше (модуль limit_req входит в стандартную сборку).

  • Права на редактирование конфигурационных файлов (обычно /etc/nginx/nginx.conf или файлы в /etc/nginx/conf.d/).

  • Базовые знания синтаксиса Nginx.

  • Доступ к командной строке сервера.

Шаг 1: Понимание принципов работы limit_req

Модуль limit_req использует алгоритм «leaky bucket» (протекающее ведро). Вы задаёте зону с определённой скоростью (например, 10 запросов в секунду), и Nginx пропускает запросы с этой скоростью. Если запросы приходят быстрее, они могут быть либо отклонены с кодом 503, либо поставлены в очередь (burst) с задержкой. Важно правильно выбрать ключ зоны — обычно это IP-адрес клиента ($binary_remote_addr), но можно использовать и другие переменные, например, $server_name или $http_user_agent.

Шаг 2: Определение зоны ограничения (limit_req_zone)

Директива limit_req_zone задаёт зону разделяемой памяти для хранения состояния. Она размещается в контексте http. Пример:

http {
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/s;
    ...
}

Здесь:

  • $binary_remote_addr — ключ, по которому ведётся учёт (IP-адрес в бинарном виде, экономит память).

  • zone=mylimit:10m — имя зоны и размер памяти (10 МБ хватает примерно на 160 000 уникальных IP).

  • rate=5r/s — разрешённая скорость: 5 запросов в секунду. Можно указывать в минутах: 30r/m.

Шаг 3: Применение ограничения в location (limit_req)

Директива limit_req включается в контексте http, server или location. Пример для location:

location /login/ {
    limit_req zone=mylimit burst=10 nodelay;
    proxy_pass http://backend;
}

Параметры:

  • zone=mylimit — имя зоны, определённой ранее.

  • burst=10 — разрешает всплеск до 10 запросов сверх установленной скорости. Эти запросы обрабатываются сразу, но следующие за ними будут отклоняться, пока не восстановится баланс.

  • nodelay — не задерживать обработку burst-запросов, а сразу их выполнять (без этого они бы помещались в очередь с задержкой).

Если не указать nodelay, то при превышении скорости запросы будут ставиться в очередь и обрабатываться с задержкой, что может увеличить время ответа.

Шаг 4: Настройка кода ошибки и логирования

По умолчанию при превышении лимита возвращается код 503 (Service Unavailable). Его можно изменить с помощью директивы limit_req_status (доступна с версии 1.3.15). Например:

limit_req_status 429;

Код 429 (Too Many Requests) более информативен для клиентов. Также можно настроить уровень логирования для отклонённых запросов:

limit_req_log_level warn;

По умолчанию используется уровень error. Уровень warn поможет снизить шум в логах.

Шаг 5: Разные лимиты для разных зон

Вы можете создать несколько зон с разными скоростями и применять их к разным частям сайта. Например, для API — строже, для статики — мягче:

http {
    limit_req_zone $binary_remote_addr zone=api:10m rate=2r/s;
    limit_req_zone $binary_remote_addr zone=static:10m rate=20r/s;

    server {
        location /api/ {
            limit_req zone=api burst=5 nodelay;
            ...
        }
        location /static/ {
            limit_req zone=static burst=30 nodelay;
            ...
        }
    }
}

Шаг 6: Исключение определённых IP из ограничений

Иногда нужно освободить от лимитов доверенные адреса (например, мониторинг или офис). Это делается с помощью директивы geo и переменной, которая будет пустой для исключённых IP:

http {
    geo $limit {
        default 1;
        192.168.1.0/24 0;
        10.0.0.1 0;
    }
    map $limit $limit_key {
        0 "";
        1 $binary_remote_addr;
    }
    limit_req_zone $limit_key zone=mylimit:10m rate=5r/s;
    ...
}

Теперь для IP из списка ключ будет пустым, и ограничения не применятся.

Шаг 7: Тестирование конфигурации и перезагрузка

После внесения изменений проверьте синтаксис:

nginx -t

Если ошибок нет, перезагрузите Nginx:

systemctl reload nginx

или

nginx -s reload

Шаг 8: Мониторинг и анализ логов

Следите за логами ошибок Nginx (/var/log/nginx/error.log), чтобы видеть, какие IP попадают под ограничения. Если лимиты слишком строгие, вы увидите много записей об отклонённых запросах. Анализируйте их и корректируйте параметры rate и burst. Также можно использовать сторонние инструменты, например, goaccess для анализа логов в реальном времени.

Шаг 9: Тонкая настройка burst и nodelay

Параметр burst определяет, сколько запросов может быть обработано сверх лимита одновременно. Если burst слишком мал, легитимные пользователи могут получать ошибки при кратковременных всплесках (например, при загрузке страницы с множеством ресурсов). Если слишком велик — защита ослабевает. Рекомендуется начинать с небольших значений (5–10) и увеличивать при необходимости. nodelay позволяет обрабатывать burst-запросы без задержки, что улучшает отзывчивость, но может привести к кратковременной перегрузке бэкенда. Если бэкенд слабый, лучше не использовать nodelay, чтобы запросы сглаживались.

Шаг 10: Использование limit_conn для ограничения соединений

Дополнительно к limit_req можно ограничить количество одновременных соединений с одного IP с помощью модуля limit_conn. Это полезно для защиты от медленных атак (slowloris). Пример:

http {
    limit_conn_zone $binary_remote_addr zone=addr:10m;
    ...
    server {
        location / {
            limit_conn addr 10;
            ...
        }
    }
}

Здесь разрешено не более 10 одновременных соединений с одного IP.

Типичные ошибки

1. Слишком строгий rate — приводит к блокировке реальных пользователей. Начните с более мягких значений и постепенно ужесточайте. 2. Отсутствие burst — при всплесках запросов (например, при загрузке страницы) пользователи будут получать ошибки. Всегда добавляйте небольшой burst. 3. Использование `$remote_addr` вместо `$binary_remote_addr` — первый хранится в виде строки и занимает больше памяти. Всегда используйте бинарный вариант. 4. Забыли про `nodelay` — если не указать, burst-запросы будут задерживаться, что может увеличить время загрузки страниц. 5. Не учтены прокси — если Nginx стоит за балансировщиком, $binary_remote_addr будет содержать IP балансировщика. Используйте real_ip модуль для корректного определения клиентского IP. 6. Игнорирование логов — без анализа логов невозможно понять, эффективны ли ограничения и не мешают ли они пользователям.

FAQ

Вопрос: Можно ли ограничить скорость по URL? Да, в качестве ключа можно использовать $request_uri или $uri. Например: limit_req_zone $request_uri zone=by_uri:10m rate=1r/s;. Но будьте осторожны: это может привести к неожиданным эффектам, если URI многообразны.

Вопрос: Что лучше: `limit_req` или `limit_conn`? Они решают разные задачи. limit_req ограничивает частоту запросов, а limit_conn — количество одновременных соединений. Для комплексной защиты используйте оба.

Вопрос: Какой код ошибки возвращать? Рекомендуется 429 (Too Many Requests) — он стандартизирован и понятен клиентам. Код 503 тоже допустим, но менее информативен.

Вопрос: Как проверить, что ограничения работают? Используйте утилиту ab (Apache Bench) или wrk для генерации нагрузки и смотрите на коды ответов. Также анализируйте логи ошибок Nginx.

Вопрос: Можно ли применять лимиты только к POST-запросам? Да, с помощью карты map можно задать ключ только для определённых методов. Например:

map $request_method $limit_key {
    POST $binary_remote_addr;
    default "";
}
limit_req_zone $limit_key zone=post_limit:10m rate=1r/s;

Итог

Настройка ограничения частоты запросов в Nginx — мощный и гибкий способ защитить сервер от перегрузок и атак. Используйте limit_req_zone для определения зон, limit_req для применения лимитов, экспериментируйте с burst и nodelay, не забывайте про мониторинг. Комбинируйте с limit_conn для комплексной защиты. Помните, что цель — не заблокировать всех, а отсечь вредоносный трафик, сохранив комфорт для реальных пользователей.

Читайте также

Комментарии

Комментарии доступны только зарегистрированным пользователям. Войти

  • Пока нет комментариев. Будьте первым.