Як встановити ліміт швидкості в nginx, але включаючи / виключаючи певні IP-адреси?


27

Я можу використовувати limit_reqдля обмеження швидкості всіх запитів на своєму сервері.

Однак я хотів би зняти обмеження швидкості для певних IP-адрес (тобто білий список) і використовувати інше обмеження швидкості для певних інших (тобто для певних IP-адрес, які я хотів би досягти 1р / с).

Я спробував використовувати умовні умови (наприклад if ( $remote_addr = "1.2.3.4" ) {}), але це, здається, працює лише з правилами перезапису, а не з обмеженням норм ставок.

Відповіді:


33

Дійсно краще уникати використання директиви "якщо". Коли ключ у 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


Яка різниця між цими двома модулями?
менте

1
Згідно з коментарями, перший обмежує паралельні з'єднання, другий обмежує швидкість з'єднань
приголомшливий користувач 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, дивіться сервер defaultfault.com/a/870170/110020 для повного пояснення того, як щось подібне буде працювати, і чому.
cnst
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.