Nginx limit_conn 继承

Nginx limit_conn 继承

我正在尝试使用 limit_conn 和 limit_req 保护在 Nginx 上运行的 Drupal 免受简单 DDoS 攻击。但我遇到了一些与limit_conn指令继承有关的奇怪行为,我无法解释。

我已将 nginx(1.8.0)配置降低到最低限度,这显示了问题:

limit_conn_zone $binary_remote_addr zone=perip:10m;

server {
    server_name test.dev;
    root /var/nginx/drupal; ## <-- Your only path reference.

    #Allow not more than 10 simultaneous connections from one address.
    limit_conn perip  10;

    location / {
        #limit_conn perip 1;
        # This is cool because no php is touched for static content
        try_files $uri @rewrite;
    }

    location @rewrite {
        # Clean URLs are handled in drupal_environment_initialize().
        rewrite ^ /index.php;
    }

    location ~ \.php$ {
        #Allow not more than 1 simultaneous *connection_to_PHP* from one address.
        limit_conn perip 1; 

        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        include fastcgi.conf;
        fastcgi_intercept_errors on;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
    }
}

如您所见,我想将所有请求的同时连接数限制为 10 个,将 php 后端的同时连接数限制为 4 个。(在这个例子中我把 4 个连接修改为 1 个,这样会更容易触发)

Nginx 文档位于http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html#limit_conn指出:

limit_conn当且仅当当前级别没有指令时,这些指令才会从上一级别继承。

但是在我的测试中发生了一些奇怪的事情,看起来 nginx 忽略了块limit_conn内的指令location ~ \.php$

  1. 当我使用 5 个同时连接测试此配置时ab -n 100 -c 5 http://test.dev/,没有发生阻塞。一旦我将
    限制提高到 11,-c 11nginx 就会开始阻止请求。
  2. 如果我将全局连接限制从 10 修改为 5,则 nginx 将限制超过 6 个连接(-c 6) - 看起来 location ~ \.php$块中的指令被忽略了。
  3. 如果我删除conn_limit服务器级别的指令,块中的指令location ~ \.php$就会突然开始工作!
  4. 更令人困惑的是:如果我将conn_limit指令添加到location /阻止中,它会正确地覆盖全局指令!

也许问题出在指令或多个重定向上?如果有人能解释为什么指令没有像预期的那样被覆盖,try_files我将非常感激。conn_limit

答案1

感谢@AlexeyTen,我希望能够回答这个问题。

重要的是两点:

  • limit_conn每个请求仅处理一次该指令!
  • limit_conn当且仅当当前级别没有指令时,这些指令才会从上一级别继承。

TL;DR:如果有limit_conn指令,nginx 会在执行链中查看子块,如果没有limit_conn,则处理父块。此后,所有其他limit_conn指令都将被忽略。

我尝试用我的例子来解释它:

在我发布的例子中,当“http://test.dev/“请求到达时,起初 nginx 不在级别limit_conn上处理server,而是等待查看匹配的位置location /。但是在这个级别上没有limit_conn指令,所以 nginx 处理该级别的指令server。之后,所有limit_conn指令都将被忽略,因为它已经被处理了。这解释了我的测试 1-3。

在测试 4 中,nginxlimit_conn在 location 中找到了一条指令location /并对其进行了处理,但同样,在 location 上location @rewrite没有limit_conn找到,因此处理了 处的指令location /。同样,我们忽略了该location ~ \.php$块。

相关内容