問題の発生サイトを確認しようとすると、ホームページが表示される代わりに、ブラウザにストレスの溜まる 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 ステータスコードが表示されるはずです。

