Nginx設定ファイルの構造と設定コンテキストを理解する

前書き

Nginxは、インターネット上の最大規模のサイトのいくつかの負荷を処理する高性能Webサーバーです。 多くの同時接続の処理に特に優れており、静的コンテンツの提供に優れています。

多くのユーザーはNginxの機能を認識していますが、新しいユーザーはNginxの構成ファイルにあるいくつかの規則に戸惑うことがよくあります。 このガイドでは、ファイルの設計方法に関するガイドラインとともに、Nginx構成ファイルの基本構造について説明します。

Nginx設定コンテキストについて

このガイドでは、メインのNginx構成ファイルにある基本構造について説明します。 このファイルの場所は、マシンにソフトウェアをインストールした方法によって異なります。 多くのディストリビューションでは、ファイルは `+ / etc / nginx / nginx.conf `にあります。 存在しない場合は、 ` / usr / local / nginx / conf / nginx.conf `または ` / usr / local / etc / nginx / nginx.conf +`にある可能性があります。

メインの設定ファイルを見たときに最初に気づくべきことの1つは、括弧のセット(「+ {」と「} ++」 )。 Nginxの用語では、これらの括弧が定義する領域は「関心領域」と呼ばれます。これらの領域には、関心領域に応じて構成の詳細が含まれているためです。 基本的に、これらの部門は、内部に構成を適用するかどうかを決定するための条件付きロジックとともに組織構造を提供します。

コンテキストは相互に階層化できるため、Nginxはディレクティブ継承のレベルを提供します。 原則として、ディレクティブが複数のネストされたスコープで有効な場合、より広いコンテキストでの宣言がデフォルト値としてすべての子コンテキストに渡されます。 子コンテキストは、これらの値を自由にオーバーライドできます。 配列型ディレクティブへのオーバーライドは、前の値に追加するのではなく、前の値を「置換」することに注意してください。

ディレクティブは、それらが設計されたコンテキストでのみ使用できます。 Nginxは、間違ったコンテキストで宣言されたディレクティブを含む構成ファイルの読み取りでエラーになります。 Nginx documentationには、各ディレクティブが有効なコンテキストに関する情報が含まれているため、よくわからない場合は参考になります。

以下では、Nginxを使用するときに遭遇する可能性のある最も一般的なコンテキストについて説明します。

コアコンテキスト

コンテキストの最初のグループは、階層ツリーを作成し、個別の構成ブロックの懸念を分離するためにNginxが使用するコアコンテキストです。 これらは、Nginx構成の主要な構造を構成するコンテキストです。

メインコンテキスト

最も一般的なコンテキストは、「メイン」または「グローバル」コンテキストです。 次のような典型的なコンテキストブロックに含まれていない唯一のコンテキストです。

# The main context is here, outside any other contexts

. . .

{

   . . .

}

これらのブロックの外側に完全に存在するディレクティブは、「メイン」コンテキストに存在すると言われています。 Nginxの構成がモジュラー形式で設定されている場合、一部のファイルには、ブラケットコンテキストの外側に存在するように見える命令が含まれますが、構成が結合されるとそのようなコンテキストに含まれます。

メインコンテキストは、Nginx構成の最も広範な環境を表します。 これは、基本レベルでアプリケーション全体に影響する詳細を構成するために使用されます。 このセクションのディレクティブは下位コンテキストに影響を与えますが、これらの多くは下位レベルでオーバーライドできないため、_inherited_ではありません。

メインコンテキストで設定される一般的な詳細には、ワーカープロセスを実行するユーザーとグループ、ワーカーの数、メインプロセスのPIDを保存するファイルがあります。 ワーカーのCPUアフィニティやワーカープロセスの「良さ」などを定義することもできます。 アプリケーション全体のデフォルトのエラーファイルは、このレベルで設定できます(これは、より具体的なコンテキストでオーバーライドできます)。

イベントコンテキスト

「イベント」コンテキストは、「メイン」コンテキスト内に含まれています。 これは、Nginxが一般的なレベルで接続を処理する方法に影響するグローバルオプションを設定するために使用されます。 Nginx構成内で定義できるイベントコンテキストは1つだけです。

このコンテキストは、構成ファイルでは、他の括弧で囲まれたコンテキスト以外では次のようになります。

# main context

events {

   # events context
   . . .

}

Nginxはイベントベースの接続処理モデルを使用するため、このコンテキスト内で定義されたディレクティブは、ワーカープロセスが接続を処理する方法を決定します。 主に、ここにあるディレクティブは、使用する接続処理技術を選択するか、これらのメソッドの実装方法を変更するために使用されます。

通常、接続処理方法は、プラットフォームで利用可能な最も効率的な選択に基づいて自動的に選択されます。 Linuxシステムでは、通常、 `+ epoll +`メソッドが最良の選択です。

構成可能なその他の項目は、各ワーカーが処理できる接続の数、ワーカーが一度に1つの接続のみを取得するか、保留中の接続について通知された後にすべての保留中の接続を取得するか、ワーカーがイベントに応答して交代するかどうかです。

HTTPコンテキスト

NginxをWebサーバーまたはリバースプロキシとして構成する場合、「http」コンテキストが構成の大部分を保持します。 このコンテキストには、プログラムがHTTPまたはHTTPS接続を処理する方法を定義するために必要なすべてのディレクティブとその他のコンテキストが含まれます。

httpコンテキストはイベントコンテキストの兄弟であるため、ネストするのではなく、並べてリストする必要があります。 どちらもメインコンテキストの子です。

# main context

events {
   # events context

   . . .

}

http {
   # http context

   . . .

}

下位コンテキストはリクエストの処理方法についてより具体的になりますが、このレベルのディレクティブは、内部で定義されたすべての仮想サーバーのデフォルトを制御します。 継承を機能させる方法に応じて、このコンテキスト以下で多数のディレクティブを構成できます。

遭遇する可能性があるディレクティブのいくつかは、アクセスおよびエラーログのデフォルトの場所を制御し( + access_log +`および `+ error_log +)、ファイル操作の非同期I / Oを構成します( + aio ++ sendfile +、および + directio +)、エラー発生時のサーバーのステータスを設定します( + error_page +)。 その他のディレクティブは、圧縮( + gzip +`および `+ gzip_disable +)を構成し、TCPキープアライブ設定( + keepalive_disable ++ keepalive_requests +、および + keepalive_timeout +)を微調整し、Nginxが従うルールを設定しますパケットとシステムコール( + sendfile ++ tcp_nodelay +、および + tcp_nopush +)を最適化してください。 追加のディレクティブは、アプリケーションレベルのドキュメントルートとインデックスファイル( + root +`と `+ index +)を設定し、異なるタイプのデータを保存するために使用されるさまざまなハッシュテーブルを設定します( + * _ hash_bucket_size +`と `+ * _ hash_max_size + `+ server_names ++ types +、および `+ variables +`の場合)。

サーバーコンテキスト

「サーバー」コンテキストは、「http」コンテキスト内で宣言されます。 これは、ネストされたブラケットコンテキストの最初の例です。 また、複数の宣言を許可する最初のコンテキストでもあります。

サーバーコンテキストの一般的な形式は次のようになります。 これらはhttpコンテキスト内にあることに注意してください。

# main context

http {

   # http context

   server {

       # first server context

   }

   server {

       # second server context

   }

}

サーバーコンテキストの複数の宣言を許可する理由は、各インスタンスがクライアント要求を処理する特定の仮想サーバーを定義するためです。 サーバーブロックは必要な数だけ持つことができ、各ブロックは接続の特定のサブセットを処理できます。

複数のサーバーブロックの可能性と可能性のため、このコンテキストタイプは、決定を行うためにNginxが選択アルゴリズムを使用する必要がある最初のコンテキストタイプでもあります。 各クライアントリクエストは、単一のサーバーコンテキストで定義された構成に従って処理されるため、Nginxは、リクエストの詳細に基づいてどのサーバーコンテキストが最も適切かを判断する必要があります。 サーバーブロックを使用して要求に応答するかどうかを決定するディレクティブは次のとおりです。

  • * listen *:このサーバーブロックが応答するように設計されているIPアドレス/ポートの組み合わせ。 これらの値に一致するクライアントによって要求が行われた場合、接続を処理するためにこのブロックが選択される可能性があります。

  • * server_name *:このディレクティブは、処理するサーバーブロックを選択するために使用される他のコンポーネントです。 リクエストを処理できる同じ特定のリッスンディレクティブを持つ複数のサーバーブロックがある場合、Nginxはリクエストの「ホスト」ヘッダーを解析し、このディレクティブと照合します。

このコンテキストのディレクティブは、ロギング、ドキュメントルート、圧縮など、httpコンテキストで定義されるディレクティブの多くをオーバーライドできます。 httpコンテキストから取得されたディレクティブに加えて、リクエストに応答する( + try_files +)ようにファイルを設定し、リダイレクトとリライトを発行する( + return +`と `+ rewrite +)、および任意に設定することもできます変数( + set +)。

ロケーションコンテキスト

定期的に対処する次のコンテキストは、ロケーションコンテキストです。 ロケーションコンテキストは、サーバーコンテキストと多くのリレーショナル品質を共有します。 たとえば、複数のロケーションコンテキストを定義し、各ロケーションを使用して特定のタイプのクライアントリクエストを処理し、選択アルゴリズムを使用してロケーション定義をクライアントリクエストと照合することにより、各ロケーションを選択します。

サーバーブロックを選択するかどうかを決定するディレクティブはサーバー_context_内で定義されますが、要求を処理する場所の機能を決定するコンポーネントは、場所_definition_(場所ブロックを開く行)にあります。

一般的な構文は次のようになります。

location   {

   . . .

}

ロケーションブロックはサーバーコンテキスト内に存在し、サーバーブロックとは異なり、互いに入れ子にすることができます。 これは、トラフィックの特定のサブセットをキャッチするためのより一般的なロケーションコンテキストを作成し、追加のコンテキストを含むより具体的な基準に基づいてさらに処理する場合に役立ちます。

# main context

server {

   # server context

   location  {

       # first location context

   }

   location  {

       # second location context

       location  {

           # first nested location

       }

       location  {

           # second nested location

       }

   }

}

サーバーコンテキストは、要求されたIPアドレス/ポートの組み合わせと「ホスト」ヘッダーのホスト名に基づいて選択されますが、ロケーションブロックは、リクエストURIを見てサーバーブロック内のリクエスト処理をさらに分割します。 リクエストURIは、ドメイン名またはIPアドレス/ポートの組み合わせの後に来るリクエストの部分です。

そのため、クライアントがポート80で + http:// www.example.com / blog +`を要求した場合、 `+ http ++ www.example.com +、およびポート80がすべてのサーバーを決定するために使用されます選択するブロック。 サーバーが選択された後、 `+ / blog +`部分(リクエストURI)は、定義された場所に対して評価され、リクエストに応答するためにさらにどのコンテキストを使用するかを決定します。

ロケーションコンテキストで表示される可能性が高いディレクティブの多くは、親レベルでも使用できます。 このレベルの新しいディレクティブを使用すると、ドキュメントルート以外の場所( + alias +)に到達し、その場所を内部でのみアクセス可能( + internal +)としてマークし、他のサーバーまたは場所にプロキシすることができます(http、fastcgi、scgiを使用) 、およびuwsgiプロキシ)。

その他のコンテキスト

上記の例は、Nginxで遭遇する本質的なコンテキストを表していますが、他のコンテキストも存在します。 以下のコンテキストは、より多くのオプションモジュールに依存する、特定の状況でのみ使用される、またはほとんどの人が使用しない機能に使用されるため、分離されました。

ただし、使用可能な各コンテキストについては説明しません。 次のコンテキストについては詳しく説明しません。

  • * + split_clients + *:このコンテキストは、割合に基づいて変数でラベル付けすることにより、サーバーが受信するクライアントをカテゴリに分割するように設定されます。 これらを使用して、異なるホストに異なるコンテンツを提供することにより、A / Bテストを実行できます。

  • * + perl / perl_set + *:これらのコンテキストは、表示される場所のPerlハンドラーを構成します。 これは、Perlでの処理にのみ使用されます。

  • * + map + *:このコンテキストは、別の変数の値に応じて変数の値を設定するために使用されます。 1つの変数の値のマッピングを提供して、2番目の変数の設定を決定します。

  • * + geo + *:上記のコンテキストと同様に、このコンテキストはマッピングを指定するために使用されます。 ただし、このマッピングは、クライアントIPアドレスを分類するために特に使用されます。 接続するIPアドレスに応じて変数の値を設定します。

  • * + types + *:このコンテキストは再びマッピングに使用されます。 このコンテキストは、MIMEタイプをそれらに関連付けられるファイル拡張子にマップするために使用されます。 これは通常、メインの `+ nginx.conf +`設定ファイルにソースされるファイルを通じてNginxで提供されます。

  • * + charset_map + *:これはマッピングコンテキストの別の例です。 このコンテキストは、変換テーブルをある文字セットから別の文字セットにマッピングするために使用されます。 コンテキストヘッダーには両方のセットがリストされ、本文にはマッピングが行われます。

以下のコンテキストは、これまで説明してきたコンテキストほど一般的ではありませんが、知っておくと便利です。

アップストリームコンテキスト

アップストリームコンテキストは、「アップストリーム」サーバーを定義および構成するために使用されます。 基本的に、このコンテキストはNginxがリクエストをプロキシできるサーバーの名前付きプールを定義します。 このコンテキストは、さまざまなタイプのプロキシを構成するときに使用される可能性があります。

アップストリームコンテキストは、特定のサーバーコンテキスト外のhttpコンテキスト内に配置する必要があります。 一般的な形式は次のようになります。

# main context

http {

   # http context

   upstream  {

       # upstream context

       server ;
       server ;

       . . .

   }

   server {

       # server context

   }

}

その後、サーバーまたはロケーションブロック内の名前でアップストリームコンテキストを参照して、特定のタイプの要求を定義済みのサーバーのプールに渡すことができます。 その後、アップストリームはアルゴリズム(デフォルトではラウンドロビン)を使用して、要求を渡す特定のサーバーを決定します。 このコンテキストにより、Nginxはリクエストをプロキシするときに負荷分散を行うことができます。

メールコンテキスト

NginxはWebまたはリバースプロキシサーバーとして最もよく使用されますが、高性能メールプロキシサーバーとしても機能します。 このタイプのディレクティブに使用されるコンテキストは、適切に「メール」と呼ばれます。 メールコンテキストは、「メイン」または「グローバル」コンテキスト内(httpコンテキスト外)で定義されます。

メールコンテキストの主な機能は、サーバーでメールプロキシソリューションを構成するための領域を提供することです。 Nginxには、認証要求を外部認証サーバーにリダイレクトする機能があります。 その後、POP3およびIMAPメールサーバーへのアクセスを提供して、実際のメールデータを提供できます。 必要に応じて、SMTPリレーホストに接続するようにメールコンテキストを構成することもできます。

一般に、メールコンテキストは次のようになります。

# main context

events {

   # events context

}

mail {

   # mail context

}

Ifコンテキスト

「if」コンテキストを確立して、内部で定義されたディレクティブの条件付き処理を提供できます。 従来のプログラミングのifステートメントのように、Nginxのifディレクティブは、特定のテストが「true」を返す場合に含まれる命令を実行します。

Nginxのifコンテキストは書き換えモジュールによって提供され、これがこのコンテキストの主な使用目的です。 Nginxは、他の多くの専用のディレクティブを使用してリクエストの条件をテストするため、ほとんどの形式の条件付き実行にはifを使用しないでください。 これは、Nginxコミュニティがhttps://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/[if is evil]というページを作成したという重要な注意事項です。

問題は、基本的に、Nginxの処理順序がifブロックの意味を覆すように思われる予期しない結果をもたらすことが非常に多いことです。 これらのコンテキスト内で安全に使用できると見なされるディレクティブは、 `+ return `および ` rewrite `ディレクティブ(このコンテキストが作成されたもの)のみです。 ifコンテキストを使用する際に注意すべきもう1つの点は、同じコンテキストで ` try_files +`ディレクティブを役に立たないものにすることです。

ほとんどの場合、書き換えまたは復帰が必要かどうかを判断するためにifが使用されます。 これらはほとんどの場合ロケーションブロックに存在するため、一般的な形式は次のようになります。

# main context

http {

   # http context

   server {

       # server context

       location  {

           # location context

           if () {

               # if context

           }

       }

   }

}

Limit_exceptコンテキスト

`+ limit_except `コンテキストは、ロケーションコンテキスト内の特定のHTTPメソッドの使用を制限するために使用されます。 たとえば、特定のクライアントのみがPOSTコンテンツにアクセスできる必要があり、誰もがコンテンツを読み取ることができる必要がある場合、 ` limit_except +`ブロックを使用してこの要件を定義できます。

上記の例は次のようになります。

. . .

# server or location context

location /restricted-write {

   # location context

   limit_except GET HEAD {

       # limit_except context

       allow 192.168.1.1/24;
       deny all;
   }
}

これにより、コンテキストヘッダーにリストされているものを除く* HTTP *メソッドが検出されると、コンテキスト内にディレクティブが適用されます(アクセスを制限する意味)。 上記の例の結果、どのクライアントもGETおよびHEAD動詞を使用できますが、「+ 192.168.1.1/24+」サブネットからのクライアントのみが他の方法を使用できます。

コンテキストに関する従う一般的な規則

Nginxの設定を検討する際に遭遇する可能性のある一般的なコンテキストのアイデアが得られたので、Nginxコンテキストを扱うときに使用するいくつかのベストプラクティスについて説明します。

利用可能な最高のコンテキストでディレクティブを適用する

多くのディレクティブは、複数のコンテキストで有効です。 たとえば、http、サーバー、または場所のコンテキストに配置できるディレクティブはかなりあります。 これにより、これらのディレクティブを柔軟に設定できます。

ただし、原則として、通常、ディレクティブは適用可能な最高のコンテキストで宣言し、必要に応じて下位のコンテキストでオーバーライドするのが最善です。 これは、Nginxが実装する継承モデルのために可能です。 この戦略を使用する理由はたくさんあります。

まず、高レベルで宣言することにより、兄弟コンテキスト間の不要な繰り返しを回避できます。 たとえば、次の例では、各場所が同じドキュメントルートを宣言しています。

http {
   server {
       location / {
           root /var/www/html;

           . . .

       }

       location /another {
           root /var/www/html;

           . . .

       }

   }
}

次のように、ルートをサーバーブロックに移動することも、httpブロックに移動することもできます。

http {
   root /var/www/html;
   server {
       location / {

           . . .

       }

       location /another {

           . . .

       }
   }
}

ほとんどの場合、サーバーレベルが最も適切ですが、より高いレベルで宣言することには利点があります。 これにより、ディレクティブをより少ない場所に設定できるだけでなく、デフォルト値をすべての子要素にカスケードして、下位レベルのディレクティブを忘れてエラーが発生する状況を防ぐことができます。 これは、長い構成では大きな問題になる可能性があります。 より高いレベルで宣言すると、正常なデフォルトが提供されます。

処理にifロジックの代わりに複数の兄弟コンテキストを使用する

クライアントのリクエストに含まれる情報に応じてリクエストを異なる方法で処理したい場合、多くの場合、ユーザーは「if」コンテキストにジャンプして処理の条件付けを試みます。 これには、以前に簡単に触れたいくつかの問題があります。

1つ目は、「if」ディレクティブが多くの場合、管理者の期待と一致しない結果を返すことです。 処理は常に同じ入力に対して同じ結果をもたらしますが、Nginxが環境を解釈する方法は、厳しいテストなしで想定できる方法とは大きく異なる場合があります。

これの2番目の理由は、これらの目的の多くに使用される最適化された専用のディレクティブが既に存在することです。 Nginxは、サーバーブロックやロケーションブロックの選択など、既に十分に文書化された選択アルゴリズムに取り組んでいます。 そのため、可能であれば、このアルゴリズムが選択プロセスロジックを処理できるように、異なる構成を独自のブロックに移動することをお勧めします。

例えば、書き換えに頼ってユーザーが提供したリクエストを作業したいフォーマットに変換する代わりに、リクエストに対して2つのブロックを設定してみてください。1つは目的のメソッドを表し、もう1つはキャッチします乱雑な要求とそれらを正しいブロックにリダイレクト(および場合によっては書き換え)します。

通常、結果は読みやすく、パフォーマンスが向上するという利点もあります。 正しいリクエストには追加の処理は行われず、多くの場合、誤ったリクエストは書き換えではなくリダイレ​​クトで取得できます。書き換えはオーバーヘッドを抑えて実行する必要があります。

結論

この時点までに、Nginxの最も一般的なコンテキストと、それらを定義するブロックを作成するディレクティブを十分に把握する必要があります。

Nginxのドキュメントで、ディレクティブを配置できるコンテキストについて、および最も効果的な場所を評価するための情報を常に確認してください。 構成を作成するときに注意を払うと、保守性が向上するだけでなく、多くの場合パフォーマンスも向上します。