Немного об ограничении частоты запросов к определённому адресу на сервере с Nginx и настройке исключений для такого ограничения.
Настраиваем лимиты.
Простое ограничение на частоту запросов выглядит так:
Здесь мы используя limit_req_zone обозначаем:
- Ключ $binary_remote_addr — это бинарное представление IP адреса. Оно занимает меньше места чем строковое, что бывает критично.
- Зону one — заданного размера часть памяти, в которой будет храниться информация о состоянии IP и его обращениях к серверу.
- Rate лимит — лимит на количество обращений за определённый отрезок времени.
Обозначенную зону далее мы просто применяем на нужный location. В примере, была создана зона one, которая ограничивает частоту обращений к /login.php 30 запросами в минуту с одного IP.
Белый список IP.
Исключить применение лимитов для определённых IP адресов можно с помощью директив map и geo. Пример создания такого белого списка ниже:
В данном примере, с помощью geo мы задаём список, в котором для нужных нам подсетей мы передаём 0, а для всех остальных 1. Затем, с помощью map мы задаём ключ $limit_key относительно значения $limit.
Для подсетей из белого списка $limit имеет значение 0, а значит в $limit_key будет передана пустая строка. Для остальных IP $limit имеет значение 1, а значит в $limit_key будет передано значение $binary_remote_addr.
Затем нам остаётся просто обозначить зону one, и применить её для нужного location. Если всё будет сделано верно, то IP, не входящие в белый список, будут попадать под заданные ограничения.
Несколько зон для location.
Кроме того, для IP из такого списка мы можем так же задать отдельные ограничения. При этом, для одного location просто будут использоваться две разных зоны:
В данном примере, для location актуальны две зоны. IP попавшие в зону def, имеют ограничение на 10 запросов в секунду, в то время как IP из зоны one имеют расширенный лимит в 30 запросов в секунду.
В примерах так же используется параметры burst и nodelay. Nginx позволяет указать, какое количество запросов клиент может выполнить сверх обозначенного зоной лимита. Запросы превышающие лимит, встают в очередь, размер этой очереди и задаётся параметром burst. Для того что бы сократить время обработки очереди, вместе с параметром burst можно использовать параметр nodelay.
2 thoughts on “ NGINX. Лимит частоты запросов. ”
Приветствую.
А если домен находится на Cloudflare, возможно такое сделать?
С Уважением.
Модуль ngx_http_limit_req_module
Модуль ngx_http_limit_req_module (0.7.21) позволяет ограничить скорость обработки запросов по заданному ключу или, как частный случай, скорость обработки запросов, поступающих с одного IP-адреса. Ограничение обеспечивается с помощью метода “leaky bucket”.
Пример конфигурации
Директивы
Синтаксис: | limit_req zone = название [ burst = число ] [ nodelay | delay = число ]; |
---|---|
Умолчание: | — |
Контекст: | http , server , location |
Задаёт зону разделяемой памяти ( zone ) и максимальный размер всплеска запросов ( burst ). Если скорость поступления запросов превышает описанную в зоне, то их обработка задерживается так, чтобы запросы обрабатывались с заданной скоростью. Избыточные запросы задерживаются до тех пор, пока их число не превысит максимальный размер всплеска. При превышении запрос завершается с ошибкой. По умолчанию максимальный размер всплеска равен нулю. Например, директивы
позволяют в среднем не более 1 запроса в секунду со всплесками не более 5 запросов.
Если же избыточные запросы в пределах лимита всплесков задерживать не требуется, то следует использовать параметр nodelay :
Параметр delay (1.15.7) задаёт лимит, по достижении которого избыточные запросы задерживаются. Значение по умолчанию равно нулю и означает, что задерживаются все избыточные запросы.
Директив limit_req может быть несколько. Например, следующая конфигурация ограничивает скорость обработки запросов, поступающих с одного IP-адреса, и в то же время ограничивает скорость обработки запросов одним виртуальным сервером:
Директивы наследуются с предыдущего уровня при условии, что на данном уровне не описаны свои директивы limit_req .
Синтаксис: | limit_req_dry_run on | off ; |
---|---|
Умолчание: | |
Контекст: | http , server , location |
Эта директива появилась в версии 1.17.1.
Включает режим пробного запуска. В данном режиме скорость обработки запросов не ограничивается, однако в зоне разделяемой памяти текущее число избыточных запросов учитывается как обычно.
Синтаксис: | limit_req_log_level info | notice | warn | error ; |
---|---|
Умолчание: | |
Контекст: | http , server , location |
Эта директива появилась в версии 0.8.18.
Задаёт желаемый уровень записи в лог случаев отказа в обработке запросов при превышении скорости и случаев задержек при обработке запроса. Задержки записываются в лог с уровнем на единицу меньшим, чем отказы, например, если указано “ limit_req_log_level notice ”, то задержки будут записываться в лог на уровне info .
Синтаксис: | limit_req_status код ; |
---|---|
Умолчание: | |
Контекст: | http , server , location |
Эта директива появилась в версии 1.3.15.
Позволяет переопределить код ответа, используемый при отклонении запросов.
Синтаксис: | limit_req_zone ключ zone = название : размер rate = скорость [ sync ]; |
---|---|
Умолчание: | — |
Контекст: | http |
Задаёт параметры зоны разделяемой памяти, которая хранит состояние для разных значений ключа. Состояние в частности хранит текущее число избыточных запросов. В качестве ключа можно использовать текст, переменные и их комбинации. Запросы с пустым значением ключа не учитываются.
До версии 1.7.6 в качестве ключа можно было задать ровно одну переменную.
В данном случае состояния хранятся в зоне “one” размером 10 мегабайт, и средняя скорость обработки запросов для этой зоны не может превышать 1 запроса в секунду.
В качестве ключа используется IP-адрес клиента. Обратите внимание, что вместо переменной $remote_addr используется переменная $binary_remote_addr . Длина значения переменной $binary_remote_addr всегда равна 4 байтам для IPv4-адресов или 16 байтам для IPv6-адресов. При этом размер состояния всегда равен 64 байтам на 32-битных платформах и 128 байтам на 64-битных платформах. В зоне размером 1 мегабайт может разместиться около 16 тысяч состояний размером 64 байта или около 8 тысяч состояний размером 128 байт.
При переполнении зоны удаляется наименее востребованное состояние. Если и это не позволяет создать новое состояние, запрос завершается с ошибкой.
Скорость задаётся в запросах в секунду (r/s). Если же нужна скорость меньше одного запроса в секунду, то она задаётся в запросах в минуту (r/m), например, ползапроса в секунду — это 30r/m.
Параметр sync (1.15.3) разрешает синхронизацию данной зоны разделяемой памяти.
Встроенные переменные
$limit_req_status хранит результат ограничения скорости поступления запросов (1.17.6): PASSED , DELAYED , REJECTED , DELAYED_DRY_RUN или REJECTED_DRY_RUN
Поразбирался с правилами nginx и написал для себя универсальную «закрывашку» системных директорий для всех ip кроме нужных.
Сюда попадут любые запросы в директории manager, core и connectors. Все адреса, кроме разрешенных получат отлуп, а разрешенные обработаются. Так как nginx начинает применять правила после первого точного совпадения — отдельно указываем как обрабатывать *.php файлы.
А теперь — установка лимита запросов документов сайта. Примитивная защита от DDOS.
Создаём новую зону для работы, в nginx.conf (секция http):
Ограничение на запросы — 1 в секунду.
Применяем это ограничение к выполнению *.php файлов сайта:
Burst — это разрешенный кратковременный всплеск запросов. Подробнее в документации.
С этим правилом админка MODX работать не будет, ибо там идёт куча одновременных запросов, на которые nginx будет отвечать error 503.
Но нам это не важно, ибо у нас раньше прописан отдельный блок для работы с системными директориями, и там php выполняется без ограничений.
Можете зажать у меня на сайте кнопку F5 на секунду и отпустить — будет error 503. А если нажимать F5 медленно — ошибки не будет. Спасает от настырных роботов и и простеньких атак.