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これらのディレクティブは、現在のレベルにディレクティブがない場合にのみ、前のレベルから継承されます。

limit_connしかし、私のテストでは奇妙なことが起こり、nginx がブロック内のディレクティブを無視しているようですlocation ~ \.php$

  1. この設定を 5 つの同時接続でテストすると、ブロックは発生しません。 制限を 11 にab -n 100 -c 5 http://test.dev/上げるとすぐに、nginx はリクエストをブロックし始めます。
    -c 11
  2. グローバル接続制限を 10 から 5 に変更すると、nginx は 6 を超える接続を制限します ( ) -ブロック-c 6内のディレクティブは無視されるようです 。location ~ \.php$
  3. サーバー レベルでディレクティブを削除するとconn_limit、ブロック内のディレクティブがlocation ~ \.php$突然機能し始めます。
  4. さらに混乱を招くのは、conn_limitディレクティブをブロックに追加するとlocation /、グローバル ディレクティブが正しく上書きされることです。

おそらく、問題はディレクティブまたは複数のリダイレクトにありますか?ディレクティブが期待どおりに上書きされないtry_files理由を誰かが説明してくれると非常にありがたいです。conn_limit

答え1

@AlexeyTen のおかげで、質問に答えられると思います。

重要なのは次の2点です。

  • ディレクティブはlimit_connリクエストごとに 1 回だけ処理されます。
  • 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 では、nginx はlimit_connlocation でディレクティブを見つけてlocation /処理しますが、ここでも location location @rewritenolimit_connは見つからないため、 at のディレクティブlocation /が処理されます。ここでも、ブロックは無視されますlocation ~ \.php$

関連情報