Nginx設定テスト:主要コマンドでスムーズなデプロイを実現

nginx -t、nginx -T、安全なリロードの習慣を使って、トラフィックに影響が出る前にNginx設定エラーをキャッチしましょう。

Nginx設定テスト:主要コマンドでスムーズなデプロイを実現

Nginxの設定テストは、壊れたリロードからあなたを救うまでは小さすぎて気にしない習慣の一つです。セミコロンの欠落、間違ったインクルードパス、または持っていないモジュールのディレクティブは、Nginxが新しい設定を受け入れるのを妨げる可能性があります。本番のリバースプロキシでは、それは小さなミスではありません。

基本コマンドはシンプルです:

sudo nginx -t

リロードの前に毎回実行してください。サーバーブロックを編集した後にも実行してください。チームがNginx設定をGitで管理している場合はCIでも実行してください。このコマンドは設定を解析し、構文が有効かどうかを報告します。ルーティングロジックが正しいこと、TLS証明書がすべてのホスト名に対して有効であること、アップストリームアプリが正常であることを証明するわけではありません。設定を適用する前にNginxが検出できる種類のミスをキャッチします。

nginx -tがチェックするもの

nginx -tはNginxに設定をテストするよう指示します。メインの設定ファイルを読み込み、includeディレクティブに従い、ディレクティブとブロックを解析し、多くのファイル/パスの問題をチェックします。成功した実行は通常次のようになります:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

失敗した実行はファイルと行番号を指し示します:

nginx: [emerg] unexpected "}" in /etc/nginx/conf.d/api.conf:18
nginx: configuration file /etc/nginx/nginx.conf test failed

行番号はパーサーが問題に気づいた場所であり、必ずしもミスを犯した場所ではありません。Nginxが18行目に予期しない}があると言った場合、その上の行でセミコロンの欠落や閉じられていないブロックがないか確認してください。

設定ファイル、証明書ファイル、またはインクルードされたスニペットがrootのみ読み取り可能な場合はsudoを使用してください:

sudo nginx -t

適切な権限がないと、構文が正しくてもテストが失敗する可能性があります。

インクルードで設定が見づらい場合はnginx -Tを使用

多くのNginxセットアップでは、設定を/etc/nginx/nginx.confconf.d/*.confsites-enabled/*、および共有スニペットに分割しています。これは保守性には良いですが、デバッグを混乱させる可能性があります。

nginx -Tは設定をテストし、解析された完全な設定を標準出力に出力します:

sudo nginx -T

これは次のような質問に答える必要がある場合に便利です:

  • このサーバーブロックを実際に定義しているファイルはどれか?
  • includeパターンがバックアップファイルを拾っていないか?
  • このディレクティブはhttpserverlocationのどのスコープで設定されているか?
  • どの重複したserver_nameブロックが優先されているか?

nginx -Tの出力を共有する際は注意してください。証明書のパス、内部ホスト名、アップストリーム名、ヘッダー、または機密情報を含むコメントが含まれる可能性があります。チケットに貼る場合は、事前に編集してください。

-cでデフォルト以外の設定ファイルをテスト

ステージングパスで設定を構築している場合は、-cを使用してください:

sudo nginx -t -c /home/deploy/nginx-staging/nginx.conf

これにより、Nginxにテストするメイン設定ファイルを指定します。その設定内の相対パスは、プレフィックス設定によって異なる動作をする可能性があるため、可能な限りステージングテストを本番のレイアウトに近づけてください。

また、コンパイル時のパスとモジュールを次のコマンドで確認できます:

nginx -V

出力は多くのシステムで標準エラー出力に送られるため、出力をリダイレクトする際に驚くことがあります。Nginxのバージョンとビルドオプション(モジュールサポートやデフォルトパスを含む)が表示されます。これは、http_v2realipstub_status、ストリームプロキシなどのモジュールのディレクティブを設定が使用する場合に重要です。

気軽に再起動せず、リロードする

テストが成功したら、Nginxをリロードします:

sudo systemctl reload nginx

リロードはマスタープロセスに新しい設定を読み込ませ、古いワーカーが既存のリクエストを処理している間に新しいワーカーを起動するよう指示します。これが設定変更の通常のパスです。

再起動はサービスを停止して開始します:

sudo systemctl restart nginx

再起動は実際に必要な場合にのみ使用してください。例えば、パッケージの変更後やサービスの状態に問題がある場合などです。通常の設定編集では、リロードの方が影響が少ないです。

一部のsystemdユニットファイルは、リロードの一部として設定テストを実行します。それを唯一の安全策として依存しないでください。自分でnginx -tを実行して、実行中のサービスに触れる前に失敗を確認してください。

ネイティブのNginxシグナルコマンドも一般的です:

sudo nginx -s reload

systemdで管理されているサーバーでは、サービス状態とログを同じ管理レイヤーに保つため、通常はsystemctl reload nginxを好みます。

安全な編集ワークフロー

通常のサーバーブロック変更には、次のリズムを使用してください:

sudo cp /etc/nginx/conf.d/api.conf /etc/nginx/conf.d/api.conf.bak.$(date +%Y%m%d%H%M%S)
sudoedit /etc/nginx/conf.d/api.conf
sudo nginx -t
sudo systemctl reload nginx
sudo systemctl status nginx --no-pager

設定がGitにある場合は、ランダムなバックアップファイルを永久に保持する代わりに、変更をコミットしてください。上記のバックアップコマンドは、小さな管理されていないサーバーには便利ですが、バージョン管理の代わりにはなりません。

リロード後、実際のルートをテストしてください:

curl -I https://example.com/api/health
curl -I -H 'Host: example.com' http://127.0.0.1/

nginx -tは設定が解析されることを教えてくれます。curlはサイトが意図した通りに動作しているかどうかを教えてくれます。

一般的な失敗メッセージとその意味

セミコロンの欠落はよく次のように表示されます:

nginx: [emerg] invalid number of arguments in "proxy_set_header" directive in /etc/nginx/conf.d/app.conf:22

その行とその前の行のディレクティブを確認してください。Nginxのディレクティブは通常;で終わり、ブロックは{ ... }で終わります。

間違ったインクルードパスは次のように表示されます:

nginx: [emerg] open() "/etc/nginx/snippets/security-headers.conf" failed (2: No such file or directory)

ファイルパスが間違っているか、スニペットがデプロイされていないか、インクルードパターンが環境固有である可能性があります。

権限の問題は次のように表示されることがあります:

nginx: [emerg] cannot load certificate "/etc/letsencrypt/live/example.com/fullchain.pem": BIO_new_file() failed

ファイルがないか、シンボリックリンクが壊れているか、テストを実行しているユーザーが読み取れない可能性があります。証明書の更新とデプロイスクリプトは、これが発生する一般的な場所です。

不明なディレクティブは、タイポ、間違ったコンテキスト、またはモジュールの欠落の3つのうちの1つを意味します。

nginx: [emerg] unknown directive "proxy_cache_purge"

ディレクティブ名が間違っている可能性があります。別のモジュールに属している可能性があります。本番のNginxビルドに、ステージングにあったサードパーティモジュールが含まれていない可能性があります。設定が移植可能であると仮定する前に、nginx -Vを確認してください。

重複または競合するサーバー名は、ハードな失敗ではなく警告として表示されることがあります:

nginx: [warn] conflicting server name "example.com" on 0.0.0.0:80, ignored

最終行でテストが成功したと言っているからといって、警告を無視しないでください。警告は、Nginxがあなたが思っているサーバーブロックを使用しないことを意味する場合があります。

CIでのテスト

Nginx設定がリポジトリにある場合は、デプロイ前にテストしてください。シンプルなコンテナベースのチェックで、設定をNginxイメージにマウントして実行できます:

nginx -t -c /etc/nginx/nginx.conf

難しいのは本番のパスと一致させることです。設定が/etc/letsencryptを参照している場合、ローカルテストにはプレースホルダーファイルまたはテスト固有の設定が必要です。アップストリームのホスト名を参照している場合、構文テストではアップストリームが生きている必要はありませんが、インクルードされたファイルと証明書ファイルは存在する必要があります。

多くのサイトを持つチームの場合、デプロイ前のステップとしてnginx -Tを実行し、サニタイズされた出力をアーティファクトとして保存するステップを追加してください。リロードが異常に動作した場合、最後の正常なデプロイのレンダリングされた設定と現在の設定を比較できます。

設定テストでキャッチできないもの

nginx -tは、新しいlocationブロックが別の正規表現ロケーションによって隠されていることを教えてくれません。アップストリームアプリが500を返すことを知りません。リダイレクトチェーンが妥当であることや、キャッシュルールが安全であることを証明しません。

そのためには、動作チェックを追加してください:

curl -I https://example.com/
curl -I https://example.com/old-path
curl -sS https://example.com/api/health

TLS変更の場合は、クライアントの観点から証明書を確認してください:

openssl s_client -connect example.com:443 -servername example.com </dev/null

リバースプロキシ変更の場合は、リロード中およびリロード後にログを監視してください:

sudo tail -f /var/log/nginx/error.log /var/log/nginx/access.log

Nginx設定テストは完全なデプロイ戦略ではありませんが、すべての戦略に含めるべきゲートです。構文にはnginx -t、レンダリング設定のデバッグにはnginx -T、ビルド詳細にはnginx -V、通常の変更にはsystemctl reload nginxを使用してください。その後、実際のリクエストで動作を確認してください。