Назад | Перейти на главную страницу

nginx Block IP на основе URI в одном месте

На данный момент есть блок из одной локации /

  location / {
    root  /var/www/docs;
    proxy_pass  http://backend;
    proxy_buffering     on;
    proxy_buffer_size   64k;
    proxy_buffers       256   64k;
  }

который нужно фильтровать по IP.

В идеале, чтобы уменьшить количество повторений одних и тех же директив в location, Я хочу провести тест в location блокировать

  location / {

    if ($uri ~ '^/(abc|def|ghi)') {
        allow 10.0.0.0/8;
        allow 1.2.3.4;
        deny all;
    }

    root  /var/www/docs;
    proxy_pass  http://backend;
    proxy_buffering     on;
    proxy_buffer_size   64k;
    proxy_buffers       256   64k;
  }

К сожалению, кажется allow/deny директивы не могут использоваться в if блок.

"allow" directive is not allowed here in /etc/nginx/sites-enabled/mysite:20

Есть ли элегантный способ выполнить тест, не повторяя location блоки?

(лайк

  location ~ /(abc|def|ghi) {

        allow 10.0.0.0/8;
        allow 1.2.3.4;
        deny all;

        ... 5 other lines root,proxy...
   }

  location  / {

        ... 5 other lines root,proxy...
   }

)

Как сказал coredump, нет, используйте несколько мест.

Но можно сделать содержимое location блоки менее повторяющиеся. Ключ здесь - именованный location блок, содержащий root и proxy_... директивы.

Например:

location / {
  try_files $uri @proxy;
}
location ~ /(abc|def|ghi) {
  allow 10.0.0.0/8;
  allow 1.2.3.4;
  deny all;

  try_files $uri @proxy;
}
location @proxy {
  root  /var/www/docs;
  proxy_pass  http://backend;
  proxy_buffering     on;
  proxy_buffer_size   64k;
  proxy_buffers       256   64k;
}

И, наверное, еще лучше было бы разместить root директива вне всех location блоки.

Сначала вам нужно определить переменную, которая будет содержать ваши IP-фильтры. Это входит в http раздел конфигурации nginx:

map $remote_addr (or $http_x_forwarded_for if behind a proxy) $allowed {
        default deny;
        ~\s*111.222.333.444$ allow;
        ~\s*333.444.555.*$   allow;
    }

затем в сервер вы пишете конструкцию if и фильтруете место доступа по содержимому переменной $ разрешено:

location / {
        if ( $allowed = "deny" ) { return 403; }
        #...
    }

Обычно в таких случаях могут помочь «вложенные локации» ...

location / {
   root /var/www/docs;
   allow all;

   location /admin {
       deny 1.2.3.4;
   }

}

... но не все директивы унаследованы во вложенных местах. К сожалению, но точно proxy_pass, fastcgi_pass и подобные не наследуются ... Таким образом, предложенное ранее решение (с @ namedlocation) является правильным в этом случае. Вы также можете использовать директиву include для "блока proxy_pass", конечно.

Нет. Используйте несколько locations, это может выглядеть некрасиво, но у вас будет меньше шансов если безумие.

Также помните, что nginx сначала обрабатывает совпадения регулярного выражения, и если ни одно из них не соответствует, он пробует наиболее конкретное буквальное местоположение, являющееся location / своего рода поймать все расположение. Зная, что вы можете уменьшить количество необходимых вам мест. Взгляни на этот документ чтобы увидеть, как обрабатываются запросы.