Как ограничить скорость в nginx, но включить / исключить определенные IP-адреса?

27

Я могу использовать limit_reqдля ограничения скорости все запросы к моему серверу.

Однако я хотел бы снять ограничение скорости для определенных IP-адресов (например, белый список) и использовать другое ограничение скорости для некоторых других (то есть определенных IP-адресов, которые я бы хотел, всего 1r / s).

Я попытался использовать условные выражения (например if ( $remote_addr = "1.2.3.4" ) {}), но, похоже, это работает только с правилами перезаписи, а не с правилами ограничения скорости.

Джейсон Коэн
источник

Ответы:

33

Действительно лучше избегать использования директивы if. Когда ключ в limit_req_zone (и limit_conn_zone) пуст, ограничения не применяются. Вы можете использовать это вместе с картами и геомодулями, чтобы создать белый список IP-адресов, где ограничения газа не применяются.

В этом примере показано, как настроить ограничение для одновременных запросов и частоты запросов с одного IP-адреса.

http {
    geo $whitelist {
       default 0;
       # CIDR in the list below are not limited
       1.2.3.0/24 1;
       9.10.11.12/32 1;
       127.0.0.1/32 1;
    }

    map $whitelist $limit {
        0     $binary_remote_addr;
        1     "";
    }

    # The directives below limit concurrent connections from a 
    # non-whitelisted IP address to five

    limit_conn_zone      $limit    zone=connlimit:10m;

    limit_conn           connlimit 5;
    limit_conn_log_level warn;   # logging level when threshold exceeded
    limit_conn_status    503;    # the error code to return

    # The code below limits the number requests from a non-whitelisted IP
    # to one every two seconds with up to 3 requests per IP delayed 
    # until the average time between responses reaches the threshold. 
    # Further requests over and above this limit will result 
    # in an immediate 503 error.

    limit_req_zone       $limit   zone=one:10m  rate=30r/m;

    limit_req            zone=one burst=3;
    limit_req_log_level  warn;
    limit_req_status     503;

Директивы зоны должны быть размещены на уровне http, однако другие директивы могут быть размещены еще ниже, например, на сервере или на уровне местоположения, чтобы ограничить их область действия или дополнительно адаптировать ограничения.

Для получения дополнительной информации обратитесь к документации Nginx ngx_http_limit_req_module и ngx_http_limit_conn_module

пользователь shonky linux
источник
В чем разница между этими двумя модулями?
Mente
1
Согласно комментариям, первый ограничивает количество одновременных подключений, а второй ограничивает скорость подключений
пользователь shonky linux
Можете ли вы объяснить, почему вы делаете сопоставление в два этапа, с geoпоследующим map, а не просто используете geoдля $limitпрямой установки ?
Маркус Даунинг
2
Кажется, он geoне может быть сопоставлен с переменной, поэтому, если вы укажете $binary_remote_addrв качестве значения отображения, это будет переводить в буквенную строку "$binary_remote_addr", а не в значение переменной.
ColinM
1
Я хотел бы добавить, что если рассматриваемый IP-адрес уже находится в зоне, необходимо перезапустить nginx; перезагрузка не достаточно.
Halfgaar
5

Вы можете безопасно использовать именованные местоположения, такие как "@location" в блоке if ().

Смотрите: http://wiki.nginx.org/IfIsEvil

Примерно так должно работать:

http {

   limit_req_zone $binary_remote_addr zone=delay:10m rate=1r/m;

   server {
      ...

      error_page 410 = @slowdown;

      if( $remote_addr != "1.2.3.4" ) {
         return 410;
      }

      location @slowdown {
         limit_req zone=delay burst 5;
         ...
      }

      location / {
         ...
      }
   }

Заполните "location @slowdown {}" той же информацией, что и "location / {}, например proxy_pass, если вы используете nginx в качестве обратного прокси-сервера.

Роберт Су
источник
Я не уверен, что понимаю 410 часть? Клиент действительно видит код состояния http 410?
Свр
1
Вау, это на самом деле работает! Очень изящный error_pageтрюк, +1! @svrist, см. serverfault.com/a/870170/110020 для полного объяснения того, как что-то подобное будет работать и почему.
CNST