症状

nginx で proxy_pass を設定したが、バックエンドに転送されない、または 502 Bad Gateway が表示される。

結論:まずこれを確認

  1. バックエンドのプロセスが起動しているか確認する
  2. proxy_pass の URL 末尾のスラッシュ有無を確認する
  3. nginx のエラーログ /var/log/nginx/error.log を確認する

トラブルシューティングフロー

    flowchart TD
    A[proxy_pass が動かない] --> B{バックエンドは起動している?}
    B -->|No| C[バックエンドを起動する]
    B -->|Yes| D{nginx error.log にエラーあり?}
    D -->|Connection refused| E[ポート番号を確認]
    D -->|Permission denied| F[SELinux/権限を確認]
    D -->|Timeout| G[バックエンドの応答を確認]
    D -->|No error| H{ブラウザで直接アクセスできる?}
    H -->|Yes| I[location ブロックの設定を確認]
    H -->|No| J[ファイアウォールを確認]
  

よくある原因

  • バックエンドが起動していない - プロセスが落ちている、ポートが Listen されていない
  • proxy_pass の URL 末尾スラッシュ問題 - スラッシュの有無でパスの扱いが変わる
  • ポート番号の間違い - バックエンドの Listen ポートと proxy_pass の指定が一致していない
  • SELinux が接続をブロック - httpd_can_network_connect が無効
  • upstream の名前解決失敗 - DNS や /etc/hosts の問題
  • タイムアウト設定が短すぎる - バックエンドの応答より前に nginx が切断
  • location ブロックのマッチ優先度 - 別の location が先にマッチしている

確認手順

ステップ1: バックエンドの起動状態を確認する

    # バックエンドのポートが Listen されているか確認
ss -tlnp | grep :3000
# または
netstat -tlnp | grep :3000
  

🔍 チェックポイント: LISTEN 状態で対象ポートが表示されれば正常

    # プロセスが起動しているか確認(例: Node.js)
ps aux | grep node
  

ステップ2: nginx のエラーログを確認する

    # 最新のエラーを確認
sudo tail -50 /var/log/nginx/error.log
  

🔍 チェックポイント: 以下のエラーを探す

  • connect() failed (111: Connection refused) → バックエンド未起動
  • connect() failed (13: Permission denied) → SELinux
  • upstream timed out → タイムアウト

ステップ3: proxy_pass の URL 形式を確認する

    # 末尾スラッシュなし - location のパスがそのまま転送される
location /api {
    proxy_pass http://localhost:3000;
}
# /api/users → http://localhost:3000/api/users

# 末尾スラッシュあり - location のパスが置換される
location /api/ {
    proxy_pass http://localhost:3000/;
}
# /api/users  http://localhost:3000/users
  

🔍 チェックポイント: バックエンドが期待するパスと一致しているか確認する

ステップ4: nginx の設定構文を確認する

    # 構文チェック
sudo nginx -t
  

🔍 チェックポイント: syntax is oktest is successful が表示されれば正常

    # 設定を再読み込み
sudo nginx -s reload
  

ステップ5: curl でバックエンドに直接アクセスする

    # nginx を経由せず直接確認
curl -v http://localhost:3000/
  

🔍 チェックポイント: 200 OK が返れば、バックエンド自体は正常

    # nginx 経由で確認
curl -v http://localhost/api/
  

ステップ6: SELinux の状態を確認する(RHEL/CentOS系)

    # SELinux の状態を確認
getenforce
  

🔍 チェックポイント: Enforcing の場合、ネットワーク接続がブロックされている可能性がある

    # httpd のネットワーク接続を許可
sudo setsebool -P httpd_can_network_connect 1
  

ステップ7: ファイアウォールを確認する

    # バックエンドポートがローカルからアクセス可能か確認
curl -v http://127.0.0.1:3000/
  

🔍 チェックポイント: localhost と 127.0.0.1 の両方で確認する

🚨 この結果が出たらヤバい

症状 意味 緊急度
Connection refused が繰り返し出る バックエンドが完全に停止している
Too many open files ファイルディスクリプタ枯渇
upstream sent too big header バックエンドの応答ヘッダーが大きすぎる
no live upstreams upstream 内の全サーバーが dead 扱い

NG行動(やってはいけないこと)

  • nginx を再起動せずに設定変更を期待する - nginx -s reload または systemctl reload nginx が必要
  • SELinux を無効化して放置する - 一時的な確認後は適切なポリシーを設定する
  • エラーログを見ずに設定を変更し続ける - 原因特定が遅れる
  • proxy_pass と location のスラッシュを適当に変更する - パスの扱いが変わり別の問題が発生する

よくある質問(FAQ)

Q1: upstream で複数サーバーを指定しているが、1台に偏る

A: デフォルトはラウンドロビン。weight パラメータや least_conn ディレクティブを確認する。バックエンドが落ちていると、生きているサーバーに集中する。

Q2: proxy_pass で WebSocket が動かない

A: UpgradeConnection ヘッダーの転送が必要。以下を追加する:

    proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
  

Q3: 502 と 504 の違いは?

A: 502 はバックエンドに接続できない。504 は接続はできたが応答がタイムアウトした。

関連するエラー・症状

  • (関連記事準備中)
  • (関連記事準備中)
  • (関連記事準備中)

解決しない場合

  • nginx 公式ドキュメント - proxy_pass
  • 確認すべきログファイル:
    • /var/log/nginx/error.log
    • /var/log/nginx/access.log
    • バックエンドアプリケーションのログ
  • 次に調べるキーワード: nginx upstream connection refused, nginx proxy_pass path rewrite