序章

Nginxは、利用可能な最も柔軟で強力なWebサーバーソリューションの1つになりました。 ただし、設計の観点からは、何よりもまずプロキシサーバーです。 この焦点は、他のサーバーでリクエストを処理するときにNginxが非常にパフォーマンスが高いことを意味します。

Nginxは、http、FastCGI、uwsgi、SCGI、またはmemcachedを使用してリクエストをプロキシできます。 このガイドでは、最も一般的なプロキシプロトコルの1つであるFastCGIプロキシについて説明します。

FastCGIプロキシを使用する理由

Nginx内のFastCGIプロキシは、通常、クライアント要求を直接処理しない、または処理すべきでないアプリケーションサーバーに対するクライアント要求を変換するために使用されます。 FastCGIは、以前のCGI、つまりCommon Gateway Interfaceに基づくプロトコルであり、各要求を個別のプロセスとして実行しないことでパフォーマンスを向上させることを目的としています。 これは、動的コンテンツの要求を処理するサーバーと効率的にインターフェースするために使用されます。

Nginx内でのFastCGIプロキシの主なユースケースの1つは、PHP処理です。 Apacheを使用してPHP処理を直接処理できるApacheとは異なります。 mod_php モジュールの場合、NginxはPHPリクエストを処理するために別のPHPプロセッサに依存する必要があります。 ほとんどの場合、この処理はで処理されます php-fpm、Nginxで動作するように広範囲にテストされたPHPプロセッサ。

FastCGIを使用するNginxは、FastCGI要求に応答するように構成されたアクセス可能なコンポーネントがある限り、他の言語を使用するアプリケーションで使用できます。

FastCGIプロキシの基本

一般に、リクエストのプロキシには、プロキシサーバー(この場合はNginx)が関与し、クライアントからバックエンドサーバーにリクエストを転送します。 NginxがFastCGIプロトコルを使用してプロキシする実際のサーバーを定義するために使用するディレクティブは次のとおりです。 fastcgi_pass.

たとえば、PHPに対する一致するリクエストを、FastCGIプロトコルを使用したPHP処理の処理専用のバックエンドに転送するには、基本的なロケーションブロックは次のようになります。

# server context

location ~ \.php$ {
    fastcgi_pass 127.0.0.1:9000;
}

. . .

上記のスニペットは、情報が少なすぎるため、実際にはそのままでは機能しません。 プロキシ接続が確立されるたびに、プロキシされたリクエストがバックエンドサーバーにとって意味のあるものになるように、元のリクエストを変換する必要があります。 FastCGIパスを使用してプロトコルを変更しているため、これには追加の作業が必要です。

http-to-httpプロキシでは、主にhttpヘッダーを拡張して、バックエンドがクライアントに代わってプロキシサーバーに応答するために必要な情報を確実に取得できるようにしますが、FastCGIは、httpヘッダーを読み取ることができない別個のプロトコルです。 この考慮事項により、関連情報は他の方法でバックエンドに渡す必要があります。

FastCGIプロトコルを使用するときに追加情報を渡す主な方法は、パラメーターを使用することです。 バックグラウンドサーバーは、これらを読み取って処理するように構成し、検出した内容に応じて動作を変更する必要があります。 Nginxは、 fastcgi_param 指令。

PHPのFastCGIプロキシシナリオで実際に機能する最低限の構成は、次のようなものです。

# server context

location ~ \.php$ {
    fastcgi_param REQUEST_METHOD $request_method;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass 127.0.0.1:9000;
}

. . .

上記の構成では、2つのFastCGIパラメーターを設定します。 REQUEST_METHODSCRIPT_FILENAME. これらは両方とも、バックエンドサーバーがリクエストの性質を理解するために必要です。 前者は実行する必要のある操作のタイプを指示し、後者は実行するファイルをアップストリームに指示します。

この例では、いくつかのNginx変数を使用して、これらのパラメーターの値を設定しました。 The $request_method 変数には、クライアントから要求されたhttpメソッドが常に含まれます。

The SCRIPT_FILENAME パラメータは、 $document_root 変数と $fastcgi_script_name 変数。 The $document_root によって設定されたベースディレクトリへのパスが含まれます root 指令。 The $fastcgi_script_name 変数はリクエストURIに設定されます。 リクエストURIがスラッシュ(/)で終わる場合、 fastcgi_index ディレクティブは最後に追加されます。 Nginxインスタンスと同じマシンでFastCGIプロセッサを実行しているため、このタイプの自己参照ロケーション定義が可能です。

別の例を見てみましょう:

# server context
root /var/www/html;

location /scripts {
    fastcgi_param REQUEST_METHOD $request_method;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_index index.php;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
}

. . .

上記の場所がリクエストを処理するために選択された場合 /scripts/test/、の値 SCRIPT_FILENAME の値の組み合わせになります root ディレクティブ、リクエストURI、および fastcgi_index 指令。 この例では、パラメータは次のように設定されます。 /var/www/html/scripts/test/index.php.

ネットワークソケットの代わりにUnixソケットを使用してFastCGIバックエンドを指定したという点で、上記の構成にもう1つの重要な変更を加えました。 Nginxは、どちらのタイプのインターフェースを使用してFastCGIアップストリームに接続できます。 FastCGIプロセッサが同じホスト上にある場合は、通常、セキュリティのためにUnixソケットをお勧めします。

FastCGI構成の分割

保守可能なコードの重要なルールは、DRY(「Do n’tRepeatYourself」)の原則に従おうとすることです。 これにより、エラーが減少し、再利用性が向上し、整理が容易になります。 Nginxを管理するための主要な推奨事項の1つは、常に最も広い適用範囲でディレクティブを設定することであることを考慮すると、これらの基本的な目標はNginx構成にも適用されます。

FastCGIプロキシ構成を処理する場合、ほとんどの使用インスタンスは構成の大部分を共有します。 このため、およびNginx継承モデルが機能する方法のために、ほとんどの場合、一般的なスコープでパラメーターを宣言することが有利です。

親コンテキストでのFastCGI構成の詳細の宣言

繰り返しを減らす1つの方法は、より高い親コンテキストで構成の詳細を宣言することです。 実際のパラメータ以外のすべてのパラメータ fastcgi_pass より高いレベルで指定できます。 それらは、パスが発生する場所に下向きにカスケードされます。 これは、複数の場所で同じ構成を使用できることを意味します。

たとえば、上記のセクションの最後の構成スニペットを変更して、複数の場所で役立つようにすることができます。

# server context
root /var/www/html;

fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;

location /scripts {
    fastcgi_pass unix:/var/run/php5-fpm.sock;
}

location ~ \.php$ {
    fastcgi_pass 127.0.0.1:9000;
}

. . .

上記の例では、 fastcgi_param 宣言と fastcgi_index ディレクティブは、後に続く両方のロケーションブロックで使用できます。 これは、繰り返しの宣言を削除する1つの方法です。

ただし、上記の構成には1つの重大な欠点があります。 もしあれば fastcgi_param 下位コンテキストで宣言されているnone fastcgi_param 親コンテキストからの値が継承されます。 継承された値をのみ使用するか、いずれも使用しません。

The fastcgi_param ディレクティブは、Nginx用語ではarrayディレクティブです。 ユーザーの観点からは、配列ディレクティブは基本的に、単一のコンテキストで複数回使用できるディレクティブです。 後続の各宣言は、Nginxが前の宣言から知っていることに新しい情報を追加します。 The fastcgi_param ディレクティブは、ユーザーが複数のパラメーターを設定できるようにするために、配列ディレクティブとして設計されました。

配列ディレクティブは、他のディレクティブとは異なる方法で子コンテキストを継承します。 配列ディレクティブからの情報は、子コンテキストのどの場所にも存在しない場合にのみ、子コンテキストに継承されます。 これは、 fastcgi_param あなたの場所の中で、それは親コンテキストから完全に継承された値を効果的にクリアします。

たとえば、上記の構成を少し変更できます。

# server context
root /var/www/html;

fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;

location /scripts {
    fastcgi_pass unix:/var/run/php5-fpm.sock;
}

location ~ \.php$ {
    fastcgi_param QUERY_STRING $query_string;
    fastcgi_pass 127.0.0.1:9000;
}

. . .

一見すると、 REQUEST_METHODSCRIPT_FILENAME パラメータは2番目のロケーションブロックに継承され、 QUERY_STRING その特定のコンテキストで追加で使用可能なパラメーター。

実際に起こることは、親のallです fastcgi_param 値は2番目のコンテキストで消去され、 QUERY_STRING パラメータが設定されています。 The REQUEST_METHODSCRIPT_FILENAME パラメータは未設定のままになります。

同じコンテキスト内のパラメーターの複数の値に関する注意

この時点で間違いなく言及する価値のあることの1つは、単一のコンテキスト内で同じパラメーターに複数の値を設定することの意味です。 次の例を議論のポイントとして取り上げましょう。

# server context

location ~ \.php$ {
    fastcgi_param REQUEST_METHOD $request_method;
    fastcgi_param SCRIPT_FILENAME $request_uri;

    fastcgi_param DOCUMENT_ROOT initial;
    fastcgi_param DOCUMENT_ROOT override;

    fastcgi_param TEST one;
    fastcgi_param TEST two;
    fastcgi_param TEST three;

    fastcgi_pass 127.0.0.1:9000;
}

. . .

上記の例では、 TESTDOCUMENT_ROOT 単一のコンテキスト内で複数回パラメータ。 以来 fastcgi_param は配列ディレクティブであり、後続の各宣言はNginxの内部レコードに追加されます。 The TEST パラメータには、配列内に宣言があり、次のように設定されます。 one, two、 と three.

この時点で理解することが重要なのは、これらすべてがNginxからの追加処理なしでFastCGIバックエンドに渡されるということです。 これは、これらの値の処理方法を決定するのは、選択したFastCGIプロセッサ次第であることを意味します。 残念ながら、異なるFastCGIプロセッサは、渡された値を完全に異なる方法で処理します

たとえば、上記のパラメーターがPHP-FPMによって受信された場合、final値は以前の値のいずれかをオーバーライドするように解釈されます。 したがって、この場合、 TEST パラメータはに設定されます three. 同様に、 DOCUMENT_ROOT パラメータはに設定されます override.

ただし、上記の値がFsgiWrapなどに渡された場合、値の解釈は大きく異なります。 まず、スクリプトの実行に使用する値を決定するための初期パスを作成します。 それは使用します DOCUMENT_ROOT の値 initial スクリプトを探します。 ただし、実際のパラメーターをスクリプトに渡すときは、PHP-FPMと同様に、最終的な値を渡します。

この不整合と予測不可能性は、同じパラメーターを複数回設定するときに、バックエンドに依存して意図を正しく解釈することはできず、またそうすべきではないことを意味します。 唯一の安全な解決策は、各パラメーターを1回だけ宣言することです。 これは、デフォルト値を安全にオーバーライドするようなことはないことも意味します。 fastcgi_param 指令。

インクルードを使用して別のファイルからFastCGI構成をソースする

一般的な構成アイテムを分離する別の方法があります。 使用できます include 別のファイルの内容をディレクティブ宣言の場所に読み込むためのディレクティブ。

これは、すべての一般的な構成アイテムを1つのファイルに保持し、必要な構成の任意の場所に含めることができることを意味します。 Nginxは実際のファイルの内容をどこに配置するので include と呼ばれる場合、親コンテキストから子に下向きに継承することはありません。 これにより、 fastcgi_param 値が消去されないため、必要に応じて追加のパラメータを設定できます。

まず、共通のFastCGI構成値を構成ディレクトリ内の別のファイルに設定できます。 このファイルを呼び出します fastcgi_common:

fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

これで、これらの構成値を使用する場所ならどこでも、このファイルを読み取ることができます。

# server context
root /var/www/html;

location /scripts {
    include fastcgi_common;

    fastcgi_index index.php;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
}

location ~ \.php$ {
    include fastcgi_common;
    fastcgi_param QUERY_STRING $query_string;
    fastcgi_param CONTENT_TYPE $content_type;
    fastcgi_param CONTENT_LENGTH $content_length;

    fastcgi_index index.php;
    fastcgi_pass 127.0.0.1:9000;
}

. . .

ここでは、いくつかの一般的なものを移動しました fastcgi_param と呼ばれるファイルへの値 fastcgi_common デフォルトのNginx構成ディレクトリにあります。 次に、宣言された値を挿入するときに、そのファイルをソースします。

この構成について注意すべき点がいくつかあります。

まず、ソースを作成する予定のファイルに、場所ごとにカスタマイズしたい値を配置しなかったということです。 同じパラメータに複数の値を設定するときに発生する前述の解釈の問題と、非配列ディレクティブはコンテキストごとに1回しか設定できないため、変更したくない共通ファイルのみを配置します。 コンテキストごとにカスタマイズしたいすべてのディレクティブ(またはパラメーターキー)は、共通ファイルから除外する必要があります。

お気づきかもしれませんが、2番目のロケーションブロックにいくつかの追加のFastCGIパラメーターを設定しています。 これが私たちが達成したいと思っていた能力です。 追加で設定できました fastcgi_param 必要に応じて、共通の値を消去せずにパラメータを設定します。

fastcgi_paramsファイルまたはfastcgi.confファイルの使用

上記の戦略を念頭に置いて、Nginx開発者と多くの配布パッケージングチームは、FastCGIパスの場所に含めることができる共通のパラメーターの適切なセットを提供することに取り組んできました。 これらは呼ばれます fastcgi_params また fastcgi.conf.

これらの2つのファイルはほぼ同じですが、実際には、単一のパラメーターに複数の値を渡すことについて前に説明した問題の結果が唯一の違いです。 The fastcgi_params ファイルにの宣言が含まれていません SCRIPT_FILENAME パラメータ、 fastcgi.conf ファイルはありません。

The fastcgi_params ファイルはずっと長い間利用可能でした。 に依存していた構成を壊さないようにするため fastcgi_params、デフォルト値を提供することが決定されたとき SCRIPT_FILENAME、新しいファイルを作成する必要がありました。 そうしないと、そのパラメーターが共通ファイルとFastCGIパスの場所の両方に設定される可能性があります。 これについては、MartinFjordvaldによるこれら2つのファイルの履歴に関する優れた投稿で詳しく説明されています。

人気のあるディストリビューションの多くのパッケージメンテナは、これらのファイルの1つだけを含めるか、コンテンツを正確にミラーリングすることを選択しました。 これらのうち1つしか使用できない場合は、使用しているものを使用してください。 ニーズに合わせて自由に変更してください。

これらのファイルの両方を利用できる場合は、ほとんどのFastCGIパスの場所で、 fastcgi.conf ファイル、それはのための宣言を含んでいるので SCRIPT_FILENAME パラメータ。 これは通常望ましいことですが、この値をカスタマイズしたい場合もあります。

これらは、ルートNginx構成ディレクトリを基準にした場所を参照することで含めることができます。 ルートNginx構成ディレクトリは通常次のようなものです /etc/nginx Nginxがパッケージマネージャーとともにインストールされている場合。

次のようなファイルを含めることができます。

# server context

location ~ \.php$ {
    include fastcgi_params;
    # You would use "fastcgi_param SCRIPT_FILENAME . . ." here afterwards
    
    . . .

}

またはこのように:

# server context

location ~ \.php$ {
    include fastcgi.conf;

    . . .

}

重要なFastCGIディレクティブ、パラメーター、および変数

上記のセクションでは、他の概念を示す手段として、かなりの数のパラメーターを、多くの場合Nginx変数に設定しました。 また、あまり説明せずにいくつかのFastCGIディレクティブを導入しました。 このセクションでは、設定する一般的なディレクティブのいくつか、変更する必要のあるパラメーター、および必要な情報を含む可能性のあるいくつかの変数について説明します。

一般的なFastCGIディレクティブ

以下は、FastCGIパスを操作するための最も有用なディレクティブのいくつかを表しています。

  • fastcgi_pass :現在のコンテキストでリクエストをバックエンドに渡す実際のディレクティブ。 これは、FastCGIプロセッサに到達できる場所を定義します。
  • fastcgi_param :パラメーターを値に設定するために使用できる配列ディレクティブ。 ほとんどの場合、これはNginx変数と組み合わせて使用され、FastCGIパラメーターをリクエストに固有の値に設定します。
  • try_files :FastCGI固有のディレクティブではありませんが、FastCGIパスの場所で使用される一般的なディレクティブです。 これは、要求されたファイルがFastCGIプロセッサに渡される前に存在することを確認するために、要求サニテーションルーチンの一部としてよく使用されます。
  • include :繰り返しますが、FastCGI固有のディレクティブではありませんが、FastCGIパスコンテキストで頻繁に使用されるディレクティブです。 ほとんどの場合、これは、複数の場所に共通の共有構成の詳細を含めるために使用されます。
  • fastcgi_split_path_info :このディレクティブは、2つのキャプチャされたグループを持つ正規表現を定義します。 最初にキャプチャされたグループは、の値として使用されます $fastcgi_script_name 変数。 2番目にキャプチャされたグループは、 $fastcgi_path_info 変数。 これらは両方とも、要求を正しく解析するためによく使用されます。これにより、プロセッサは、要求のどの部分が実行するファイルであり、どの部分がスクリプトに渡す追加情報であるかを知ることができます。
  • fastcgi_index :これはに追加されるべきインデックスファイルを定義します $fastcgi_script_name スラッシュで終わる値(/). これは、 SCRIPT_FILENAME パラメータがに設定されている $document_root$fastcgi_script_name また、ロケーションブロックは、ファイルの後に情報を含む要求を受け入れるように構成されています。
  • fastcgi_intercept_errors :このディレクティブは、FastCGIサーバーから受信したエラーをNginxで処理するか、クライアントに直接渡すかを定義します。

上記のディレクティブは、一般的なFastCGIパスを設計するときに使用するもののほとんどを表しています。 これらすべてを常に使用するわけではありませんが、次に説明するFastCGIパラメーターおよび変数と非常に密接に相互作用することがわかります。

FastCGIで使用される一般的な変数

FastCGIパスで使用する可能性のあるパラメーターについて説明する前に、これらのパラメーターの設定で利用する一般的なNginx変数について少し説明する必要があります。 これらのいくつかはNginxのFastCGIモジュールによって定義されていますが、ほとんどはCoreモジュールからのものです。

  • $query_stringまたは$args:元のクライアント要求で指定された引数。
  • $ is_args :「?」に等しくなりますリクエストに引数があり、それ以外の場合は空の文字列に設定されます。 これは、引数を持つ場合と持たない場合があるパラメーターを作成するときに役立ちます。
  • $ request_method :これは元のクライアント要求メソッドを示します。 これは、現在のコンテキスト内で操作を許可する必要があるかどうかを判断するのに役立ちます。
  • $ content_type :これはに設定されます Content-Type リクエストヘッダー。 この情報は、後続のコンテンツを正しく処理するためにユーザーの要求がPOSTである場合に、プロキシによって必要になります。
  • $ content_length :これはの値に設定されます Content-Length クライアントからのヘッダー。 この情報は、クライアントのPOST要求に必要です。
  • $ fastcgi_script_name :これには実行するスクリプトファイルが含まれます。 リクエストがスラッシュ(/)で終わる場合、 fastcgi_index ディレクティブは最後に追加されます。 その場合 fastcgi_split_path_info ディレクティブが使用される場合、この変数は、そのディレクティブによって定義された最初にキャプチャされたグループに設定されます。 この変数の値は、実行される実際のスクリプトを示している必要があります。
  • $ request_filename :この変数には、要求されたファイルのファイルパスが含まれます。 現在のドキュメントルートの値を取得し、両方を考慮してこの値を取得します。 rootalias ディレクティブ、およびの値 $fastcgi_script_name. これは、を割り当てる非常に柔軟な方法です。 SCRIPT_FILENAME パラメータ。
  • $ request_uri :クライアントから受信したリクエスト全体。 これには、スクリプト、追加のパス情報、およびクエリ文字列が含まれます。
  • $ fastcgi_path_info :この変数には、リクエストのスクリプト名の後に使用できる追加のパス情報が含まれています。 この値には、実行するスクリプトが知っておくべき別の場所が含まれている場合があります。 この変数は、を使用するときに2番目にキャプチャされた正規表現グループから値を取得します。 fastcgi_split_path_info 指令。
  • $ document_root :この変数には、現在のドキュメントルート値が含まれます。 これは、に従って設定されます root また alias ディレクティブ。
  • $ uri :この変数には、正規化が適用された現在のURIが含まれています。 書き換えまたは内部リダイレクトする特定のディレクティブはURIに影響を与える可能性があるため、この変数はそれらの変更を表現します。

ご覧のとおり、FastCGIパラメーターの設定方法を決定する際に使用できる変数はかなりあります。 これらの多くは似ていますが、スクリプトの実行に影響を与える微妙な違いがいくつかあります。

一般的なFastCGIパラメータ

FastCGIパラメータは、リクエストの送信先であるFastCGIプロセッサで利用できるようにしたいキー値情報を表します。 すべてのアプリケーションが同じパラメータを必要とするわけではないため、多くの場合、アプリのドキュメントを参照する必要があります。

これらのパラメーターのいくつかは、プロセッサーが実行するスクリプトを正しく識別するために必要です。 その他はスクリプトで使用できるようになり、設定されたパラメーターに依存するように構成されている場合は、スクリプトの動作が変更される可能性があります。

  • QUERY_STRING :このパラメーターは、クライアントから提供された任意のクエリ文字列に設定する必要があります。 これは通常、「?」の後に指定されたキーと値のペアになります。 URIで。 通常、このパラメータは次のいずれかに設定されます。 $query_string また $args 変数。どちらも同じデータを含む必要があります。
  • REQUEST_METHOD :このパラメーターは、クライアントによって要求されたアクションのタイプをFastCGIプロセッサーに示します。 これは、パスが正しく機能するために設定する必要がある数少ないパラメーターの1つです。
  • CONTENT_TYPE :上記で設定したリクエスト方式が「POST」の場合、このパラメータを設定する必要があります。 FastCGIプロセッサが期待するコンテンツのタイプを示します。 これはほとんどの場合、 $content_type 変数。元のリクエストの情報に従って設定されます。
  • CONTENT_LENGTH :リクエストメソッドが「POST」の場合、このパラメータを設定する必要があります。 これはコンテンツの長さを示します。 これはほとんどの場合、 $content_length、元のクライアント要求の情報から値を取得する変数。
  • SCRIPT_NAME :このパラメーターは、実行されるメインスクリプトの名前を示すために使用されます。 これは非常に重要なパラメータであり、ニーズに応じてさまざまな方法で設定できます。 多くの場合、これはに設定されます $fastcgi_script_name、これはリクエストURIである必要があり、リクエストURIは fastcgi_index スラッシュで終わる場合は追加、使用する場合は最初にキャプチャされたグループ fastcgi_fix_path_info.
  • SCRIPT_FILENAME :このパラメーターは、実行するスクリプトのディスク上の実際の場所を指定します。 との関係のため SCRIPT_NAME パラメータ、いくつかのガイドはあなたが使用することを提案します $document_root$fastcgi_script_name. 多くの利点がある別の選択肢は、を使用することです $request_filename.
  • REQUEST_URI :これには、実行するスクリプト、追加のパス情報、および引数を含む、変更されていない完全なリクエストURIが含まれている必要があります。 一部のアプリケーションは、この情報を自分で解析することを好みます。 このパラメーターは、それを行うために必要な情報を提供します。
  • PATH_INFO :もし cgi.fix_pathinfo PHP構成ファイルで「1」に設定されている場合、これにはスクリプト名の後に追加された追加のパス情報が含まれます。 これは、スクリプトが作用するファイル引数を定義するためによく使用されます。 設定 cgi.fix_pathinfo スクリプト要求が他の手段でサニタイズされていない場合、「1」に変更するとセキュリティに影響する可能性があります(これについては後で説明します)。 時々これはに設定されます $fastcgi_path_info 変数。 fastcgi_split_path_info 指令。 また、一時変数を使用する必要がある場合もあります。これは、その値が他の処理によって破壊されることがあるためです。
  • PATH_TRANSLATED :このパラメーターは、に含まれるパス情報をマップします PATH_INFO 実際のファイルシステムパスに。 通常、これは次のように設定されます $document_root$fastcgi_path_info、ただし、上記のように、後の変数を一時的に保存された変数に置き換える必要がある場合があります。

FastCGIに渡す前にリクエストを確認する

まだ取り上げていない非常に重要なトピックの1つは、動的リクエストをアプリケーションサーバーに安全に渡す方法です。 有効性に関係なく、すべてのリクエストをバックエンドアプリケーションに渡すことは、非効率的であるだけでなく、危険でもあります。 攻撃者がサーバーに任意のコードを実行させようとして、悪意のあるリクエストを作成する可能性があります。

この問題に対処するには、正当な要求のみをFastCGIプロセッサに送信していることを確認する必要があります。 これは、特定のセットアップのニーズや、FastCGIプロセッサがNginxインスタンスと同じシステム上にあるかどうかに応じて、さまざまな方法で実行できます。

構成を設計する方法を通知する必要がある基本的なルールの1つは、ユーザーファイルの処理と解釈を決して許可しないことです。 悪意のあるユーザーが、画像など、一見無害に見えるファイルに有効なコードを埋め込むのは比較的簡単です。 このようなファイルがサーバーにアップロードされたら、FastCGIプロセッサにファイルが送信されないようにする必要があります。

ここで解決しようとしている主な問題は、CGI仕様で実際に指定されている問題です。 この仕様では、実行するスクリプトファイルを指定し、その後にスクリプトで使用できる追加のパス情報を指定できます。 この実行モデルでは、ユーザーは正当なスクリプトのように見えるURIを要求できますが、実行される実際の部分はパスの早い段階にあります。

のリクエストを検討してください /test.jpg/index.php. 構成がで終わるすべての要求を単に渡す場合 .php プロセッサに対して、その正当性をテストせずに、プロセッサは、仕様に従っている場合、その場所をチェックし、可能であればそれを実行します。 ファイルが見つからない場合は、仕様に従い、実行を試みます。 /test.jpg ファイル、マーキング /index.php スクリプトの追加パス情報として。 ご覧のとおり、これは、ユーザーアップロードのアイデアと組み合わせると、非常に望ましくない結果をもたらす可能性があります。

この問題を解決するには、さまざまな方法があります。 アプリケーションが処理のためにこの追加のパス情報に依存しない場合、最も簡単なのは、プロセッサでそれをオフにすることです。 PHP-FPMの場合、これをオフにすることができます php.ini ファイル。 たとえば、Ubuntuシステムでは、次のファイルを編集できます。

sudo nano /etc/php5/fpm/php.ini

単に検索します cgi.fix_pathinfo オプションで、コメントを外し、「0」に設定して、この「機能」を無効にします。

cgi.fix_pathinfo=0

PHP-FPMプロセスを再起動して、変更を加えます。

sudo service php5-fpm restart

これにより、PHPはパスの最後のコンポーネントでのみ実行を試みます。 したがって、上記の例では、 /test.jpg/index.php ファイルが存在しなかった場合、PHPは実行しようとする代わりに正しくエラーになります /test.jpg.

FastCGIプロセッサがNginxインスタンスと同じマシン上にある場合の別のオプションは、プロセッサに渡す前に、ディスク上のファイルの存在を確認することです。 の場合 /test.jgp/index.php ファイルが存在しません、エラーが発生しました。 含まれている場合は、処理のためにバックエンドに送信します。 これにより、実際には、上記とほぼ同じ動作が発生します。

location ~ \.php$ {
        try_files $uri =404;

        . . .

}

アプリケーションがパス情報の動作に依存して正しい解釈を行う場合でも、リクエストをバックエンドに送信するかどうかを決定する前にチェックを行うことで、この動作を安全に許可できます。

たとえば、信頼できないアップロードを許可するディレクトリを具体的に照合し、それらがプロセッサに渡されないようにすることができます。 たとえば、アプリケーションのアップロードディレクトリが /uploads/、正規表現が評価される前に一致する次のようなロケーションブロックを作成できます。

location ^~ /uploads {
}

内部では、PHPファイルのあらゆる種類の処理を無効にすることができます。

location ^~ /uploads {
    location ~* \.php$ { return 403; }
}

親の場所は、で始まるすべてのリクエストに一致します /uploads PHPファイルを処理するリクエストは、バックエンドに送信する代わりに403エラーを返します。

また、使用することができます fastcgi_split_path_info スクリプトとして解釈する必要があるリクエストの部分と、正規表現を使用して追加のパス情報として定義する必要がある部分を手動で定義するディレクティブ。 これにより、パス情報機能に依存することができますが、スクリプトと見なすものとパスと見なすものを正確に定義できます。

たとえば、で終わるパスコンポーネントの最初のインスタンスを考慮するロケーションブロックを設定できます。 .php 実行するスクリプトとして。 残りは追加のパス情報と見なされます。 これは、リクエストのインスタンスで /test.jpg/index.php、パス全体を、追加のパス情報なしでスクリプト名としてプロセッサに送信できます。

この場所は次のようになります。

location ~ [^/]\.php(/|$) {

    fastcgi_split_path_info ^(.+?\.php)(.*)$;
    set $orig_path $fastcgi_path_info;

    try_files $fastcgi_script_name =404;

    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;

    fastcgi_param SCRIPT_FILENAME $request_filename;
    fastcgi_param PATH_INFO $orig_path;
    fastcgi_param PATH_TRANSLATED $document_root$orig_path;
}

上記のブロックは、次のようなPHP構成で機能するはずです。 cgi.fix_pathinfo 追加のパス情報を許可するには、「1」に設定されます。 ここで、ロケーションブロックは、で終わるリクエストだけでなく一致します .php、だけでなく、 .php 追加のディレクトリコンポーネントを示すスラッシュ(/)の直前が続きます。

ブロック内では、 fastcgi_split_path_info ディレクティブは、正規表現を使用して2つのキャプチャされたグループを定義します。 最初のグループは、URIの最初から最初のインスタンスまでの部分と一致します。 .php そしてそれを $fastcgi_script_name 変数。 次に、その時点以降の情報を2番目にキャプチャされたグループに配置し、次の変数に格納します。 $fastcgi_path_info.

を使用します set に保持されている値を格納するディレクティブ $fastcgi_path_info この時点でと呼ばれる変数に $orig_path. これは、 $fastcgi_path_info 変数は私たちによってすぐに一掃されます try_files 指令。

上記でキャプチャしたスクリプト名を使用してテストします try_files. これは、実行しようとしているスクリプトがディスク上にあることを確認するファイル操作です。 ただし、これには、クリアするという副作用もあります。 $fastcgi_path_info 変数。

従来のFastCGIパスを実行した後、 SCRIPT_FILENAME いつものように。 また、 PATH_INFO オフロードした値に $orig_path 変数。 私たちの $fastcgi_path_info がクリアされた場合、元の値はこの変数に保持されます。 また、 PATH_TRANSLATED 追加のパス情報をディスク上の存在する場所にマップするためのパラメーター。 これを行うには、 $document_root 変数 $orig_path 変数。

これにより、次のようなリクエストを作成できます /index.php/users/view だから私たちの /index.php ファイルはに関する情報を処理できます /users/view ディレクトリ、状況を回避しながら /test.jpg/index.php 実行されます。 スクリプトは常に、で終わる最短のコンポーネントに設定されます .php、したがって、この問題を回避します。

スクリプトファイルの場所を変更する必要がある場合は、エイリアスディレクティブを使用してこれを機能させることもできます。 これは、ロケーションヘッダーとロケーションヘッダーの両方で説明する必要があります。 fastcgi_split_path_info 意味:

location ~ /test/.+[^/]\.php(/|$) {

    alias /var/www/html;

    fastcgi_split_path_info ^/test(.+?\.php)(.*)$;
    set $orig_path $fastcgi_path_info;

    try_files $fastcgi_script_name =404;

    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;

    fastcgi_param SCRIPT_FILENAME $request_filename;
    fastcgi_param PATH_INFO $orig_path;
    fastcgi_param PATH_TRANSLATED $document_root$orig_path;
}

これらを使用すると、を利用するアプリケーションを実行できます。 PATH_INFO パラメータを安全に。 覚えておいてください、あなたは変更する必要があります cgi.fix_pathinfo あなたのオプション php.ini これを正しく機能させるには、ファイルを「1」にします。 また、オフにする必要があるかもしれません security.limit_extensions あなたの中で php-fpm.conf ファイル。

結論

うまくいけば、これでNginxのFastCGIプロキシ機能について理解を深めることができます。 この機能により、Nginxは、動的コンテンツの責任をより適切なソフトウェアにオフロードしながら、高速接続処理と静的コンテンツの提供という強みを発揮できます。 FastCGIを使用すると、Nginxは、パフォーマンスが高く安全な構成で、多数のアプリケーションと連携できます。