問題を抱えているNGINXユーザーを支援していると、ほかのユーザーの設定で何度も目にしてきたものと同じ設定ミスによく遭遇します。時には、NGINXエンジニアが作成した設定にも見られます。本ブログでは、特によくある10のエラーを取り上げ、問題点と修正方法を解説します。
- ワーカーあたりのファイルディスクリプター数が不足
- The
error_logoffdirective - アップストリームサーバーへのキープアライブ接続を有効にしないこと
- ディレクティブの継承の仕組みを忘れる
- The
proxy_bufferingoffディレクティブ - Improper use of the
ifディレクティブの不適切な使用 - 過剰なヘルスチェック
- メトリクスへのセキュリティで保護されていないアクセス
- すべてのトラフィックが同じ/24 CIDRブロックから送信される場合に「
ip_hash」を使用 - upstreamグループを活用していない
間違い1:ワーカーあたりのファイルディスクリプター数が不足している
The worker_connectionsディレクティブは、NGINXワーカープロセスが同時に開いておける接続数の上限を設定します(デフォルトは512)。この上限には、クライアント接続だけでなく、プロキシ先サーバーとの接続など、あらゆる種類の接続が含まれます。ただし、ワーカーあたりの同時接続数には、最終的にもう1つの制限がある点に注意が必要です。それは、各プロセスに割り当てられるファイルディスクリプター(FD)の最大数に関するオペレーティングシステムの制限です。最新のUNIXディストリビューションでは、デフォルトの上限は1024です。
ごく小規模なNGINX環境を除き、ワーカーあたり512接続という上限では、おそらく不十分です。実際、NGINX Open SourceバイナリおよびNGINX Plusとともに配布しているデフォルトの「nginx.conf」ファイルでは、この上限を1024に引き上げています。
よくある設定ミスは、FDの上限をworker_connectionsの値の少なくとも2倍に引き上げていないことです。これを修正するには、メイン設定コンテキストでworker_rlimit_nofileディレクティブを使用して、その値を設定します。
より多くのFDが必要になる理由は次のとおりです。NGINXワーカープロセスからクライアントまたはアップストリームサーバーへの各接続で、FDが1つ消費されます。NGINXがWebサーバーとして動作する場合、クライアント接続に1つ、配信するファイルごとに1つのFDを使用するため、クライアントあたり少なくとも2つのFDが必要です(ただし、ほとんどのWebページは多数のファイルで構成されています)。プロキシサーバーとして動作する場合は、クライアントへの接続とアップストリームサーバーへの接続にそれぞれ1つのFDを使用し、さらにサーバーのレスポンスを一時的に保存するファイルに3つ目のFDを使用する可能性があります。キャッシュサーバーとしては、キャッシュ済みのレスポンスに対してはWebサーバーのように動作し、キャッシュが空または期限切れの場合はプロキシサーバーのように動作します。
NGINXは、ログファイルごとに1つのFDを使用するほか、マスタープロセスとの通信にも2つほどのFDを使用します。ただし通常、これらの数は、接続やファイルに使用されるFDの数と比べるとわずかです。
UNIXでは、プロセスごとのFD数を設定する方法がいくつか用意されています。
- シェルからNGINXを起動する場合は、
ulimitコマンド - NGINXをサービスとして起動する場合は、
initスクリプトまたはsystemdサービスマニフェストの変数 - The /etc/security/limits.confファイル
ただし、使用する方法はNGINXの起動方法によって異なります。一方、worker_rlimit_nofileはNGINXの起動方法にかかわらず機能します。
FDの数にはシステム全体の上限もあり、OSのsysctl fs.file-maxコマンドで設定できます。通常は十分に大きな値ですが、すべてのNGINXワーカープロセスが使用する可能性のあるファイルディスクリプタの最大数(worker_rlimit_nofile * worker_processes)がfs.file‑maxを大幅に下回っていることを確認することを推奨します。何らかの理由でNGINXが使用可能なFDをすべて使い切ると(DoS攻撃を受けた場合など)、問題を修正するためにマシンへログインすることさえできなくなります。
間違い2:error_log offディレクティブ
よくある誤解は、error_log offディレクティブを指定するとログ記録が無効になると考えることです。実際には、access_logディレクティブとは異なり、error_logにはoffパラメーターを指定できません。設定にerror_log offディレクティブを含めると、NGINXはNGINX設定ファイルのデフォルトディレクトリ(通常は/etc/nginx)に、offという名前のエラーログファイルを作成します。
エラーログは、NGINXに関する問題をデバッグする際の重要な情報源であるため、無効にすることは推奨しません。ただし、ストレージ容量が非常に限られており、ログデータによって使用可能なディスク領域を使い切る可能性がある場合は、エラーログを無効にすることが適切な場合もあります。メインの設定コンテキストに次のディレクティブを追加します。
error_log /dev/null emerg;このディレクティブは、NGINXが設定を読み込んで検証するまで適用されないことに注意してください。そのため、NGINXの起動時または設定の再読み込み時には、設定の検証が完了するまで、デフォルトのエラーログの保存先(通常は/var/log/nginx/error.log)にログが記録される場合があります。ログディレクトリを変更するには、-e <error_log_location>パラメーターをnginxコマンドに指定します。
間違い3:アップストリームサーバーへのキープアライブ接続を有効にしていない
デフォルトでは、NGINXは新しい受信リクエストごとにアップストリーム(バックエンド)サーバーへの新しい接続を確立します。この方法は安全ですが、接続の確立に3つ、切断に3つまたは4つのパケットをNGINXとサーバー間で交換する必要があるため、効率的ではありません。
トラフィック量が多い場合、リクエストごとに新しい接続を開くと、システムリソースを使い果たし、接続をまったく開けなくなる可能性があります。その理由は、接続ごとに送信元アドレス、送信元ポート、宛先アドレス、宛先ポートの4要素の組み合わせが一意でなければならないためです。NGINXからアップストリームサーバーへの接続では、このうち3つの要素(1番目、3番目、4番目)が固定されるため、変数となるのは送信元ポートだけです。接続が閉じられると、LinuxソケットはTIME‑WAIT状態に2分間とどまります。そのため、トラフィック量が多い場合は、使用可能な送信元ポートのプールを使い果たす可能性が高まります。この状態になると、NGINXはアップストリームサーバーへの新しい接続を開けなくなります。
この問題を解決するには、NGINXとアップストリームサーバー間でキープアライブ接続を有効にします。リクエストの完了時に接続を閉じるのではなく、接続を開いたままにして、後続のリクエストに再利用します。これにより、送信元ポートが枯渇する可能性を低減するとともに、パフォーマンスを向上させます。
キープアライブ接続を有効にするには:
- 各
keepaliveディレクティブをすべてのupstream{}ブロックに含め、各ワーカープロセスのキャッシュに保持するアップストリームサーバーへのアイドル状態のキープアライブ接続数を設定します。なお、keepaliveディレクティブは、NGINXワーカープロセスが開くことのできるアップストリームサーバーへの接続総数を制限するものではありません。これはよくある誤解です。そのため、keepaliveのパラメーターを想定するほど大きな値に設定する必要はありません。このパラメーターには、upstream{}ブロックに記載されているサーバー数の2倍を設定することを推奨します。この値であれば、NGINXがすべてのサーバーとのキープアライブ接続を維持するのに十分であり、同時にアップストリームサーバーが新しい着信接続も処理できる程度に抑えられます。また、upstream{}ブロックで、hash、ip_hash、least_conn、least_time、またはrandomディレクティブを使用して負荷分散アルゴリズムを指定する場合、そのディレクティブはkeepaliveディレクティブより前に記述する必要があります。これは、NGINX設定ではディレクティブの順序は問わないという一般原則に対する、数少ない例外の1つです。 - アップストリームグループにリクエストを転送する
location{}ブロックには、proxy_passディレクティブとともに、次のディレクティブを含めます。
proxy_http_version 1.1;
proxy_set_header "Connection" "";- デフォルトでは、NGINXはアップストリームサーバーへの接続にHTTP/1.0を使用するため、サーバーに転送するリクエストに
Connection:closeヘッダーを追加します。その結果、keepaliveディレクティブがupstream{}ブロックに存在していても、リクエストが完了するたびに各接続が閉じられます。proxy_http_versionディレクティブは、代わりにHTTP/1.1を使用するようNGINXに指示し、proxy_set_headerディレクティブはclose値をConnectionヘッダーから削除します。
間違い4:ディレクティブの継承の仕組みを忘れる
NGINXディレクティブは、下位方向、つまり「外側から内側へ」継承されます。すなわち、子コンテキスト(別のコンテキスト、つまり親コンテキスト内にネストされたコンテキスト)は、親レベルに含まれるディレクティブの設定を継承します。たとえば、server{}ブロックとlocation{}ブロックはすべて、http{}コンテキスト内にある場合、httpレベルに含まれるディレクティブの値を継承します。また、server{}ブロック内のディレクティブは、そのブロック内にあるすべての子location{}ブロックに継承されます。ただし、同じディレクティブが親コンテキストとその子コンテキストの両方に含まれている場合、値は加算されません。代わりに、子コンテキストの値が親の値を上書きします。
よくある間違いは、配列ディレクティブにこの「上書きルール」が適用されることを忘れてしまうことです。配列ディレクティブは、複数のコンテキストに記述できるだけでなく、同じコンテキスト内に複数回記述することもできます。たとえば、proxy_set_headerやadd_headerが該当します。特に後者は名前に「add」が含まれているため、上書きルールを忘れやすくなります。
継承の仕組みを、次のadd_headerの例で説明します。
http {
add_header X-HTTP-LEVEL-HEADER 1;
add_header X-ANOTHER-HTTP-LEVEL-HEADER 1;
server {
listen 8080;
location / {
return 200 "OK";
}
}
server {
listen 8081;
add_header X-SERVER-LEVEL-HEADER 1;
location / {
return 200 "OK";
}
location /test {
add_header X-LOCATION-LEVEL-HEADER 1;
return 200 "OK";
}
location /correct {
add_header X-HTTP-LEVEL-HEADER 1;
add_header X-ANOTHER-HTTP-LEVEL-HEADER 1;
add_header X-SERVER-LEVEL-HEADER 1;
add_header X-LOCATION-LEVEL-HEADER 1;
return 200 "OK";
}
}
}ポート8080でリッスンしているサーバーでは、add_headerディレクティブがserver{}ブロックにもlocation{}ブロックにもありません。そのため、継承は単純で、http{}コンテキストで定義された2つのヘッダーが適用されます。
% curl -i localhost:8080
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Mon, 21 Feb 2022 10:12:15 GMT
Content-Type: text/plain
Content-Length: 2
Connection: keep-alive
X-HTTP-LEVEL-HEADER: 1 X-ANOTHER-HTTP-LEVEL-HEADER: 1
OKポート8081でリッスンするサーバーでは、add_headerディレクティブがserver{}ブロックにはありますが、その子であるlocation /ブロックにはありません。server{}ブロックで定義されたヘッダーは、http{}コンテキストで定義された2つのヘッダーをオーバーライドします。
% curl -i localhost:8081
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Mon, 21 Feb 2022 10:12:20 GMT
Content-Type: text/plain
Content-Length: 2
Connection: keep-alive
X-SERVER-LEVEL-HEADER: 1
OK子のlocation /testブロックにはadd_headerディレクティブがあり、親のserver{}ブロックのヘッダーと、http{}コンテキストの2つのヘッダーの両方を上書きします。
% curl -i localhost:8081/test
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Mon, 21 Feb 2022 10:12:25 GMT
Content-Type: text/plain
Content-Length: 2
Connection: keep-alive
X-LOCATION-LEVEL-HEADER: 1
OKIf we want a location{}ブロックで、ローカルに定義されたヘッダーに加えて親コンテキストで定義されたヘッダーも保持するには、親ヘッダーをlocation{}ブロック内で再定義する必要があります。これは、location /correctブロックで行っています。
% curl -i localhost:8081/correct
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Mon, 21 Feb 2022 10:12:30 GMT
Content-Type: text/plain
Content-Length: 2
Connection: keep-alive
X-HTTP-LEVEL-HEADER: 1 X-ANOTHER-HTTP-LEVEL-HEADER: 1 X-SERVER-LEVEL-HEADER: 1 X-LOCATION-LEVEL-HEADER: 1
OK間違い5:proxy_buffering offディレクティブ
NGINXでは、プロキシバッファリングがデフォルトで有効になっています(proxy_bufferingディレクティブはonに設定されています)。プロキシバッファリングでは、サーバーから届くレスポンスをNGINXが内部バッファに保存し、レスポンス全体がバッファリングされるまでクライアントへのデータ送信を開始しません。バッファリングは、低速なクライアントに対するパフォーマンスの最適化に役立ちます。クライアントがレスポンス全体を取得するまでNGINXがレスポンスをバッファリングするため、プロキシ先サーバーは可能な限り迅速にレスポンスを返し、ほかのリクエストを処理できる状態に戻ることができます。
プロキシバッファリングを無効にすると、NGINXはサーバーからのレスポンスをクライアントに送信し始める前に、その先頭部分のみをバッファリングします。使用するバッファのデフォルトサイズは1メモリページ(オペレーティングシステムに応じて4 KBまたは8 KB)です。通常、これはレスポンスヘッダーを格納するのに十分な容量です。その後、NGINXはレスポンスを受信するたびにクライアントへ同期的に送信します。そのため、サーバーはNGINXが次のレスポンスセグメントを受け入れられるようになるまで、アイドル状態で待機することになります。
そのため、設定でproxy_bufferingがoffになっているケースが非常に多いことには驚かされます。クライアント側のレイテンシーを低減する意図があるのかもしれませんが、その効果はごくわずかな一方で、多くの弊害があります。プロキシバッファリングを無効にすると、設定していてもレート制限やキャッシュが機能せず、パフォーマンスが低下するなどの問題が生じます。
プロキシバッファリングの無効化が妥当となるユースケース(ロングポーリングなど)はごく限られているため、デフォルト設定の変更は強く推奨しません。詳細については、「NGINX Plus Admin Guide」を参照してください。
間違い6:ifディレクティブの不適切な使用
The ifディレクティブは、特にlocation{}ブロック内での使用が難しいものです。期待どおりに動作しないことが多く、セグメンテーション違反を引き起こす場合さえあります。実際、その扱いは非常に難しく、NGINX Wikiには「If is Evil」という記事があります。問題の詳細と回避方法については、そちらをご覧ください。
一般に、if{}ブロック内で常に安全に使用できるディレクティブは、returnとrewriteだけです。次の例では、ifを使用して、X‑Testヘッダーを含むリクエストを検出します(ただし、テストする条件は任意に指定できます)。NGINXは430 (Request Header Fields Too Large)エラーを返し、名前付きロケーション@error_430でこのエラーをインターセプトして、リクエストをbという名前のアップストリームグループにプロキシします。
location / {
error_page 430 = @error_430;
if ($http_x_test) {
return 430;
}
proxy_pass http://a;
}
location @error_430 {
proxy_pass b;
}この例をはじめ、ifの多くの用途では、このディレクティブ自体を使用せずに済むことがよくあります。次の例では、リクエストにX‑Testヘッダーが含まれている場合、map{}ブロックによって$upstream_name変数がbに設定され、リクエストはその名前のアップストリームグループにプロキシされます。
map $http_x_test $upstream_name {
default "b";
"" "a";
}
# ...
location / {
proxy_pass http://$upstream_name;
}間違い7:過剰なヘルスチェック
複数の仮想サーバーを構成し、同じアップストリームグループにリクエストをプロキシすることはよくあります(つまり、複数のproxy_passserver{}ブロックに同一のhealth_checkディレクティブを記述します)。この場合、すべてのserver{}ブロックにディレクティブを記述するのは誤りです。追加の情報は得られず、アップストリームサーバーの負荷が増えるだけです。
言うまでもないことですが、解決策は、各upstream{}ブロックにヘルスチェックを1つだけ定義することです。ここでは、bという名前のアップストリームグループに対するヘルスチェックを、適切なタイムアウトとヘッダー設定を含めて、特別な名前付きロケーションに定義します。
location / {
proxy_set_header Host $host;
proxy_set_header "Connection" "";
proxy_http_version 1.1;
proxy_pass http://b;
}
location @health_check {
health_check;
proxy_connect_timeout 2s;
proxy_read_timeout 3s;
proxy_set_header Host example.com;
proxy_pass http://b;
}複雑な構成では、この例のように、すべてのヘルスチェック用ロケーションをNGINX Plus APIおよびダッシュボードとともに1つの仮想サーバーにまとめることで、管理をさらに簡素化できます。
server {
listen 8080;
location / {
# …
}
location @health_check_b {
health_check;
proxy_connect_timeout 2s;
proxy_read_timeout 3s;
proxy_set_header Host example.com;
proxy_pass http://b;
}
location @health_check_c {
health_check;
proxy_connect_timeout 2s;
proxy_read_timeout 3s;
proxy_set_header Host api.example.com;
proxy_pass http://c;
}
location /api {
api write=on;
# directives limiting access to the API (see 'Mistake 8' below)
}
location = /dashboard.html {
root /usr/share/nginx/html;
}
}HTTP、TCP、UDP、gRPCサーバーのヘルスチェックの詳細については、「NGINX Plus Admin Guide」を参照してください。
間違い8:メトリクスへのアクセスが保護されていない
NGINXの動作に関する基本的なメトリクスは、Stub Statusモジュールから取得できます。NGINX Plusでは、NGINX Plus APIを使用して、さらに広範なメトリクスを収集することもできます。メトリクスの収集を有効にするには、stub_statusディレクティブまたはapiディレクティブを、それぞれserver{}ブロックまたはlocation{}ブロックに含めます。このブロックが、メトリクスを表示するためにアクセスするURLになります。(NGINX Plus APIでは、メトリクスを収集するNGINXエンティティ(仮想サーバー、アップストリームグループ、キャッシュなど)の共有メモリゾーンも設定する必要があります。手順については、NGINX Plus Admin Guideを参照してください。)
一部のメトリクスには、WebサイトやNGINXがプロキシするアプリへの攻撃に悪用される可能性がある機密情報が含まれています。ユーザー設定で時折見られる誤りは、該当するURLへのアクセスを制限していないことです。ここでは、メトリクスを保護する方法をいくつか紹介します。最初の例では、stub_statusを使用します。
以下の設定では、インターネット上の誰もが次のURLでメトリクスにアクセスできます。http://example.com/basic_status.
server {
listen 80;
server_name example.com;
location = /basic_status {
stub_status;
}
}HTTP Basic認証でメトリクスを保護
メトリクスをパスワードで保護するには、HTTP Basic Authenticationを使用し、auth_basicディレクティブとauth_basic_user_fileディレクティブを指定します。このファイル(ここでは「.htpasswd」)には、ログインしてメトリクスを表示できるクライアントのユーザー名とパスワードを記載します。
server {
listen 80;
server_name example.com;
location = /basic_status {
auth_basic “closed site”;
auth_basic_user_file conf.d/.htpasswd;
stub_status;
}
}メトリクスをallowおよびdenyディレクティブで保護
承認済みユーザーにログインを求めず、メトリクスへのアクセス元となるIPアドレスがわかっている場合は、別の方法としてallowディレクティブを使用できます。個別のIPv4アドレス、IPv6アドレス、およびCIDR範囲を指定できます。deny allディレクティブを使用すると、それ以外のアドレスからのアクセスを防止できます。
server {
listen 80;
server_name example.com;
location = /basic_status {
allow 192.168.1.0/24;
allow 10.1.1.0/16;
allow 2001:0db8::/32;
allow 96.1.2.23/32;
deny all;
stub_status;
}
}2つの方法を組み合わせる
両方の方法を組み合わせる場合はどうすればよいでしょうか。特定のアドレスから接続するクライアントにはパスワードなしでメトリクスへのアクセスを許可し、それ以外のアドレスから接続するクライアントには引き続きログインを要求できます。そのためには、satisfy anyディレクティブを使用します。このディレクティブにより、HTTP Basic認証の資格情報でログインするか、事前承認済みのIPアドレスを使用するクライアントに対して、NGINXがアクセスを許可します。セキュリティをさらに強化するには、satisfyをallに設定し、特定のアドレスから接続する場合でもログインを必須にできます。
server {
listen 80;
server_name monitor.example.com;
location = /basic_status {
satisfy any;
auth_basic “closed site”;
auth_basic_user_file conf.d/.htpasswd;
allow 192.168.1.0/24;
allow 10.1.1.0/16;
allow 2001:0db8::/32;
allow 96.1.2.23/32;
deny all;
stub_status;
}
}NGINX Plusでは、NGINX Plus APIエンドポイント(次の例ではhttp://monitor.example.com:8080/api/)と、http://monitor.example.com/dashboard.htmlのライブアクティビティ監視ダッシュボードへのアクセスを、同じ手法で制限します。
この設定では、96.1.2.23/32ネットワークまたはlocalhostから接続するクライアントに限り、パスワードなしでのアクセスを許可します。ディレクティブはserver{}レベルで定義されているため、APIとダッシュボードの両方に同じ制限が適用されます。なお、write=onパラメーターをapiに指定すると、これらのクライアントはAPIを使用して設定を変更することもできます。
APIとダッシュボードの設定について詳しくは、「NGINX Plus Admin Guide」を参照してください。
server {
listen 8080;
server_name monitor.example.com;
satisfy any;
auth_basic “closed site”;
auth_basic_user_file conf.d/.htpasswd;
allow 127.0.0.1/32;
allow 96.1.2.23/32;
deny all;
location = /api/ {
api write=on;
}
location = /dashboard.html {
root /usr/share/nginx/html;
}
}間違い9:すべてのトラフィックが同じ/24 CIDRブロックから送信される場合にip_hashを使用する
The ip_hashアルゴリズムは、クライアントIPアドレスのハッシュに基づいて、upstream{}ブロック内のサーバー間でトラフィックを負荷分散します。ハッシュキーには、IPv4アドレスの先頭3オクテットまたはIPv6アドレス全体が使用されます。この方式ではセッション永続性が確立されるため、サーバーが利用できない場合を除き、クライアントからのリクエストは常に同じサーバーに転送されます。
高可用性を確保するよう構成された仮想プライベートネットワークに、リバースプロキシとしてNGINXを導入したとします。NGINXの前段には、各種ファイアウォール、ルーター、レイヤー4ロードバランサー、ゲートウェイを配置します。これらは、社内ネットワーク、パートナーネットワーク、インターネットなど、さまざまな送信元からのトラフィックを受け入れてNGINXに転送し、NGINXがアップストリームサーバーへのリバースプロキシ処理を行えるようにします。初期のNGINX構成は次のとおりです。
http {
upstream {
ip_hash;
server 10.10.20.105:8080;
server 10.10.20.106:8080;
server 10.10.20.108:8080;
}
server {# …}
}しかし、問題があることがわかりました。すべての「インターセプト」デバイスが同じ10.10.0.0/24ネットワーク上にあるため、NGINXからは、すべてのトラフィックがそのCIDR範囲内のアドレスから送信されているように見えます。なお、ip_hashアルゴリズムはIPv4アドレスの先頭3オクテットをハッシュ化します。このデプロイでは、すべてのクライアントで先頭3オクテット(10.10.0)が同じであるため、ハッシュもすべて同じになり、トラフィックを異なるサーバーに分散する基準がありません。
この問題を解決するには、代わりにhashアルゴリズムを使用し、$binary_remote_addr変数をハッシュキーに指定します。この変数はクライアントの完全なアドレスを取得し、IPv4アドレスの場合は4バイト、IPv6アドレスの場合は16バイトのバイナリ表現に変換します。これにより、介在するデバイスごとに異なるハッシュが生成され、想定どおりに負荷分散が機能します。
また、デフォルトの方式ではなくconsistentパラメーターを指定して、ketamaハッシュ方式を使用します。これにより、サーバー構成が変更された際に別のアップストリームサーバーへ再マッピングされるキーの数が大幅に減り、キャッシュサーバーのキャッシュヒット率が向上します。
http {
upstream {
hash $binary_remote_addr consistent;
server 10.10.20.105:8080;
server 10.10.20.106:8080;
server 10.10.20.108:8080;
}
server {# …}
}間違い10:アップストリームグループを活用していない
最もシンプルなユースケースの1つとして、ポート3000でリクエストを待ち受ける単一のNodeJSベースのバックエンドアプリケーションに対し、NGINXをリバースプロキシとして使用しているとします。一般的な設定は次のようになります。
http {
server {
listen 80;
server_name example.com;
location / {
proxy_set_header Host $host;
proxy_pass http://localhost:3000/;
}
}
}簡単ですね。proxy_passディレクティブは、クライアントからのリクエストの送信先をNGINXに指示します。NGINXは、ホスト名をIPv4またはIPv6アドレスに解決するだけです。接続が確立されると、NGINXはそのサーバーにリクエストを転送します。
ここで誤りとなるのは、サーバーが1台しかなく、したがって負荷分散を設定する必要もないため、upstream{}ブロックを作成しても意味がないと考えることです。実際には、upstream{}ブロックを使用すると、次の設定例に示すように、パフォーマンスを向上させる複数の機能を利用できます。
http {
upstream node_backend {
zone upstreams 64K;
server 127.0.0.1:3000 max_fails=1 fail_timeout=2s;
keepalive 2;
}
server {
listen 80;
server_name example.com;
location / {
proxy_set_header Host $host;
proxy_pass http://node_backend/;
proxy_next_upstream error timeout http_500;
}
}
}The zoneディレクティブは、ホスト上のすべてのNGINXワーカープロセスがアップストリームサーバーの構成情報と状態情報にアクセスできる共有メモリゾーンを確立します。複数のアップストリームグループでこのゾーンを共有できます。NGINX Plusでは、このゾーンにより、NGINXを再起動せずに、NGINX Plus APIを使用してアップストリームグループ内のサーバーや個々のサーバーの設定を変更することもできます。詳細については、「NGINX Plus管理ガイド」を参照してください。
The serverディレクティブには、サーバーの動作を調整するためのパラメーターが複数あります。この例では、NGINXがサーバーを異常と判断し、リクエストを受け付ける対象から除外する条件を変更しています。ここでは、デフォルトの10秒間に1回ではなく、2秒間に通信試行が1回でも失敗すると、サーバーを異常と判断します。
この設定をproxy_next_upstreamディレクティブと組み合わせて、NGINXが通信試行の失敗と見なす条件を構成します。この条件に該当すると、NGINXはリクエストをアップストリームグループ内の次のサーバーに渡します。デフォルトのエラー条件とタイムアウト条件にhttp_500を追加し、アップストリームサーバーから返されるHTTP 500 (Internal Server Error)コードを通信試行の失敗と見なすようにします。
The keepaliveディレクティブでは、各ワーカープロセスのキャッシュに保持する、アップストリームサーバーへのアイドル状態のキープアライブ接続数を設定します。その利点については、「間違い3:アップストリームサーバーへのキープアライブ接続を有効にしていない」ですでに説明しました。
NGINX Plusでは、アップストリームグループに追加機能を設定できます。
- 前述のとおり、NGINX Open Sourceがサーバーのホスト名をIPアドレスに解決するのは、起動時の1回のみです。serverディレクティブの
resolveパラメーターを使用すると、NGINX Plusはアップストリームサーバーのドメイン名に対応するIPアドレスの変更を監視し、再起動せずにアップストリーム設定を自動的に変更できます。また、serviceパラメーターを使用すると、NGINX Plusはポート番号、重み、優先度の情報を含むDNSSRVレコードも利用できます。これは、サービスのポート番号が動的に割り当てられることの多いマイクロサービス環境では不可欠です。サーバーアドレスの名前解決について詳しくは、F5ブログの「NGINXおよびNGINX PlusでDNSを使用したサービスディスカバリ」をご覧ください。 - serverディレクティブの
slow_startパラメーターを使用すると、NGINX Plusは、正常でリクエストを受け付けられる状態になったと新たに判断されたサーバーに送信するリクエスト量を徐々に増やすことができます。これにより、リクエストが突然集中してサーバーが過負荷となり、再び障害が発生するのを防ぎます。 - The
queueディレクティブを使用すると、リクエストを処理するアップストリームサーバーを選択できない場合に、クライアントへ即座にエラーを返す代わりに、NGINX Plusでリクエストをキューに格納できます。
リソース
- NGINX PlusおよびNGINXの設定ファイルの作成(NGINX Plus管理ガイド)
- Gixy(GitHubで公開されているNGINX構成アナライザー)
- NGINX Amplify(Analyzerツールを含む)
NGINX Plusをお試しいただくには、今すぐ30日間の無料トライアルを開始するか、ユースケースについてご相談ください。
著者について

関連するブログ記事
チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する
OpenTelemetryを使用してNGINXサーバーの状態と健全性をより明確に把握することで、問題のトラブルシューティングを行い、Webアプリケーションのパフォーマンスを向上できます。
AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正
Akita SoftwareのAPIオブザーバビリティ向け新しいNGINX Plus Certified Moduleを活用して、APIエンドポイントの問題をより迅速に特定し、修正できます。
JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法
Red HatのシニアプリンシパルデベロッパーアドボケイトであるDaniel Oh氏が、Javaプロジェクトをゼロから構築するためのひな形を作成し、Kubernetesネイティブアプリケーションとしてビルドする方法を解説します。
F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング
NGINXaaS for Azureは、NGINX PlusをAzureネイティブのSaaSとして利用できるサービスです。NGINXの設定を容易にリフト&シフトできるため、クラウド導入とモダンアプリの展開を加速できます。

SELinuxでNGINXおよびNGINX Plusを使用する
Red Hat Enterprise Linux(RHEL)および関連ディストリビューションでSecurity-Enhanced Linux(SELinux)を有効にすると、デフォルト設定によりNGINXとNGINX Plusの一部の操作が制限されます。この記事では、すべての機能を利用できるようにSELinuxの設定を変更する方法について説明します。
NGINX PlusによるAWS Auto Scalingグループの負荷分散
新しいnginx-asg-sync統合ソフトウェアにより、NGINX PlusはAWS Auto Scalingグループの負荷を直接分散できるため、クラウドでの負荷分散がさらに柔軟になります