nginxのtry_filesでrewrite or internal redirection cycleが起きる条件

  • nginx
  • SPA

この記事は、構成と文章の整理に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(静的ファイル専用など)で確実に拾えるようにしてあれば問題は起きない。