Nginx の ERR_TOO_MANY_REDIRECTS を修正する:「内部リダイレクトサイクル」の解決策

intermediate Nginx2026-03-30| Ubuntu 20.04/22.04, Debian 11/12, CentOS 7/8, Nginx 1.18.x or higher, PHP-FPM 7.4/8.x

Error Message

rewrite or internal redirection cycle while internally redirecting to "/index.php"
#nginx#devops#php-fpm#サーバー設定#トラブルシューティング

問題の発生サイトを確認しようとすると、ホームページが表示される代わりに、ブラウザにストレスの溜まる ERR_TOO_MANY_REDIRECTS というメッセージが表示されることがあります。Nginx のエラーログ(通常は /var/log/nginx/error.log)を確認すると、次のような特定のエントリが見つかるはずです。

2023/10/24 10:15:30 [error] 1234#0: *1 rewrite or internal redirection cycle while internally redirecting to "/index.php", client: 192.168.1.1, server: example.com, request: "GET / HTTP/1.1", host: "example.com"

Nginx には、内部リダイレクトの回数を10回までに制限する安全装置があります。リクエストがループに陥り、最終的に提供すべきファイルが見つからない場合、Nginx はサーバーの CPU 負荷が最大になるのを防ぐためにプロセスを強制終了します。

ステップ 1:Curl を使ってループの場所を特定するcurl テストを素早く行うことで、ループがブラウザのロジックにあるのか、それとも Nginx の深部にあるのかを明らかにできます。ターミナルから次のコマンドを実行してください。

curl -I http://example.com

結果を詳しく見てみましょう。HTTP と HTTPS の間で HTTP/1.1 301 Moved Permanently ヘッダーが何度もやり取りされている場合は、論理的なリダイレクトループが発生しています。一方、500 Internal Server Error が表示される場合は、ログに記録されている内部書き換えサイクル(internal rewrite cycle)が原因です。

ステップ 2:try_files ディレクティブの監査Laravel、WordPress、Symfony などのほとんどの PHP アプリケーションは、URL の処理を try_files ディレクティブに依存しています。一般的で正常な設定は次のようになります。

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

このサイクルは、Nginx がルートフォルダ内で index.php を見つけられないときに始まります。ファイルが見つからないため、Nginx は最後のパラメータにフォールバックしますが、それが location ~ \.php$ ブロックをトリガーし、そこで再び失敗して検索を再開してしまいます。root パスを再確認してください。アプリケーションが /var/www/my-app/public にあるのに、Nginx が /var/www/my-app を探している場合、エントリファイルは見つかりません。

server {
    listen 80;
    server_name example.com;
    root /var/www/html/public; # このパスに index.php が含まれていることを確認してください
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
    }
}

ステップ 3:SSL 終端ループの解決Cloudflare や AWS Load Balancer を使用していませんか?その場合、SSL の「ピンポン」状態に陥っている可能性があります。これは、プロキシがポート 80 (HTTP) 経由で Nginx と通信しているにもかかわらず、Nginx がすべてを HTTPS にリダイレクトしようとすることで発生します。プロキシがリクエストを送り、Nginx が「HTTPS へ行け」と返し、プロキシがそれを再び HTTP として送り返すというループです。

これを止めるには、X-Forwarded-Proto ヘッダーを使用して元のプロトコルを検出します。リクエストがまだ安全でない場合にのみリダイレクトするように設定を更新します。

# server ブロック内に追加してください
if ($http_x_forwarded_proto != "https") {
    return 301 https://$host$request_uri;
}

ステップ 4:PHP 用の「サーキットブレーカー」を使用するSCRIPT_FILENAME が見つからない場合、Nginx はどのスクリプトを実行すべきか混乱することがあります。サーキットブレーカーを追加することは、ループを即座に停止させる最善の方法です。PHP ブロック内に try_files $fastcgi_script_name =404; を追加します。これにより、ファイルが見つからない場合に内部リダイレクトを繰り返すのではなく、処理を停止して 404 エラーを返すよう Nginx に指示します。

location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    
    # ファイルが見つからない場合にループを遮断する行
    try_files $fastcgi_script_name =404;
    
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass unix:/var/run/php/php-fpm.sock;
}

ステップ 5:検証とリロードサイトがオフラインになるのを防ぐため、変更を適用する前にテストを行ってください。Nginx の構文チェックを実行します。

sudo nginx -t

テストに合格したら、サービスをリロードして変更を反映させます。

sudo systemctl reload nginx

最後に、もう一度 curl -I を実行してください。正常な HTTP/1.1 200 OK、または 1 回の 301 リダイレクトの後に 200 ステータスコードが表示されるはずです。

まとめチェックリスト- ルートの確認: root ディレクティブが index.php を含むフォルダを正確に指しているか確認してください。- 検索の中止: 行方不明のファイルを Nginx が無限に探し続けないよう、PHP ブロックで try_files ... =404; を使用してください。- プロキシの認識: Cloudflare を使用している場合は、$scheme 変数の代わりに X-Forwarded-Proto ヘッダーを使用してください。- デバッグの有効化: それでも解決しない場合は、設定に rewrite_log on; を追加し、エラーログのレベルを notice に設定して、URL 変換のステップを詳細に確認してください。

Related Error Notes