症状

ブラウザで「ERR_TOO_MANY_REDIRECTS」「このページは正しくリダイレクトされていません」と表示される

結論:まずこれを確認

  1. curl -I -L URL でリダイレクト先を追跡し、ループしているか確認する
  2. nginx設定で同じURLへのrewrite/returnが連鎖していないか確認する
  3. SSL終端がnginxより前(ロードバランサー等)にある場合、X-Forwarded-Protoの処理を確認する

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

    flowchart TD
    A[リダイレクトループ発生] --> B{curlでループ確認}
    B -->|ループあり| C{HTTPSリダイレクト関連?}
    B -->|ループなし| D[ブラウザキャッシュクリア]
    C -->|Yes| E[SSL終端位置を確認]
    C -->|No| F{rewrite/returnルール}
    E --> G[X-Forwarded-Proto確認]
    F -->|ルールあり| H[条件式を確認]
    F -->|ルールなし| I[upstreamの設定確認]
    G --> J[プロキシヘッダー設定を修正]
    H --> K[重複・矛盾するルールを修正]
    I --> L[バックエンドのリダイレクトを確認]
  

よくある原因

  • HTTPからHTTPSへのリダイレクト設定の重複 - nginx側とアプリ側の両方でリダイレクト設定があり、互いに転送し合う
  • ロードバランサー配下でのHTTPSリダイレクト - SSL終端がLB側にあり、nginx側では常にHTTPに見えるため無限ループする
  • rewriteルールの条件不備 - リダイレクト後のURLも同じルールにマッチしてしまう
  • trailing slashの処理 - /path/path/を相互にリダイレクトし続ける
  • www有無のリダイレクト設定の矛盾 - www付きと無しで互いにリダイレクトする設定になっている
  • locationブロックの優先順位問題 - 意図しないlocationブロックにマッチしている
  • proxyヘッダーの未設定 - バックエンドが自身のURLを正しく認識できていない

確認手順

ステップ1: リダイレクトチェーンを確認する

    curl -I -L --max-redirs 10 https://example.com/path
  

🔍 チェックポイント: Locationヘッダーの遷移を確認し、同じURLが繰り返されていればループ確定

ステップ2: nginx設定のrewrite/returnルールを確認する

    # 設定ファイルからrewrite/returnを抽出
grep -rn "rewrite\|return 30" /etc/nginx/sites-enabled/
  

🔍 チェックポイント: 同じパスに対して複数のリダイレクトルールが存在しないか確認する

ステップ3: HTTPSリダイレクトの設定を確認する

    # HTTPからHTTPSへのリダイレクト設定を確認
grep -rn "return 301 https" /etc/nginx/sites-enabled/
grep -rn "rewrite.*https" /etc/nginx/sites-enabled/
  

🔍 チェックポイント: リダイレクト条件に$scheme$httpsの判定が含まれているか確認する

ステップ4: ロードバランサー環境の場合はヘッダーを確認する

    # リクエストヘッダーを確認するためのテスト設定
# nginx.confのlocationブロックに一時的に追加
add_header X-Debug-Scheme $scheme;
add_header X-Debug-Forwarded-Proto $http_x_forwarded_proto;
  
    # curlで確認
curl -I https://example.com/path
  

🔍 チェックポイント: X-Forwarded-Protoが正しくhttpsになっているか確認する

ステップ5: 正しい条件式に修正する

ロードバランサー配下の場合の推奨設定:

    # X-Forwarded-Protoを考慮したHTTPSリダイレクト
server {
    listen 80;
    server_name example.com;

    # LB配下ではX-Forwarded-Protoを確認
    if ($http_x_forwarded_proto = "http") {
        return 301 https://$host$request_uri;
    }

    # LBを使わない環境用
    if ($scheme = "http") {
        return 301 https://$host$request_uri;
    }
}
  

🔍 チェックポイント: 設定変更後、nginx -tでシンタックスエラーがないことを確認する

ステップ6: 設定をリロードして動作確認する

    # 設定テスト
sudo nginx -t

# リロード
sudo systemctl reload nginx

# 動作確認
curl -I -L --max-redirs 5 https://example.com/path
  

🔍 チェックポイント: リダイレクトが1回で終了し、最終的に200が返ることを確認する

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

  • ブラウザだけでテストする - キャッシュされた301リダイレクトが残り、正確な確認ができない
  • rewriteルールを追加して回避しようとする - ルールが複雑化し、問題の特定が困難になる
  • nginx -tを実行せずにreloadする - シンタックスエラーでnginxが停止するリスクがある
  • 本番環境で直接設定を変更する - 検証環境で動作確認してから本番に適用する
  • 設定変更前のバックアップを取らない - 切り戻しができなくなる

よくある質問(FAQ)

Q1: ブラウザで301リダイレクトがキャッシュされてしまった場合は?

A: ブラウザのキャッシュをクリアするか、シークレットモードでアクセスする。またはcurl -Iでサーバー側の動作を確認する

Q2: CloudflareなどのCDN配下でリダイレクトループが発生する場合は?

A: CDN側のSSL/TLS設定を「Full」または「Full (Strict)」に変更する。「Flexible」だとオリジンへの接続がHTTPになりループの原因となる

Q3: 特定のパスだけでリダイレクトループが発生する場合は?

A: locationブロックの優先順位を確認する。正規表現を使ったlocationブロックが意図しないパスにマッチしている可能性がある

関連するエラー・症状

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

解決しない場合