Nginx 502 Bad Gateway エラーの診断と解決方法

Nginx 502 エラーを修正するには、エラーログ、アップストリームの健全性、ソケットのパーミッション、プロキシ設定、タイムアウト、ファイアウォールを確認します。

Nginx 502 Bad Gateway エラーの診断と解決方法

Nginx は強力で人気のある Web サーバー兼リバースプロキシであり、静的コンテンツの配信、トラフィックの負荷分散、PHP-FPM、Node.js、Python Gunicorn、Apache Tomcat などのさまざまなアップストリームアプリケーションサーバーへのリクエスト転送によく使用されます。Nginx がこれらのアップストリームサーバーのいずれかとの通信で問題に遭遇すると、通常は「502 Bad Gateway」エラーで応答します。

まず Nginx エラーログを確認し、次にアップストリームプロセスが実行中で、到達可能であり、応答を許可されていることを確認します。

Nginx 502 Bad Gateway エラーについて

502 Bad Gateway エラーは、リバースプロキシとして機能する Nginx がアップストリームサーバーから無効な応答を受信したことを示します。これは、Nginx がアップストリームサーバーへの接続に成功したものの、応答がない、不完全な応答、または理解できない応答を受信したことを意味します。重要なのは、問題は Nginx 自体ではなく、Nginx が通信しようとしているサービスにあることです。

一般的なアップストリームサーバーは次のとおりです。

  • PHP-FPM: PHP アプリケーション(例:WordPress、Laravel)用。
  • Gunicorn/uWSGI: Python アプリケーション(例:Django、Flask)用。
  • Node.js: JavaScript アプリケーション用。
  • Apache Tomcat: Java アプリケーション用。
  • その他の Web サーバー: 特定のコンテンツを提供する Apache HTTP Server など。

502 エラーは、アプリケーションのバックエンドが正しく機能していないか、Nginx からアクセスできないことを示す重要な指標です。

段階的な診断

502 エラーを解決する鍵は、体系的な診断です。最も可能性の高い原因から始めて、徐々に調査を進めます。

1. 最初に Nginx エラーログを確認する

Nginx エラーログは主要な情報源です。多くの場合、Nginx がアップストリームサーバーと通信できなかった理由に関する具体的な詳細が含まれています。

  • 場所: 通常は /var/log/nginx/error.log にあります。
  • コマンド: tail -f を使用して、エラーを再現しようとしながらリアルタイムでログを監視します。
tail -f /var/log/nginx/error.log

確認すべき点:

  • connect() failed (111: Connection refused): アップストリームサーバーが指定されたアドレス/ポートでリッスンしていないか、ファイアウォールが接続をブロックしていることを示します。
  • upstream timed out: アップストリームサーバーの応答に時間がかかりすぎています。
  • upstream prematurely closed connection: アップストリームサーバーが完全な応答を送信する前に接続を閉じました。
  • no live upstreams while connecting to upstream: Nginx が設定された利用可能なアップストリームサーバーを見つけられませんでした。

2. アップストリームサーバーのステータスを確認する

Nginx エラーログから手がかりを得たら、アップストリームアプリケーションサーバーのステータスを確認します。

  • PHP-FPM の場合:

    sudo systemctl status php8.2-fpm
    
  • Node.js/Python/その他のカスタムアプリの場合: プロセスが実行中かどうかを確認します。

    ps aux | grep node
    ps aux | grep gunicorn
    

    PM2(Node.js)や Supervisor(汎用)などのプロセスマネージャーを使用している場合は、そのステータスを確認します。

    pm2 status
    sudo supervisorctl status
    

サービスが実行されていない場合は、起動を試み、エラーがないか独自のログを確認します。

sudo systemctl start php8.2-fpm

3. アップストリームへのネットワーク接続を確認する

Nginx が設定されたポートまたはソケットパスでアップストリームサーバーに到達できることを確認します。

  • TCP/IP 接続の場合(例:127.0.0.1:8000: telnet または nc(netcat)を使用して、Nginx サーバーからポートの接続性をテストします。

    telnet 127.0.0.1 8000
    nc -vz 127.0.0.1 8000
    

    接続が成功すると、Connected to 127.0.0.1. または succeeded! と表示されます。ハングアップするか Connection refused と表示される場合、アップストリームサービスがリッスンしていないか、ファイアウォールがブロックしています。

  • Unix ソケットの場合(例:unix:/run/php/phpX.X-fpm.sock: ソケットファイルが存在し、正しいパーミッションを持っていることを確認します。

    ls -l /run/php/phpX.X-fpm.sock
    

    Nginx はこのソケットファイルに対する読み取り/書き込み権限を持っている必要があります。Nginx ユーザー(例:www-data)は、ソケットを所有するグループ(例:www-data または php-fpm)のメンバーである必要があります。

一般的な原因と解決策

診断手順に基づいて、502 エラーの最も頻繁な原因とその解決方法を以下に示します。

1. アップストリームサーバーが実行されていないかクラッシュした

原因: Nginx がプロキシしようとしているアプリケーション(例:PHP-FPM、Gunicorn、Node.js アプリ)が実行されていないか、クラッシュしています。

解決策: アップストリームサービスを起動または再起動します。

# PHP-FPM の例
sudo systemctl start php8.2-fpm
# すでに実行中でクラッシュが疑われる場合は、再起動します:
sudo systemctl restart php8.2-fpm

# カスタムアプリケーションの場合は、特定の起動/再起動コマンドを使用します

ヒント: アップストリームサービスがシステム起動時に自動的に起動するように設定されていることを確認します。systemd サービスの場合は、systemctl enable phpX.X-fpm を使用します。

2. アップストリームサーバーの過負荷 / リソース枯渇

原因: アップストリームサーバーが過負荷になり、メモリや CPU を使い果たしたり、プロセス制限に達したりして、応答を停止したり、新しい接続を拒否したりしています。

症状: Nginx エラーログに、特に負荷がかかっているときに断続的に connection refused または upstream timed out が表示される場合があります。システム監視ツール(tophtopfree -h)は、高いリソース使用率を示します。

解決策:

  • PHP-FPM の場合: 設定ファイル(例:/etc/php/X.X/fpm/pool.d/www.conf)で PHP-FPM プール設定を調整します。

    • pm.max_children: 同時に生存できる子プロセスの最大数。
    • pm.start_servers: 起動時に作成される子プロセスの数。
    • pm.min_spare_serverspm.max_spare_servers: 保持するアイドル状態の子プロセスの数を制御します。
    ; 動的プロセス管理の例
    pm = dynamic
    pm.max_children = 50
    pm.start_servers = 10
    pm.min_spare_servers = 5
    pm.max_spare_servers = 20
    
    • スクリプトがメモリを使い果たしている場合は、php.inimemory_limit を増やします。
  • その他のアプリケーションの場合: 可能であれば、ワーカープロセス、スレッドの数を増やすか、より多くのメモリを割り当てます。アプリケーションの特定のメトリクスを監視します。

  • Nginx タイムアウト: Nginx 設定で proxy_connect_timeoutproxy_send_timeoutproxy_read_timeout ディレクティブを増やしますが、バックエンドが実際に苦戦している場合、これは単にエラーを遅らせるだけであることを理解してください。

    http {
        ...
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
        ...
    }
    

3. Nginx のアップストリーム設定が正しくない

原因: Nginx がアップストリームサーバーに対して間違った IP アドレス、ポート、または Unix ソケットパスに接続するように設定されています。

症状: Nginx エラーログに、リクエストの直後に connect() failed (111: Connection refused) と表示されます。

解決策: Nginx サーバーブロック設定(/etc/nginx/sites-available/your_site.conf)を注意深く確認します。

  • HTTP/HTTPS アップストリームの場合:

    location /app {
        proxy_pass http://127.0.0.1:8000; # IP とポートが正しいことを確認
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    
  • Unix ソケット経由の PHP-FPM の場合:

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/phpX.X-fpm.sock; # このパスが PHP-FPM 設定と完全に一致することを確認
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    
  • TCP/IP 経由の PHP-FPM の場合:

    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000; # IP とポートを確認
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    

変更後は、必ず Nginx 設定をテストし、Nginx をリロード/再起動します:

nginx -t
systemctl reload nginx # または -t が必要を示した場合は再起動

4. PHP-FPM の request_terminate_timeout を超過

原因: PHP スクリプトの実行に PHP-FPM の request_terminate_timeout 設定よりも時間がかかっています。Nginx は応答を待ちますが、PHP-FPM がスクリプトを終了するため、Nginx は不完全な応答を受信します。

症状: Nginx エラーログに upstream timed out または script timed out と表示される場合があります。PHP-FPM ログには child XX exited on signal 9 (SIGKILL) と表示される場合があります。

解決策:

  • request_terminate_timeout を増やす: PHP-FPM プール設定(www.conf)で、このディレクティブを見つけて調整します。0 に設定するとタイムアウトが無効になりますが、長時間実行されるスクリプトがリソースを占有する可能性があるため、一般的には推奨されません。

    request_terminate_timeout = 300 # 5分(300秒)に増やす
    
  • Nginx の fastcgi_read_timeout を増やす: この Nginx タイムアウトは、request_terminate_timeout 以上である必要があります。

    location ~ \.php$ {
        ...
        fastcgi_read_timeout 300s; # PHP-FPM の request_terminate_timeout 以上である必要があります
        ...
    }
    

警告: タイムアウトを増やすと 502 エラーが解決される可能性がありますが、根本的なパフォーマンスの問題を隠してしまう可能性があります。長期的な最善の解決策は、遅い PHP スクリプトを最適化することです。

5. ファイアウォールの問題

原因: ファイアウォール(Nginx サーバー上、または別々の場合はアップストリームサーバー上)が、アップストリームのポートまたはソケットへの接続をブロックしています。

解決策:

  • ファイアウォールのステータスを確認:

    sudo ufw status # UFW の場合(Ubuntu/Debian)
    sudo firewall-cmd --list-all # firewalld の場合(CentOS/RHEL)
    sudo iptables -L # iptables の場合
    
  • 必要なポートを開放: Nginx がアップストリームへの接続に使用するポート(例:TCP/IP 経由の PHP-FPM の場合は 9000)が開いていることを確認します。

    sudo ufw allow from 127.0.0.1 to any port 9000 # localhost が 9000 に接続できるようにする
    sudo firewall-cmd --permanent --add-port=9000/tcp # firewalld の場合
    sudo firewall-cmd --reload
    
  • テスト目的でのみ、管理された環境で一時的にファイアウォールを無効にし、その後再び有効にして適切に設定します。

6. SELinux または AppArmor の干渉

原因: SELinux(RHEL/CentOS)や AppArmor(Ubuntu/Debian)などのセキュリティ強化機能が、ファイルのパーミッションやファイアウォールが正しく設定されている場合でも、Nginx がアップストリームソケットにアクセスしたりネットワーク接続を行ったりするのを妨げている可能性があります。

症状: ログに permission denied または同様のメッセージが表示される場合があり、特に /var/log/audit/audit.log(SELinux の場合)に表示されます。

解決策:

  • audit.log を確認:

    sudo grep nginx /var/log/audit/audit.log
    
  • SELinux を一時的に許可モードに設定: sudo setenforce 0。エラーが解決した場合、SELinux が原因です。その後、適切な SELinux ポリシー(例:audit2allow)を生成して適用する必要があります。必ず強制モードに戻してください(sudo setenforce 1)。

  • AppArmor のステータスを確認: sudo aa-status。AppArmor がアクティブな場合、Nginx プロファイルを調整する必要があるかもしれません。

7. 大きなリクエスト/レスポンスボディ(プロキシバッファリング)

原因: Nginx のデフォルトのプロキシバッファリング設定が、非常に大きなリクエストまたはレスポンスボディに対して小さすぎるため、早期に接続が閉じられる可能性があります。

症状: Nginx エラーログに upstream prematurely closed connection while reading response header from upstream または upstream prematurely closed connection while reading response body from upstream と表示される場合があります。

解決策: httpserver、または location ブロックで Nginx プロキシバッファリングディレクティブを調整します。

http {
    ...
    proxy_buffer_size   128k; # 応答の最初の部分のバッファサイズ
    proxy_buffers   4 256k; # 応答の残りの部分のバッファの数とサイズ
    proxy_busy_buffers_size   256k; # ビジーバッファの最大サイズ
    proxy_temp_file_write_size 256k; # バッファリングがオーバーフローした場合の一時ファイルへの書き込みサイズ
    ...
}

: これらの設定はより多くのメモリを消費します。サーバーのリソースとアプリケーションの応答の一般的なサイズに基づいて、慎重に調整してください。

一般的なトラブルシューティングのヒント

  • 関連するすべてのログを確認する: Nginx エラーログに加えて、Nginx アクセスログ、アップストリームアプリケーションログ(PHP-FPM、Gunicorn、Node.js アプリのログ)、システムログ(/var/log/syslogdmesg)も確認します。
  • Nginx を再起動する: 設定変更後は、必ず Nginx を再起動して変更を反映させます: systemctl restart nginx
  • Nginx 設定をテストする: 再起動する前に、Nginx 設定の構文を検証します: nginx -t
  • 問題を切り分ける: Nginx をバイパスして、アップストリームアプリケーションに直接アクセスしてみます。たとえば、Node.js アプリが localhost:3000 にある場合、サーバーのコマンドラインから curl http://localhost:3000 を使用します。これも失敗する場合、問題は間違いなく Nginx ではなくアプリケーションにあります。
  • ディスク容量を確認する: ディスクがいっぱいになると、アプリケーションが一時ファイルやログを書き込めなくなり、クラッシュや障害が発生する可能性があります。df -h を使用してディスク使用量を確認します。

まとめ

/var/log/nginx/error.log から始めて、次にアップストリームが実行中で Nginx ホストから到達可能であることを確認します。障害が接続拒否、タイムアウト、権限拒否、早期切断のいずれであるかがわかれば、修正は通常、アップストリームサービス、ソケットのパーミッション、タイムアウト設定、またはファイアウォールルールにあります。