序章

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ドキュメントには、各ディレクティブが有効なコンテキストに関する情報が含まれているため、不明な点がある場合は参考にしてください。

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

コアコンテキスト

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

メインコンテキスト

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

# The main context is here, outside any other contexts

. . .

context {

    . . .

}

これらのブロックの完全に外側に存在するディレクティブは、「メイン」コンテキストに存在すると言われます。 Nginx構成がモジュール方式でセットアップされている場合、一部のファイルには、括弧で囲まれたコンテキストの外側に存在するように見える命令が含まれますが、構成がつなぎ合わされると、そのようなコンテキストに含まれることに注意してください。

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

メインコンテキストで構成される一般的な詳細には、ワーカープロセスを実行するユーザーとグループ、ワーカーの数、およびメインプロセスの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_logerror_log)、ファイル操作用の非同期I / Oを構成します(aio, sendfile、 と directio)、エラーが発生したときのサーバーのステータスを構成します(error_page). 他のディレクティブは圧縮を構成します(gzipgzip_disable)、TCPキープアライブ設定を微調整します(keepalive_disable, keepalive_requests、 と keepalive_timeout)、およびパケットとシステムコールを最適化するためにNginxが従うルール(sendfile, tcp_nodelay、 と tcp_nopush). 追加のディレクティブは、アプリケーションレベルのドキュメントルートファイルとインデックスファイルを構成します(rootindex)そして、さまざまなタイプのデータを格納するために使用されるさまざまなハッシュテーブルを設定します(*_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 :このディレクティブは、処理するサーバーブロックを選択するために使用されるもう1つのコンポーネントです。 リクエストを処理できる同じ特異性のlistenディレクティブを持つサーバーブロックが複数ある場合、Nginxはリクエストの「Host」ヘッダーを解析し、このディレクティブと照合します。

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

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

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

サーバーブロックを選択するかどうかを決定するディレクティブはサーバーcontext内で定義されますが、リクエストを処理する場所の機能を決定するコンポーネントは、場所 defined (ロケーションブロックを開く行)。

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

location match_modifier location_match {

    . . .

}

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

# main context

server {
    
    # server context

    location /match/criteria {

        # first location context

    }

    location /other/criteria {

        # second location context

        location nested_match {

            # first nested location

        }

        location other_nested {

            # second nested location

        }

    }

}

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

したがって、クライアントが要求した場合 http://www.example.com/blog ポート80では、 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で提供されます nginx.conf 設定ファイル。
  • charset_map :これはマッピングコンテキストの別の例です。 このコンテキストは、変換テーブルをある文字セットから別の文字セットにマップするために使用されます。 コンテキストヘッダーには両方のセットがリストされ、本文にはマッピングが行われます。

以下のコンテキストは、これまでに説明したコンテキストほど一般的ではありませんが、それでも知っておくと非常に役立ちます。

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

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

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

# main context

http {

    # http context

    upstream upstream_name {

        # upstream context

        server proxy_server1;
        server proxy_server2;

        . . .

    }

    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は他の多くの専用ディレクティブを使用してリクエストの条件をテストするため、ほとんどの形式の条件付き実行に使用しない必要があります。 これは、Nginxコミュニティが if isevilというページを作成したという重要な注意事項です。

問題は基本的に、Nginxの処理順序が、ifブロックの意味を覆すように見える予期しない結果につながる可能性が非常に高いことです。 これらのコンテキスト内で確実に安全に使用できると見なされるディレクティブは、 returnrewrite ディレクティブ(このコンテキストが作成されたもの)。 ifコンテキストを使用するときに覚えておくべきもう一つのことは、それがレンダリングすることです try_files 同じコンテキストのディレクティブは役に立たない。

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

# main context

http {

    # http context

    server {

        # server context

        location location_match {

            # location context

            if (test_condition) {

                # if context

            }

        }

    }

}

Limit_exceptコンテキスト

The 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つのブロックを設定してみてください。一方は目的のメソッドを表し、もう一方はキャッチします。厄介なリクエストとそれらを正しいブロックにリダイレクト(そして場合によっては書き換え)します。

結果は通常読みやすく、パフォーマンスが向上するという追加の利点もあります。 正しいリクエストは追加の処理を受けず、多くの場合、誤ったリクエストはリライトではなくリダイレクトで処理できます。リライトはより低いオーバーヘッドで実行されるはずです。

結論

この時点で、Nginxの最も一般的なコンテキストと、それらを定義するブロックを作成するディレクティブを十分に理解しているはずです。

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