NginxでのFastCGIプロキシの理解と実装

前書き

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

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

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

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

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

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

FastCGIプロキシの基本

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

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

# server context

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

. . .

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

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

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

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;
}

. . .

上記の構成では、「+ REQUEST_METHOD 」と「 SCRIPT_FILENAME +」という2つのFastCGIパラメーターを設定します。 これらは両方とも、バックエンドサーバーが要求の性質を理解するために必要です。 前者は実行すべき操作の種類を示し、後者は実行するファイルをアップストリームに通知します。

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

+ SCRIPT_FILENAME +`パラメーターは、 `+ $ document_root +`変数と `+ $ fastcgi_script_name +`変数の組み合わせに設定されます。 `+ $ document_root`には、 + root`ディレクトリで設定されたベースディレクトリへのパスが含まれます。 `+ $ 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(「自分自身を繰り返さない」)の原則に従うことです。 これにより、エラーの削減、再利用性の向上、組織の改善が可能になります。 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 `が宣言されている場合、親コンテキストの ` fastcgi_param +`値の_none_が継承されます。 継承された値のみを使用するか、どれも使用しません。

`+ fastcgi_param `ディレクティブは、Nginxの用語では_array_ディレクティブです。 ユーザーの観点から見ると、配列ディレクティブは基本的に、単一のコンテキストで複数回使用できるディレクティブです。 後続の各宣言は、Nginxが前の宣言から知っているものに新しい情報を追加します。 ` 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_METHOD `と ` SCRIPT_FILENAME `パラメーターは2番目のロケーションブロックに継承され、 ` QUERY_STRING +`パラメーターはその特定のコンテキストでさらに利用できると考えるかもしれません。

実際に起こることは、親の `+ fastcgi_param `値の_all_が2番目のコンテキストで消去され、 ` QUERY_STRING `パラメーターのみが設定されることです。 ` REQUEST_METHOD `および ` SCRIPT_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;
}

. . .

上記の例では、1つのコンテキスト内で + TEST`および + DOCUMENT_ROOT`パラメーターを複数回設定しています。 + fastcgi_param +`は配列ディレクティブであるため、後続の各宣言はNginxの内部レコードに追加されます。 `+ TEST +`パラメータには、配列に宣言があり、 `+ one、` + two`、および `+ three`に設定されます。

この時点で理解することが重要なのは、これらすべてがNginxからのさらなる処理なしにFastCGIバックエンドに渡されることです。 つまり、これらの値の処理方法を決定するのは、選択したFastCGIプロセッサ次第です。 残念ながら、異なるFastCGIプロセッサは、渡された値を処理しますhttp://serverfault.com/questions/512028/nginx-fcgiwrap-how-come-order-of-fastcgi-param-matters [完全に異なる]。

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

ただし、上記の値がFsgiWrapのようなものに渡される場合、値は非常に異なって解釈されます。 最初に、スクリプトを実行するために使用する値を決定する初期パスを作成します。 スクリプトを探すために、 `+ initial `の ` DOCUMENT_ROOT +`値を使用します。 ただし、実際のパラメーターをスクリプトに渡すと、PHP-FPMと同様に最終的な値が渡されます。

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

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

共通の構成アイテムを分離する別の方法があります。 `+ include +`ディレクティブを使用して、別のファイルの内容をディレクティブ宣言の場所に読み込むことができます。

これは、すべての共通の構成アイテムを単一のファイルに保持し、必要な構成のどこにでも含めることができることを意味します。 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 `値をデフォルトのNginx設定ディレクトリ内の ` fastcgi_common +`というファイルに移動しました。 次に、内部で宣言された値を挿入するときに、そのファイルをソースします。

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

最初のことは、ソースする予定のファイルに、ロケーションごとにカスタマイズしたい値を配置しなかったことです。 同じパラメーターに複数の値を設定するときに発生する上記の解釈の問題、および非配列ディレクティブはコンテキストごとに1回しか設定できないため、変更したくない共通ファイルにのみアイテムを配置します。 コンテキストごとにカスタマイズしたいすべてのディレクティブ(またはパラメーターキー)は、共通ファイルから除外する必要があります。

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

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

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

これらの2つのファイルはほとんど同じですが、実際には、1つのパラメーターに複数の値を渡すことについて前述した問題の結果だけが違います。 `+ fastcgi_params `ファイルには ` SCRIPT_FILENAME `パラメーターの宣言が含まれていませんが、 ` fastcgi.conf +`ファイルには含まれています。

`+ fastcgi_params `ファイルはずっと長い間利用可能です。 ` fastcgi_params `に依存する設定が壊れないようにするために、 ` SCRIPT_FILENAME +`のデフォルト値を提供する決定が下されたときに、新しいファイルを作成する必要がありました。 そうしないと、共通ファイルとFastCGIパスの両方の場所でそのパラメーターが設定される可能性があります。 これについては、http://blog.martinfjordvald.com/2013/04/nginx-config-history-fastcgi_params-versus-fastcgi-conf/ [これら2つのファイルの歴史に関するMartin Fjordvaldの優れた投稿]で詳しく説明されています。

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

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

これらは、ルートNginx構成ディレクトリに相対的な場所を参照することで含めることができます。 Nginxがパッケージマネージャーと共にインストールされている場合、ルートNginx設定ディレクトリは通常、「+ / etc / 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モジュールで定義されていますが、ほとんどはコアモジュールのものです。

  • * + $ 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 + *:この変数には、要求されたファイルのファイルパスが含まれます。 `+ root `と ` alias `ディレクティブの両方、および ` $ fastcgi_script_name `の値を考慮して、現在のドキュメントルートの値を取得することでこの値を取得します。 これは、 ` SCRIPT_FILENAME +`パラメーターを割り当てる非常に柔軟な方法です。

  • * + $ request_uri + *:クライアントから受け取ったリクエスト全体。 これには、スクリプト、追加のパス情報、およびクエリ文字列が含まれます。

  • * + $ fastcgi_path_info + *:この変数には、リクエストのスクリプト名の後に使用できる追加のパス情報が含まれます。 この値には、実行するスクリプトが認識すべき別の場所が含まれている場合があります。 この変数は、 `+ fastcgi_split_path_info +`ディレクティブを使用するときに、2番目にキャプチャされた正規表現グループから値を取得します。

  • * + $ 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、スラッシュで終わる場合は ` fastcgi_index `が追加されたリクエストURI、または ` fastcgi_fix_path_info +`を使用する場合は最初にキャプチャされたグループです。

  • * + SCRIPT_FILENAME + *:このパラメーターは、実行するスクリプトのディスク上の実際の場所を指定します。 `+ SCRIPT_NAME `パラメータとの関係のため、一部のガイドでは、 ` $ document_root $ fastcgi_script_name `の使用を推奨しています。 多くの利点がある別の選択肢は、 ` $ request_filename l`を使用することです。

  • * + REQUEST_URI + *:これには、変更されていない完全なリクエストURI、実行するスクリプト、追加のパス情報、および引数が含まれている必要があります。 一部のアプリケーションは、この情報を自分で解析することを好みます。 このパラメーターは、そのために必要な情報を提供します。

  • * + PATH_INFO + *:PHP構成ファイルで `+ cgi.fix_pathinfo `が「1」に設定されている場合、スクリプト名の後に追加された追加のパス情報が含まれます。 これは、スクリプトが動作するファイル引数を定義するためによく使用されます。 スクリプト要求が他の手段でサニタイズされない場合、「 cgi.fix_pathinfo 」を「1」に設定すると、セキュリティに影響する可能性があります(これについては後で説明します)。 時々、これは ` $ fastcgi_path_info `変数に設定され、 ` fastcgi_split_path_info +`ディレクティブから2番目にキャプチャされたグループが含まれます。 また、一時変数を使用する必要がある場合もありますが、その値は他の処理によって上書きされる場合があるためです。

  • * + 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 in`のリクエストのインスタンスでは、追加のパス情報なしでスクリプト名としてパス全体をプロセッサに送信できることを意味します。

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

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;
}

上記のブロックは、追加のパス情報を許可するために `+ cgi.fix_pathinfo `が「1」に設定されているPHP構成で動作するはずです。 ここで、ロケーションブロックは、 ` .php `で終わるリクエストだけでなく、追加のディレクトリコンポーネントを示すスラッシュ(/)の直前にある ` .php +`を持つリクエストにも一致します。

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

`+ set `ディレクティブを使用して、この時点で ` $ fastcgi_path_info `に保持されている値を ` $ orig_path `という変数に保存します。 これは、 ` try_files `ディレクティブによって ` $ fastcgi_path_info +`変数がすぐに消去されるためです。

`+ 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 +`パラメーターを安全に利用するアプリケーションを実行できます。 これを正しく機能させるには、 `+ php.ini`ファイルの + cgi.fix_pathinfo`オプションを「1」に変更する必要があります。 `+ php-fpm.conf `ファイルで ` security.limit_extensions +`をオフにする必要があるかもしれません。

結論

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

前の投稿:CoreOSクラスター上にKubernetesをインストールおよび構成する方法
次の投稿:Ubuntu 14.04でGogsをセットアップする方法