Nginxの一般的なエラーのトラブルシューティング:実践ガイド

Nginxのエラーに遭遇しましたか?この実践ガイドでは、一般的な問題を診断し解決する方法を紹介します。設定の問題、許可拒否エラー、接続拒否、502/504ゲートウェイエラーなどに対処する方法を学びます。明確な説明、実行可能な解決策、そしてサイトをアクセス可能でスムーズに動作させ続けるための必須のNginxコマンドを提供します。

Nginxの一般的なエラーのトラブルシューティング:実践ガイド

Nginxの一般的なエラーのトラブルシューティングは、ステータスコードを問題全体として扱うのをやめると、はるかに簡単になります。502は、アプリのクラッシュ、間違ったソケットパス、または壊れたヘッダーを返すバックエンドが原因かもしれません。403は、ファイルのパーミッション、インデックスファイルの欠落、または予想以上にマッチした拒否ルールが原因かもしれません。

証拠から始めましょう:エラーログ、アクセスログ、nginx -t、そしてNginxがアプリにプロキシしている場合はバックエンドログです。ブラウザのページだけから推測するのは時間の無駄です。

まずはクイックチェックから

設定を変更する前に、これらを実行してください:

sudo nginx -t
sudo systemctl status nginx --no-pager
sudo tail -n 80 /var/log/nginx/error.log
sudo tail -n 80 /var/log/nginx/access.log

nginx -tは設定が解析可能かどうかを教えてくれます。サービスステータスはNginxが実行中かどうかを教えてくれます。ログは、リクエストの処理中にNginxが何を見たかを教えてくれます。

問題が1つのURLに限定されている場合は、curlで再現してヘッダーとステータスを明確に確認します:

curl -I https://example.com/problem/path
curl -v https://example.com/problem/path

問題が特定のホスト名でのみ発生する場合は、それを含めます:

curl -I -H 'Host: app.example.com' http://127.0.0.1/

これにより、NginxのルーティングをDNS、CDN、ロードバランサーの動作から分離できます。

Nginxが起動しない、またはリロードできない

起動失敗は通常、構文エラー、間違ったコンテキストでの重複ディレクティブ、インクルードファイルの欠落、または証明書パスの問題が原因です。

以下を使用します:

sudo nginx -t
sudo journalctl -u nginx -n 100 --no-pager

一般的なメッセージは直接的です:

  • unknown directiveは、タイプミス、サポートされていないモジュール、または間違ったNginxビルドに配置されたディレクティブを意味します。
  • directive is not allowed hereは、ディレクティブが間違ったコンテキストにあることを意味します。例えば、http専用のディレクティブをserver内部に配置するなどです。
  • cannot load certificateは、パスが間違っている、ファイルがない、またはパーミッションがNginxによる読み取りをブロックしていることを意味します。
  • bind() to 0.0.0.0:80 failedは、多くの場合、別のプロセスが既にそのポートを使用していることを意味します。

ポートを確認するには:

sudo ss -tulnp | grep ':80\|:443'

nginx -tが成功するまでリロードしないでください。リロードに失敗しても通常は古いワーカープロセスは実行されたままですが、再起動に失敗するとサイトがダウンする可能性があります。

(13: Permission denied)403 Forbidden

Permission deniedは、Nginxワーカーユーザーがファイルを読み取ったりディレクトリをトラバースしたりできない場合にエラーログに表示されます。ブラウザには403 Forbiddenと表示されることがあります。

まずワーカーユーザーを見つけます:

grep -R '^user ' /etc/nginx/nginx.conf

DebianとUbuntuでは、多くの場合www-dataです。RHEL互換システムでは、多くの場合nginxです。

/var/www/htmlのような静的ルートの場合、Nginxはすべての親ディレクトリに対する実行権限とファイルに対する読み取り権限を必要とします:

sudo find /var/www/html -type d -exec chmod 755 {} \;
sudo find /var/www/html -type f -exec chmod 644 {} \;

反射的にアプリケーションディレクトリに対してchown -R www-data:www-dataを実行しないでください。エラーは消えるかもしれませんが、Webサーバーに不要な書き込みアクセス権を与えることになります。より安全なパターンは、デプロイの所有権を分離し、Nginxに読み取りアクセス権のみを付与することです。

パーミッションが問題ないように見える場合は、リクエストがインデックスファイルのないディレクトリに対するものかどうかを確認します:

location / {
    root /var/www/html;
    index index.html index.htm;
}

/docs/index.htmlがなく、autoindexがオフの場合、Nginxは403を返します。これは正しい動作です。

SELinuxも、RHEL系システムでパーミッション関連の障害を引き起こす可能性があります。ファイルのパーミッションが正しいのにNginxが読み取りやプロキシをできない場合は、SELinuxを無効にする前に監査ログを確認します:

sudo ausearch -m avc -ts recent

(111: Connection refused)502 Bad Gateway

Connection refusedは、Nginxがアップストリームに接続しようとしたが、ターゲットが積極的に拒否したことを意味します。アプリがダウンしている、別のアドレスでリッスンしている、または存在しないソケットパスを使用している可能性があります。

このプロキシの場合:

location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

確認します:

sudo ss -tulnp | grep 3000
curl -I http://127.0.0.1:3000
sudo systemctl status your-app --no-pager

NginxがUnixソケットを使用している場合は、ソケットファイルを確認します:

ls -l /run/gunicorn/app.sock

ワーカーユーザーはソケットの読み取りと書き込みができる必要があります。

502 Bad Gatewayはより広範囲です。Nginxはアップストリームに何かに到達しましたが、応答が無効、不完全、早期に閉じられた、またはNginxが期待したものではありませんでした。Nginxエラーと同じタイムスタンプでアプリのログを確認します。そのタイムスタンプの一致が重要です。そうしないと、昨日の例外を追いかけることになります。

PHP-FPMの場合は、fastcgi_passが設定されたプールソケットまたはポートと一致していることを確認します。例えば:

fastcgi_pass unix:/run/php/php8.3-fpm.sock;

次に確認します:

sudo systemctl status php8.3-fpm --no-pager
ls -l /run/php/php8.3-fpm.sock

504 Gateway Timeout

504は、Nginxがアップストリームを待機し、タイムリーな応答が得られなかったことを意味します。レポート、インポート、または遅い管理操作に対してタイムアウトを増やすことは有効ですが、すべてのリクエストで遅いパブリックエンドポイントに対する唯一の修正策であってはなりません。

location /api/reports/ {
    proxy_pass http://127.0.0.1:3000;
    proxy_connect_timeout 10s;
    proxy_send_timeout 60s;
    proxy_read_timeout 180s;
}

次に、バックエンドのタイミングを確認します。アクセスログにアップストリームのタイミングを追加します(まだない場合):

log_format proxy_timing '$remote_addr "$request" $status '
                        'request_time=$request_time '
                        'upstream_time=$upstream_response_time';

$upstream_response_timeが高い場合、アプリまたはデータベースに焦点を当てるべきでしょう。Nginxがタイムアウトを示しているが、アプリのログは迅速に応答したと示している場合は、ネットワークホップ、コンテナネットワーキング、ホスト内のDNS解決、またはNginxとアプリの間のロードバランサーを確認します。

413 Request Entity Too Large

413は通常、単純です:リクエストボディがNginxの許可するサイズより大きいです。アップロード、大きなJSONペイロード、フォーム投稿がトリガーとなる可能性があります。

client_max_body_sizeを最も狭い有用な場所に設定します:

server {
    server_name example.com;

    location /upload/ {
        client_max_body_size 100M;
        proxy_pass http://127.0.0.1:3000;
    }
}

巨大なグローバル制限を設定することはほとんど良い考えではありません。ほとんどのルートはそれを必要とせず、許可されるボディが大きくなると、悪意のあるクライアントがスタックに強制できる作業量が増加します。

SSLと証明書エラー

TLS障害は、どこで気付くかによって異なって見えることがよくあります。Nginxがリロードに失敗する、ブラウザが証明書について警告する、またはクライアントがハンドシェイクに失敗する可能性があります。

証明書の日付を確認します:

openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -noout -dates -subject -issuer

公開サービスが提示するものを確認します:

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -dates -subject -issuer

これら2つのコマンドが異なる証明書を示す場合、ロードバランサー、CDN、または別のホストがトラフィックを処理している可能性があります。

400 Bad Request とヘッダーの問題

400は通常、Nginxがリクエスト構文を受け入れなかったことを意味します。実際のブラウザではあまり一般的ではありませんが、ボット、古いクライアント、異常なプロキシ、または特大のヘッダーが原因となる可能性があります。

client sent too large request headerのようなメッセージを探します。正当なSSOまたはアプリケーションCookieが大きすぎる場合は、ヘッダーバッファ設定を調整する必要があるかもしれません。それを最初の対応ではなく、対象を絞った修正として扱います。特大のCookieは、多くの場合アプリケーションで修正する方が良いです。

実践的な操作順序

Nginxの問題が発生している場合、再現可能な順序を使用します:

  1. 正確なURL、ホスト、ステータスコード、時間を確認します。
  2. nginx -tとサービスのステータスを確認します。
  3. アクセスログでリクエストを照合します。
  4. エラーログで同じタイムスタンプを照合します。
  5. プロキシしている場合は、アップストリームサービスのステータスとログを確認します。
  6. Nginxホストからアップストリームを直接テストします。
  7. 証拠に適合する最小の設定変更を行います。
  8. nginx -tを実行し、リロードし、再テスト中にログを監視します。

ほとんどのNginxの問題は、障害がどこで発生したかがわかれば普通のことになります:Nginxの前、Nginx内部、Nginxとアップストリームの間、またはアップストリームサービス内部です。