

nginxのtry_filesでrewrite or internal redirection cycleが起きる条件
この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。
何が起きたか
nginxのエラーログにこういうのが出た。
*4 rewrite or internal redirection cycle while internally redirecting to "/index.html", client: 127.0.0.1, server: _, request: "GET /index.html HTTP/1.1", Host: "example.net"設定はSPA向けによくある形。
try_files $uri $uri/ /index.html;try_filesの動作
左から順に候補を確認していくだけ。$uriは実ファイルとして存在するか、$uri/はディレクトリとして存在するか、最後のパラメータはそのどちらでもなかったときのフォールバック。最後のパラメータが=404のように=付きならその場でステータスを返すだけだけど、/index.htmlのようにURIの形なら内部リダイレクトになる。
flowchart TD
A[リクエスト] --> B{"$uriは実ファイルとして存在する?"}
B -- Yes --> C[そのファイルを返す]
B -- No --> D{"$uri/はディレクトリとして存在する?"}
D -- Yes --> E[indexディレクティブに従って配下のファイルを返す]
D -- No --> F{"最後のパラメータは=code形式?"}
F -- Yes --> G[そのステータスコードを返す]
F -- No --> H["最後のパラメータへ内部リダイレクト(例: /index.html)"]
ループになる理由
/index.htmlへ内部リダイレクトすると、そのURIはまた同じlocationにマッチして、try_filesが再評価される。ここでdocument root配下にindex.htmlの実体が無いと、$uri(=/index.html)も$uri/も存在しないので、また最後のパラメータの/index.htmlにリダイレクト……という感じで自分自身を呼び直す形になる。
nginxは内部リダイレクトの回数に上限(10回)を持っていて、それを超えるとこのエラーで打ち切られるらしい。今回のログのメッセージはまさにその挙動。
404にしたい場合
ディレクトリ配下にフォールバック用のindex.htmlを置かず、単に見つからなければ404にしたいなら=404を使う。
try_files $uri $uri/ =404;=404は内部リダイレクトを発生させずその場でステータスを返すだけなので、上のようなループにはならない。
補足
try_files自体は2009年リリースのnginx 0.7.27から入っている機能で、この基本動作は当時から変わっていない(実機で全バージョン確認したわけではないので、あくまで公式ドキュメントとコミュニティの解説をベースにした話)。ループになるのは基本的に、フォールバック先のURIが同じlocationに戻ってくる構成のときだけなので、/index.htmlを別のlocation(静的ファイル専用など)で確実に拾えるようにしてあれば問題は起きない。