Nginx try_files ディレクティブの徹底解説:使い方、設定方法、応用、パフォーマンスまで
ウェブサーバーの設定において、リクエストされたURIに対応する適切なコンテンツを見つけることは、最も基本的な機能の一つです。静的なHTMLファイルや画像、CSS、JavaScriptといったファイルをそのまま返す場合もあれば、特定のパスに対してPHPやPythonなどのスクリプトを実行する場合、さらにはリクエストされたURIが見つからなかった場合に特定のエラーページを表示する必要もあります。
Nginxでは、このような「複数の候補の中から適切なリソースを探し出して返す」という処理を効率的かつ柔軟に行うために、try_files ディレクティブが提供されています。このディレクティブは、Nginxの設定において非常に頻繁に利用され、静的サイトの配信、モダンなWebアプリケーションのフロントコントローラーパターン、SPA (Single Page Application) のルーティングなど、様々なユースケースで中心的な役割を果たします。
本記事では、Nginxの try_files ディレクティブについて、その基本的な構文から詳細な動作原理、多様な使い方、関連するディレクティブとの連携、パフォーマンスへの影響、さらにはよくある問題とその解決策に至るまで、網羅的かつ詳細に解説します。この記事を読むことで、try_files を深く理解し、あなたのNginx設定をより強力で効率的なものにするための知識を得られるでしょう。
1. try_files とは何か? なぜ使うのか?
Nginxは、クライアントからのHTTPリクエストを受け取ると、そのリクエストのURIに基づいて、どのコンテンツをどのように返すかを決定します。この決定プロセスにおいて、特定のURIに対して複数の候補となるファイルパスや処理方法が存在することがよくあります。
例えば、ユーザーが /about というURLにアクセスした場合を考えてみましょう。ウェブサイトの構造によっては、これは以下のような複数の意味を持つ可能性があります。
/aboutという名前の静的なHTMLファイル (/var/www/html/about) を指しているかもしれない。/about/index.htmlのように、/aboutディレクトリ内のインデックスファイルを指しているかもしれない。/aboutに対応する静的ファイルが見つからなかった場合に、アプリケーションのフロントコントローラーである/index.phpに処理を委譲し、PHPスクリプトが/aboutというパスに基づいて動的なコンテンツを生成するかもしれない。- これらの候補全てが見つからなかった場合、404 Not Found エラーを返す必要がある。
このようなシナリオで、「まず /about というファイルを探し、なければ /about/ ディレクトリのインデックスファイルを探し、それも見つからなければ /index.php に処理を渡し、最終的にそれもダメなら 404 エラーを返す」といった一連のフォールバック処理を効率的に記述できるのが try_files ディレクティブです。
try_files は、指定されたファイルパスやディレクトリパスを順番に評価し、最初にヒットしたものに対応する処理を行います。これにより、複雑な条件分岐 (例えば if ディレクティブを多用する場合など) を使うよりもシンプルで、多くの場合パフォーマンスも優れた設定を実現できます。
2. try_files の基本構文と動作原理
try_files ディレクティブは、server ブロックまたは location ブロックの中で使用できます。一般的な構文は以下の通りです。
nginx
try_files file1 [file2 file3 ...] uri;
または、最終引数にステータスコードを指定することもできます。
nginx
try_files file1 [file2 file3 ...] =code;
それぞれの引数について説明します。
file(1つ以上必須): これは、Nginxが最初に試行するファイルまたはディレクトリのパスを指定します。複数のfile引数をスペース区切りで指定できます。これらのパスは、通常rootまたはaliasディレクティブで指定されたドキュメントルートからの相対パスとして解釈されます。ファイルパスには、Nginxの変数を使用することも可能です ($uri,$request_uri,$argsなど)。指定されたパスがディレクトリである場合、Nginxは通常、そのディレクトリ内のインデックスファイル (indexディレクティブで指定されたファイル、デフォルトではindex.html) を探そうとします。ただし、try_filesの中でディレクトリを指定する場合は、明示的に末尾にスラッシュ (/) を付けて指定する必要があります (例:$uri/)。uri(最後の引数としてのみ指定可能): これは、指定されたfileの候補が全て見つからなかった場合に、Nginxが内部的にリダイレクトする新しいURIです。このURIへのリクエストは、元のリクエストとは異なる、全く新しい内部リクエストとして扱われます。この内部リダイレクトにより、別のlocationブロックに処理を委譲したり、特定のスクリプトファイル (例:/index.php) にリクエストを渡したりすることが可能になります。この引数には、クライアントへの外部リダイレクトではなく、サーバー内部でのリクエスト処理の移譲であるという重要な違いがあります。=code(最後の引数としてのみ指定可能): これは、指定されたfileの候補が全て見つからなかった場合に、Nginxがクライアントに返すHTTPステータスコードを指定します。最も一般的なのは=404(Not Found) ですが、=500(Internal Server Error) など、他のステータスコードを指定することも可能です。この引数が指定された場合、Nginxはそのステータスコードを返し、通常はerror_pageディレクティブの設定に従って、対応するエラーページを表示します。
動作原理:
try_files ディレクティブは、左から右へと順番に引数を評価します。
- 最初の
file引数で指定されたパスに対応するファイルまたはディレクトリが存在するかどうかをチェックします。- もし存在し、それがファイルであれば、Nginxはそのファイルをクライアントに返します。ここで処理は終了です。
- もし存在し、それがディレクトリであれば、Nginxはそのディレクトリ内のインデックスファイル (
indexディレクティブで指定されたファイル) を探します。インデックスファイルが見つかれば、そのファイルが返され処理は終了です。インデックスファイルが見つからなければ、次の引数の評価に移ります。 - もし存在しなければ、次の引数の評価に移ります。
- 2番目以降の
file引数に対しても、同様のチェックを順番に行います。ファイルまたはディレクトリが見つかれば、その対応するコンテンツが返され、処理は終了です。 - 全ての
file引数に対応するファイルまたはディレクトリが見つからなかった場合、最後の引数を評価します。- 最後の引数が
uriであれば、Nginxはそのuriに対して内部リダイレクトを行います。この新しいURIに対するリクエストは、Nginxの設定内で再度ルーティングされ、対応するlocationブロックで処理されます。元のリクエストのメソッド、ヘッダー、リクエストボディは引き継がれます。クエリストリングは、特別な指定がない限り引き継がれます ($is_args$argsを使用して制御できます)。 - 最後の引数が
=codeであれば、NginxはそのHTTPステータスコードをクライアントに返します。
- 最後の引数が
重要なポイント:
try_filesはファイルシステム上の存在確認を行います。これはI/O操作を伴うため、多数の引数や、存在しない可能性が高いパスを最初に指定すると、パフォーマンスに影響を与える可能性があります。- ディレクトリを指定する場合は、末尾にスラッシュ (
/) を付ける必要があります ($uri/のように)。スラッシュがない場合、それはファイルとしてのみ扱われます。 - 最後の引数が
uriの場合、それは新しいURIへの内部リダイレクトであり、外部リダイレクト (301, 302など) ではありません。ブラウザのアドレスバーのURLは変わりません。 try_filesディレクティブ自体は、ファイルのコンテンツタイプ (Content-Typeヘッダー) を決定する機能は持っていません。これは通常、mime.typesファイルやtypesディレクティブによって、返されるファイルの拡張子に基づいて自動的に行われます。try_filesでファイルが見つかった場合、そのファイルに対するリクエストとして処理が進みます。例えば、.phpファイルが見つかった場合、通常は.phpファイルを処理するためのlocationブロック (例:location ~ \.php$) に内部的に処理が移譲され、PHP-FPMなどのFastCGIサーバーにリクエストが渡されます。
3. try_files の典型的な使い方
try_files は、様々なシナリオで柔軟に利用できます。ここではいくつかの代表的な使い方を紹介します。
3.1. 静的ファイルの提供とフォールバック
最も基本的な使い方は、リクエストされたURIに対応する静的ファイルを探し、見つからなければ 404 エラーを返す設定です。
“`nginx
server {
root /var/www/html;
location / {
try_files $uri $uri/ =404;
}
}
“`
この例では、リクエストURIが /path/to/file であると仮定します。
try_files $uri ...: まず、rootディレクティブで指定された/var/www/htmlディレクトリ内で、リクエストURIに対応するファイル/var/www/html/path/to/fileが存在するかチェックします。- もし存在すれば、そのファイルがクライアントに返されます。
try_files ... $uri/ ...: ファイルが見つからなかった場合、次にリクエストURIに対応するディレクトリ/var/www/html/path/to/file/が存在するかチェックします。- もし存在すれば、Nginxは
/var/www/html/path/to/file/ディレクトリ内のインデックスファイル (例:index.html) を探します (indexディレクティブの設定による)。インデックスファイルが見つかればそれが返されます。
- もし存在すれば、Nginxは
try_files ... =404;: ファイルもディレクトリもインデックスファイルも見つからなかった場合、最終的に=404が返され、404 Not Found エラーとなります。
このように、$uri はファイル、$uri/ はディレクトリとその中のインデックスファイルを探すための一般的なパターンとしてよく使用されます。
3.2. SPA (Single Page Application) での使用
React, Vue.js, AngularなどのSPAでは、クライアントサイドでルーティングを行います。ユーザーが /about や /products/123 のような特定のパスに直接アクセスしたり、ページをリロードしたりした場合、サーバーは通常、アプリケーションのエントリーポイントである index.html を返す必要があります。しかし、もし /about という静的ファイルやディレクトリが存在すれば、それが優先されてしまい、SPAのルーティングが正しく機能しません。
この問題を解決するために、try_files を利用して、「リクエストされたURIに対応する静的ファイル(CSS, JS, 画像など)が見つからなければ、全てのエントリーポイントである index.html を返す」という設定を行います。
“`nginx
server {
root /var/www/spa/dist;
location / {
try_files $uri $uri/ /index.html;
}
}
“`
この設定の動作:
try_files $uri ...: クライアントが/css/style.cssにアクセスした場合、まず/var/www/spa/dist/css/style.cssというファイルを探します。静的ファイルであればそれが返されます。/aboutのようなパスの場合、対応する静的ファイルは存在しないため、次のステップへ進みます。try_files ... $uri/ ...:/aboutのようなパスで、もし/var/www/spa/dist/about/というディレクトリが存在すれば、その中のインデックスファイルを探します。SPAでは通常そのようなディレクトリは存在しないか、存在しても/aboutというクライアントサイドルートとは無関係であることが多いです。存在しない場合、次のステップへ進みます。try_files ... /index.html;:$uriも$uri/も見つからなかった場合、最終引数である/index.htmlに内部リダイレクトされます。この/index.htmlは/var/www/spa/dist/index.htmlというファイルとして存在することが想定されます。Nginxは/index.htmlを返すため、ブラウザはSPAアプリケーションをロードし、クライアントサイドJavaScriptが/aboutというパスを解釈して適切なコンポーネントを表示します。
このように、try_files を使うことで、静的アセットの配信と、SPAのエントリーポイントへのフォールバックを同時にシンプルに実現できます。
3.3. 動的なコンテンツへのフォールバック (フロントコントローラーパターン)
多くのモダンなWebアプリケーションフレームワーク (WordPress, Laravel, Symfonyなど) は、リクエストされたURIにかかわらず、全てのリクエストを単一のフロントコントローラーファイル (通常は index.php) に集約して処理する、フロントコントローラーパターンを採用しています。これにより、ルーティングや共通処理 (認証、ログなど) をアプリケーション側で一元管理できます。
このパターンを実現するために、try_files を使用して、「リクエストされたURIに対応する静的ファイルやディレクトリが見つからなければ、フロントコントローラーに処理を委譲する」という設定を行います。
WordPressのパーマリンク設定は、このパターンの代表例です。
“`nginx
server {
root /var/www/wordpress;
index index.html index.php; # インデックスファイルも指定しておく
location / {
try_files $uri $uri/ /index.php?$args;
}
# .php ファイルの処理は別の location ブロックで行う
location ~ \.php$ {
include snippets/fastcgi-php.conf; # FastCGI設定を含むファイル
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; # PHP-FPMソケットへのパス
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info; # PATH_INFO を渡す設定
}
}
“`
この設定の動作:
try_files $uri ...: クライアントが/wp-content/themes/mytheme/style.cssのような静的アセットにアクセスした場合、まず/var/www/wordpress/wp-content/themes/mytheme/style.cssというファイルを探します。存在すればそれが返されます。/hello-world/のようなWordPressの投稿ページへのアクセスの場合、対応する静的ファイルは存在しないため、次のステップへ進みます。try_files ... $uri/ ...:/hello-world/のようなパスで、もし/var/www/wordpress/hello-world/というディレクトリが存在すれば、その中のインデックスファイル (index.htmlまたはindex.php) を探します。通常、WordPressのパーマリンクではこのようなディレクトリは存在しないため、次のステップへ進みます。try_files ... /index.php?$args;:$uriも$uri/も見つからなかった場合、最終引数である/index.php?$argsに内部リダイレクトされます。/index.phpは、リクエストを/index.phpというURIにリライトすることを意味します。?$argsは、元のリクエストに含まれていたクエリストリング (?key1=value1&key2=value2) を、新しいURI (/index.php) に引き継ぐための指定です。これにより、例えば/index.php?p=123のようなリクエストも正しく/index.phpにクエリストリング付きで渡されます。- この
/index.phpへの内部リダイレクトは、次にlocation ~ \.php$ブロックによって捕捉されます。
location ~ \.php$:/index.phpへのリクエストは、このlocationブロックで処理されます。ここでPHP-FPMなどのFastCGIサーバーに処理が渡され、/index.phpスクリプトが実行されます。PHPスクリプトは、元のリクエストURI (/hello-world/) を$_SERVER['REQUEST_URI']や$_SERVER['PATH_INFO']といったサーバー変数から取得し、それに基づいて適切なコンテンツ (例: 「Hello World」という投稿の内容) をデータベースから取得して動的に生成し、Nginx経由でクライアントに返します。
このように、try_files は静的ファイル配信と、動的なフロントコントローラーへのスムーズな連携を可能にします。
3.4. カスタムエラーページの表示
最後の引数に =code を指定することで、ファイルが見つからなかった場合に特定のエラーコードを返すことができます。これは、error_page ディレクティブと組み合わせて、カスタムエラーページを表示するために使用されます。
“`nginx
server {
root /var/www/html;
location / {
try_files $uri $uri/ =404;
}
error_page 404 /404.html;
location = /404.html {
internal; # 外部からの直接アクセスを禁止
}
}
“`
この設定の動作:
- クライアントが
/nonexistentのような存在しないURIにアクセスします。 try_files $uri $uri/ =404;が評価されます。/var/www/html/nonexistentも/var/www/html/nonexistent/ディレクトリも存在しないため、最終引数=404が実行されます。- Nginxは内部的にステータスコード 404 を生成します。
error_page 404 /404.html;ディレクティブにより、Nginxは 404 エラーが発生した場合に/404.htmlに内部リダイレクトするよう設定されています。/404.htmlへの内部リダイレクトが発生し、対応するlocation = /404.htmlブロックで処理されます。- この
locationブロックはinternal;ディレクティブによって外部からの直接アクセスを禁止しています。Nginxはrootディレクティブに従って/var/www/html/404.htmlファイルを探し、それをクライアントに返します。クライアントには 404 ステータスコードと共にカスタムエラーページの内容が表示されます。
try_files =code は、error_page をトリガーするための効果的な方法です。try_files $uri $uri/ /404.html; とすることも可能ですが、この場合 /404.html がファイルとして存在しない場合に 404 エラーにならない可能性があるため、エラーハンドリングを明示的に行うには =code の使用が推奨されます。
4. 引数の詳細と応用
try_files の引数は、Nginxの変数と組み合わせることでさらに強力になります。また、ファイルとディレクトリの指定方法にも注意が必要です。
4.1. file 引数の詳細
- 相対パス:
file引数は、通常rootまたはaliasディレクティブで指定されたパスからの相対パスとして扱われます。例えばroot /var/www/html; try_files /path/to/file ...;は/var/www/html/path/to/fileを探します。ただし、絶対パス (/で始まるパス) を指定しても、それはrootやaliasからの相対パスとして解釈されます。 - 変数の利用: Nginxの様々な組み込み変数やユーザー定義変数を
file引数に使用できます。最もよく使われるのは$uriです。$uri: 正規化された現在のリクエストURI。クエリストリングは含まれません。$request_uri: 元のクライアントリクエストURI。クエリストリングを含みます。通常は$uriを使う方が安全です。$args: クエリストリングのみ (?は含まない)。$is_args: クエリストリングがあれば?、なければ空文字列。$document_root: 現在のロケーションで有効なrootディレクティブの値。$fastcgi_script_name: FastCGIに渡すスクリプト名としてよく使用される変数。通常は$uriに$document_rootを付けたものになります。- 例:
try_files $uri.html $uri/index.html ...;
- ディレクトリの指定: ディレクトリを指定する場合、末尾にスラッシュ (
/) を付ける必要があります。例えば$uri/と指定すると、Nginxは$uriで示されるパスがディレクトリであるかチェックし、ディレクトリであればその中のインデックスファイルを探します。スラッシュを付けずに$uriとだけ指定した場合、それはファイルとしてのみ扱われ、ディレクトリは見つけられません。 - 複数の
file: 複数のfileを指定することで、いくつかの候補パスを順番に試すことができます。例えば、.html拡張子を省略したURIでアクセスされた場合に、対応する.htmlファイルを探す設定など。
nginx
location / {
# /about にアクセス -> /var/www/html/about.html を探す
# /about/ にアクセス -> /var/www/html/about/index.html を探す (index ディレクティブの設定による)
# どちらも見つからなければ 404
try_files $uri.html $uri/ =404;
}
4.2. uri 引数の詳細
- 内部リダイレクト:
uri引数は、Nginxが内部的にリクエストを新しいURIに書き換えて、再処理を開始させるためのものです。これはクライアントへの外部リダイレクトとは異なり、ブラウザのURLは変化しません。 - 新しい
locationブロックの評価:uri引数で指定された新しいURIは、Nginxの設定内で再度ルーティングされ、そのURIに対応するlocationブロックが見つかると、そこで処理が続行されます。例えば、try_files ... /index.php;の場合、/index.phpは通常location ~ \.php$のようなブロックで捕捉され、PHPハンドリングの処理に進みます。 - クエリストリングの扱い:
uri引数にクエリストリングを含めずに/path/to/new_uriのように指定した場合、元のリクエストのクエリストリングは自動的に引き継がれます。明示的にクエリストリングを制御したい場合は、変数を使用します。try_files ... /new_uri?$args;: 元のクエリストリングを引き継ぐ (最も一般的)try_files ... /new_uri;: 元のクエリストリングは引き継がれない (ただし Nginxのバージョンや設定による違いに注意。$argsを明示的に付ける方が意図が明確)try_files ... /new_uri?param=value;: 新しいクエリストリングをハードコード
- リダイレクトループの可能性:
uri引数で指定されたURIが、再度同じtry_filesディレクティブを持つlocationブロックにマッチし、かつfileの候補も見つからない場合、無限リダイレクトループに陥る可能性があります。例えば、location / { try_files $uri /fallback; } location /fallback { try_files $uri /fallback; }のような設定は危険です。ループを避けるためには、内部リダイレクト先のlocationブロックではtry_filesを使用しないか、または最終引数に=codeを使用するように設計する必要があります。
4.3. =code 引数の詳細
- エラーコードの返却:
=code引数は、ファイル候補が見つからなかった場合に、Nginxが指定されたHTTPステータスコードをクライアントに返すことを指示します。 error_pageとの連携: この機能は、error_pageディレクティブと組み合わせて使用することが一般的です。try_files ... =404; error_page 404 /404.html;のように設定することで、「ファイルが見つからなかったら 404 を返し、404 が発生したら/404.htmlを表示する」というフローを構築できます。internalディレクティブ:error_pageで指定されたエラーページ用URI (/404.htmlなど) に対応するlocationブロックには、通常internal;ディレクティブを含めるべきです。これにより、そのURIへの外部からの直接アクセスを禁止し、Nginxの内部リダイレクトによってのみアクセスできるように制限することで、セキュリティを高めます。- 最後の手段として:
=codeは、全てのファイル候補やフォールバックURIを試しても適切なリソースが見つからなかった場合の「最後の手段」として機能します。
5. try_files と他のディレクティブとの連携
try_files は、単独で機能するのではなく、他の様々なNginxディレクティブと組み合わせて使用することで、その真価を発揮します。
5.1. root および alias
try_files の file 引数は、通常 root または alias ディレクティブで指定されたパスを基準として解釈されます。
root:locationブロック内のすべてのファイルパスに対して、指定されたドキュメントルートを適用します。location / { root /var/www/html; try_files $uri =404; }の場合、$uriは/var/www/html/$uriとして扱われます。alias: 特定のlocationブロック内のURIの特定の部分を、別のファイルシステムパスにマップします。location /static/ { alias /opt/web/static/; try_files $uri =404; }の場合、/static/path/to/fileというリクエストURIは、aliasによって/opt/web/static/path/to/fileというファイルシステムパスにマップされます。try_files $uriの$uriは/static/path/to/fileですが、aliasが適用されるため、Nginxは/opt/web/static/path/to/fileを探します。try_filesの引数に変数をそのまま使う際は、aliasのマッピングルールを理解しておくことが重要です。一般的には、rootとtry_filesを組み合わせる方がシンプルで分かりやすいことが多いです。
5.2. location
try_files は server ブロックまたは location ブロック内に記述します。location ブロックで囲むことにより、特定のURIパターンにのみ try_files のルールを適用することができます。
“`nginx
server {
root /var/www/html;
location / {
# 全てのリクエストに対する try_files ルール
try_files $uri $uri/ /index.html;
}
location ~ \.php$ {
# PHPファイルに対する try_files ルール (ここでは不要だが例として)
try_files $uri =404; # .php ファイルが見つからなければ 404
fastcgi_pass ...;
}
}
“`
try_files の最終引数に uri を指定した場合、その新しいURIに対するリクエストは、Nginxの設定全体で再度 location マッチングが行われます。これにより、try_files で別の location ブロックに処理を移譲するという強力な連携が可能になります。
5.3. index
index ディレクティブは、ディレクトリへのリクエストがあった際に、どのファイルをインデックスファイルとして扱うかを指定します (例: index index.html index.php;)。
try_files の引数としてディレクトリ ($uri/ など) を指定した場合、Nginxはそのディレクトリ内で index ディレクティブによって指定されたファイルを探します。
location / { root /var/www/html; index index.html index.php; try_files $uri $uri/ =404; }/dir/へのリクエストは$uri/(/dir/) にマッチします。- Nginxは
/var/www/html/dir/ディレクトリ内でindex index.html index.phpに従ってindex.htmlを探します。あればそれを返します。 - なければ
index.phpを探し、あればそれを返します。 - どちらも見つからなければ、次の
try_files引数に移ります (=404)。
try_files と index は密接に関連しており、通常は組み合わせて使用されます。
5.4. error_page
前述の通り、try_files =code は error_page ディレクティブと連携して、カスタムエラーページを表示するために使用されます。try_files で特定のステータスコードを生成し、そのコードに対するエラーページの設定を error_page で行うのが標準的なパターンです。
5.5. if との比較
Nginxで条件分岐を行うディレクティブとして if もありますが、Nginxのドキュメントでは if の使用は推奨されていません。特に location ブロック内で if を使用すると、予期せぬ挙動を引き起こす可能性があります。多くのファイル存在チェックやリクエストのフォールバック処理は、try_files でより効率的かつ安全に記述できます。
例えば、「ファイルが存在しなければ、別の場所にリダイレクトする」という処理を考えます。
if を使用した(非推奨の)例:
nginx
location / {
root /var/www/html;
# 非推奨! 複雑な if ロジックは try_files で!
if (!-f $request_filename) { # ファイルが存在しない場合
rewrite ^(.*)$ /index.php last; # index.php に書き換え
}
}
この if と rewrite の組み合わせは、try_files $uri /index.php; と同等か、多くの場合 try_files よりもパフォーマンスが劣り、理解しにくい挙動を招く可能性があります。Nginxの設定において、条件分岐が必要な場合は、まず try_files で実現できないか検討すべきです。
5.6. rewrite との比較
rewrite ディレクティブもURIの書き換えを行いますが、try_files の最後の uri 引数による内部リダイレクトとは少し性質が異なります。
try_files uri: 指定されたURIに新しいリクエストとして内部的にリダイレクトします。これにより、新しいURIに対して再度locationマッチングが行われます。これは、静的ファイルが見つからなかった場合に、別のlocationブロックで定義されたアプリケーションのフロントコントローラー (.php処理など) に処理を委譲する場合に非常に適しています。rewrite: 正規表現マッチングに基づいてURIを書き換えます。書き換えられたURIは、現在のlocationブロック内で再度処理されることもあれば (lastフラグ)、全く新しいリクエストとして扱われることもあります (breakやredirect/permanentフラグ)。rewriteはより強力で複雑なURI操作が可能ですが、設定が難しく、特に正規表現の使用はパフォーマンスにも影響を与える可能性があります。
多くの場合、単にファイルやディレクトリの存在チェックを行い、適切なフォールバック先(静的ファイル、インデックスファイル、フロントコントローラー、エラーページなど)を見つけるという目的であれば、try_files を使用する方がシンプルでパフォーマンスも良い選択肢となります。rewrite は、URIの特定のパターンを別のパターンに変換するなど、より複雑なマッピングが必要な場合に検討すべきです。
SPAの例で try_files $uri $uri/ /index.html; と記述しましたが、これを rewrite で実現しようとすると煩雑になります。
“`nginx
SPAの例を rewrite で実現 ( try_files より複雑になる)
location / {
root /var/spa/dist;
# ファイルかディレクトリが存在するかどうかをまず確認…
# しかし、rewrite はファイルシステム上の存在確認を直接行わない(できるが煩雑)
# 代わりに、すべてのリクエストを index.html に書き換える
rewrite ^ /index.html last;
}
問題点: 静的ファイル (CSS, JS, 画像など) も全て /index.html に書き換えられてしまう!
静的ファイルは除外するルールを追加する必要がある
location / {
root /var/spa/dist;
# まず静的ファイルを探す
location ~ .(css|js|jpg|png|gif)$ {
try_files $uri =404; # 静的ファイルが見つからなければ 404 で良い場合
}
# それ以外のパスは index.html に書き換え
rewrite ^ /index.html last;
}
これでもまだ完璧ではない(例: ディレクトリへのアクセスなど)
やはり try_files $uri $uri/ /index.html; の方がシンプルに意図を表現できる。
``try_files` が最も適しています。
このように、ファイルやディレクトリの存在チェックを伴うフォールバック処理には、
6. 高度な設定とパフォーマンス
6.1. 変数を使った動的なパス指定
try_files では、より動的なパスを指定するために変数を使うことがよくあります。前述の $uri, $uri/, $args 以外にも、例えばサブドメインごとに異なるドキュメントルートを使用するような場合に、ホスト名変数 ($host) と組み合わせてファイルパスを生成することも可能です。
“`nginx
server {
root /var/www/sites; # サイトのルートディレクトリの親
location / {
# ホスト名に対応するディレクトリを探し、その中の $uri を探す
# 例: example.com -> /var/www/sites/example.com/$uri を探す
try_files $host/$uri $host/$uri/ =404;
}
}
“`
この例では、www.example.com からのリクエストに対しては /var/www/sites/www.example.com/$uri を、blog.example.com からのリクエストに対しては /var/www/sites/blog.example.com/$uri を探すようになります。
6.2. try_files のパフォーマンスへの影響
try_files は、指定されたファイルパスやディレクトリパスに対してファイルシステム上の存在チェックを行います。これはI/O操作を伴います。
- I/Oオーバーヘッド: 引数で指定されたファイルやディレクトリが存在しない場合、Nginxはファイルシステムにアクセスして存在確認を行います。存在しないパスが多いほど、その分I/O操作が増え、オーバーヘッドが発生します。特にディスクI/Oが遅い環境では、これがパフォーマンスボトルネックになる可能性があります。
- キャッシュの利用: Nginx自身は
try_filesの結果をキャッシュする機能を持っていませんが、オペレーティングシステム (OS) がファイルシステムのメタデータ (ファイルやディレクトリの存在情報など) をキャッシュします。これにより、同じパスに対する連続した存在確認は高速に行われます。しかし、ファイルシステムの内容が頻繁に変更されるような環境では、OSのキャッシュが十分に効かない可能性があります。 - URI引数 (
uri) のオーバーヘッド: 最終引数にuriを指定した場合、それは内部リダイレクトとなり、新しいリクエストとして再度Nginxの処理パス (locationマッチングなど) を通ります。これは、ファイルを直接返す場合に比べてわずかにオーバーヘッドが増加します。しかし、このオーバーヘッドは通常小さく、アプリケーションのフロントコントローラーへの委譲など、その機能的なメリットの方がはるかに大きいことが多いです。 - 引数の順番: 存在確率が高いファイルパスを先に指定することで、不要な存在チェックを減らし、パフォーマンスを向上させることができます。例えば、静的ファイルがほとんどのリクエストで存在し、フロントコントローラーへのフォールバックは少ない、というシナリオであれば、
try_files $uri $uri/ /index.php?$args;のように、静的ファイル関連を先に記述するのが効率的です。
6.3. パフォーマンス最適化のヒント
- 必要最小限の引数:
try_filesには、本当に必要な候補パスだけを指定するようにしましょう。 - 確率の高い順に: 存在する確率が高いパスを左側に記述することで、不要なI/Oを削減できます。
- ファイルシステムのパフォーマンス:
try_filesのパフォーマンスは、基盤となるファイルシステムの速度に大きく影響されます。可能であれば、SSDなどの高速なストレージを使用することが推奨されます。ネットワークファイルシステム (NFSなど) をドキュメントルートに使用している場合、パフォーマンスが低下する可能性があるため注意が必要です。 aliasの使用:aliasを使うと、URIのパスとファイルシステム上のパスが異なる場合に、try_filesの引数をシンプルに保つことができます。ただし、aliasの末尾のスラッシュの有無など、ルールを正確に理解する必要があります。- 不要な
$uri/の省略: ディレクトリインデックスを探す必要がないロケーションであれば、$uri/の指定を省略することで、不要なディレクトリ存在チェックとインデックスファイル検索をスキップできます。
7. よくある間違いとトラブルシューティング
try_files は強力ですが、設定ミスにより予期せぬ挙動を引き起こすこともあります。ここではよくある間違いと、そのトラブルシューティング方法を紹介します。
7.1. root または alias の設定ミス
try_files の file 引数は root または alias からの相対パスとして解釈されるため、これらの設定が間違っていると、Nginxはファイルを正しい場所で見つけられません。
- 問題: ファイルが存在するはずなのに 404 になる。
- 原因:
rootやaliasが正しいディレクトリを指していない。または、try_filesの引数パスがroot/aliasと組み合わされた結果、意図しないパスになっている。 - 解決策:
nginx.confを確認し、serverブロックやlocationブロックにおけるrootまたはaliasの設定が正しいか確認する。特にaliasを使用している場合は、aliasでマップされるURIの末尾とaliasディレクティブの値の末尾のスラッシュの有無が期待通りのマッピングになっているか注意深く確認する。Nginxのerror_logをdebugレベルに設定すると、Nginxが実際にどのファイルパスを探しに行ったかを確認できます。
7.2. ファイルパスの記述ミス
try_files の引数として指定するファイルパスや変数に誤りがある場合も、ファイルが見つかりません。
- 問題: 例えば
/css/style.cssが見つからないが、try_files $uri ...と設定している。 - 原因:
try_filesの引数として指定したパス (例:$uri) が、root/aliasと組み合わされた結果、ファイルシステム上の正しいパス (/var/www/html/css/style.css) になっていない。または、変数に誤りがある。 - 解決策: 設定ファイルを再度確認し、
try_filesの引数がroot/aliasと正しく組み合わさって目的のファイルパスを指しているかを確認する。特に変数を使う場合は、変数に何が入るかを理解しておく必要があります ($uriは正規化されたパスでクエリストリングを含まないなど)。error_log debug;で確認するのが有効です。
7.3. ディレクトリを指定する際のスラッシュ忘れ
ディレクトリへのリクエスト時にインデックスファイルを探させたいにも関わらず、try_files の引数でディレクトリパスに末尾のスラッシュを付けていない。
- 問題:
/directory/へのアクセスで/directory/index.htmlを表示したいのに 404 になる。try_files $uri =404;と設定している。 - 原因:
$uriは/directory/というURIだが、try_files $uriはあくまで/var/www/html/directory/というファイルを探そうとする。ディレクトリとしては認識されない。 - 解決策: ディレクトリを存在チェックしてインデックスファイルを探させたい場合は、必ず末尾にスラッシュを付けて
$uri/のように記述する。try_files $uri $uri/ =404;のように設定すれば、ファイルとしての$uriがなければ、ディレクトリとしての$uri/を探しに行きます。
7.4. パーミッションの問題
Nginxワーカープロセスが、ドキュメントルートディレクトリや、try_files で指定されたファイル/ディレクトリへのアクセス権限を持っていない場合。
- 問題: ファイルが存在し、Nginx設定も正しそうだが、ファイルにアクセスできない (例えば 403 Forbidden または 404 Not Found)。
- 原因: Nginxワーカープロセスを実行しているシステムユーザー (通常
www-data,nginx, またはnobodyなど) が、ファイルシステム上の該当パスに対して読み取り権限を持っていない。 - 解決策: ファイルシステム上のドキュメントルートディレクトリとその配下のファイル/ディレクトリに対して、Nginxワーカープロセスを実行しているユーザーに必要な読み取り権限 (
r) と、ディレクトリの場合は実行権限 (x) を与える。例えばchown -R www-data:www-data /var/www/htmlやchmod -R o+rX /var/www/htmlといったコマンドを使用します。Nginxのerror_logにPermission deniedのようなエラーメッセージが出力されていることが多いです。
7.5. URI引数によるリダイレクトループ
try_files の最終引数に指定した uri が、再度同じ location ブロックにマッチし、かつファイル候補が見つからずに無限にリダイレクトを繰り返してしまう。
- 問題: ブラウザが応答しなくなる、またはNginxのCPU使用率が異常に高くなる。ログに同じような内部リダイレクトのメッセージが繰り返し出力される。
- 原因:
location / { try_files $uri /fallback; } location /fallback { try_files $uri /fallback; }のような、フォールバック先が自身または互いに呼び出し合うような設定になっている。 - 解決策: 内部リダイレクト先の
locationブロックでは、try_filesの最終引数を=codeにするか、またはtry_filesを使用しないように設定を見直す。例えば、フロントコントローラーへのリダイレクトであれば、そのlocationブロックはファイルシステム上の存在確認は行わず、直接FastCGIへ渡すような設定になっているべきです。
7.6. 最終引数にファイルパスを指定してしまい、内部リダイレクトにならない
最終引数に、内部リダイレクトさせたいURI (例: /index.php) ではなく、ファイルシステム上のパス (例: $document_root/index.php) を指定してしまう。
- 問題:
try_files $uri $uri/ $document_root/index.php;と設定したが、ファイルが見つからなかった場合にブラウザに/var/www/html/index.phpというファイル内容がそのまま表示されてしまうか、404 になる。PHPスクリプトとして実行されない。 - 原因:
try_filesの最終引数がファイルパスとして解釈され、Nginxはそのファイルをクライアントに返そうとする。ファイルタイプに応じたハンドリング (例: PHPスクリプトの実行) を行うためには、URIとして指定し、対応するlocationブロックに委譲する必要がある。 - 解決策: 最終引数には、内部リダイレクト先のURIを記述する。例:
try_files $uri $uri/ /index.php?$args;この/index.php?$argsというURIが、NginxのルーティングによってPHPを処理するlocationブロックに渡されます。
7.7. デバッグ方法: Nginxログの活用
Nginxが try_files でどのようにファイルを検索しているか、どのステップで処理が成功または失敗したかを確認するには、Nginxの error_log を info または debug レベルに設定することが非常に有効です。
“`nginx
nginx.conf または conf.d/*.conf 内の http, server, または location ブロックに記述
error_log /var/log/nginx/error.log info;
またはより詳細に
error_log /var/log/nginx/error.log debug;
``nginx -s reload
設定変更後、Nginxをリロード () するか再起動します。error.logを監視しながらリクエストを送信すると、Nginxがtry_filesの各引数をどのように評価し、ファイルシステム上のどのパスを探しに行ったか、そして最終的にどの処理に進んだかの詳細なログが出力されます。これにより、設定ミスやファイルパスの誤りを特定しやすくなります。デバッグが完了したら、ログレベルは元に戻すことを推奨します (通常はwarnまたはerror)。debug` レベルは大量のログを出力するため、本番環境での常時使用には適しません。
8. 具体的な設定例
ここでは、これまで説明してきた内容を踏まえ、いくつかの具体的な設定例を紹介します。
8.1. 静的サイトのシンプル設定
HTML、CSS、JS、画像などの静的ファイルを配信するシンプルな設定。
“`nginx
server {
listen 80;
server_name example.com www.example.com;
root /var/www/html;
index index.html index.htm; # ディレクトリインデックスを指定
location / {
# 1. リクエストURIに対応するファイルを探す
# 2. 見つからなければ、リクエストURIに対応するディレクトリを探し、その中の index ファイルを探す
# 3. どちらも見つからなければ 404 を返す
try_files $uri $uri/ =404;
}
# よくあるファイルタイプの直接配信 (try_files $uri で捕捉されるが、明示的に設定することも可能)
location ~ \.(css|js|jpg|jpeg|png|gif|ico|svg)$ {
expires 30d; # キャッシュ設定
add_header Cache-Control "public, no-transform";
# try_files $uri =404; # こちらも必要に応じて追加
}
# カスタム 404 ページ
error_page 404 /404.html;
location = /404.html {
internal;
root /var/www/html; # エラーページ用のルート(rootと同じで良い場合が多い)
}
}
“`
8.2. SPA (React, Vue, Angular) の設定例
静的ファイルが見つからなかった場合に、全てのエントリーポイントである /index.html にフォールバックさせる設定。
“`nginx
server {
listen 80;
server_name spa.example.com;
root /var/www/spa/dist; # SPAビルド出力ディレクトリ
index index.html; # エントリーポイント
location / {
# 1. リクエストURIに対応する静的ファイルを探す ($uri)
# 2. 見つからなければ、リクエストURIに対応するディレクトリを探し、index.html を探す ($uri/)
# 3. どちらも見つからなければ、/index.html に内部リダイレクトする
try_files $uri $uri/ /index.html;
}
# もし /index.html 自体が存在しなかった場合のフォールバック (必須ではないが安全のため)
location = /index.html {
try_files $uri =404; # index.html が見つからなければ 404 を返す
}
# 静的アセット (CSS, JS, 画像など) のキャッシュ設定 (任意)
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
# try_files $uri =404; # ここでもファイル存在チェックは有効
}
}
“`
8.3. WordPressのパーマリンク設定例 (index.php へのルーティング)
静的ファイル (テーマファイル、プラグインファイル、アップロード画像など) はそのまま配信し、それ以外のURIは index.php に委譲する設定。
“`nginx
server {
listen 80;
server_name wordpress.example.com;
root /var/www/wordpress;
index index.php index.html index.htm; # インデックスファイルの候補
location / {
# 1. リクエストURIに対応するファイルを探す ($uri)
# 2. 見つからなければ、リクエストURIに対応するディレクトリを探し、インデックスファイルを探す ($uri/)
# 3. どちらも見つからなければ、/index.php に内部リダイレクトし、元のクエリストリングを引き継ぐ ($args)
try_files $uri $uri/ /index.php?$args;
}
# .php ファイルの処理は FastCGI に委譲
location ~ \.php$ {
include snippets/fastcgi-php.conf; # FastCGI設定ファイル (ディストリビューションによる)
# 例: Debian/Ubuntu の場合
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
# 例: CentOS/RHEL の場合
# fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info; # PATH_INFO を渡す (必須ではないが一部プラグインで必要)
# セキュリティ対策: 許可されていない場所からの .php アクセスを拒否 (任意)
# if (!-f $document_root$fastcgi_script_name) { return 404; } # try_files $uri =404; と同等
}
# 隠しファイルやディレクトリへのアクセス拒否 (任意)
location ~ /\.(?!well-known) {
deny all;
}
}
``try_files $uri $uri/ /index.php?$args;
このWordPressの設定例では、の最終引数/index.php?$argsが重要です。これにより、例えば/hello-world/というパーマリンクへのアクセスは、静的ファイルとしてもディレクトリとしても見つからず、最終的に/index.php?/hello-world/(ただし$argsはクエリストリングのみなので実際には/index.phpとなるが、fastcgi_param SCRIPT_FILENAMEやREQUEST_URIで元のパスがPHPに渡される) に近い形でPHP-FPMに渡され、WordPressのindex.php` がリクエストURIを解析して適切なコンテンツを生成します。
8.4. 複数のフォールバックパスを指定する例
特定のファイルが存在しなければ、別の名前のファイルを探す、といった設定。
“`nginx
server {
root /var/www/app;
location / {
# 例: リクエストURIが /page/about の場合
# 1. /var/www/app/page/about を探す (ファイルまたはディレクトリ)
# 2. 見つからなければ、/var/www/app/page/about.html を探す (ファイル)
# 3. 見つからなければ、/var/www/app/page/index.html を探す (ファイル)
# 4. どれも見つからなければ、/var/www/app/page.html を探す (ファイル)
# 5. それも見つからなければ 404 を返す
try_files $uri $uri/ $uri.html $uri/index.html $uri.php =404; # いろいろ試す例
}
location ~ \.php$ {
# .php ファイルの処理
fastcgi_pass ...;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
“`
この例では、try_files の引数に複数の候補パスを順番に列挙しています。アクセス頻度や存在確率の高いものから順に記述するのが良いでしょう。
9. まとめ
Nginxの try_files ディレクティブは、ウェブサーバーにおけるリソース探索とフォールバック処理の核となる非常に強力で柔軟な機能です。
- クライアントからのリクエストURIに対して、指定された複数のファイルやディレクトリを順番に存在チェックします。
- 最初に存在するものがファイルであればそのファイルを返し、ディレクトリであればインデックスファイルを探して返します。
- 全ての候補が見つからなかった場合、最後の引数で指定されたURIへの内部リダイレクトを行うか、または指定されたHTTPステータスコードを返します。
- 静的ファイル配信、ディレクトリインデックス、SPAのルーティング、フロントコントローラーパターン、カスタムエラーページなど、様々なウェブサイトの構築において中心的な役割を果たします。
root,alias,location,index,error_pageといった他のNginxディレクティブと連携して使用されます。ifやrewriteと比較して、ファイル存在チェックに基づくフォールバック処理をシンプルかつ効率的に記述するのに優れています。- 多数の引数を指定したり、存在しないパスを多数チェックしたりすると、ファイルシステムI/Oのオーバーヘッドによりパフォーマンスに影響を与える可能性があるため、必要最小限の候補パスを効率的な順番で指定することが推奨されます。
- 設定ミスを防ぐためには、
root/aliasとtry_filesの引数の関係性を理解し、特にディレクトリ指定におけるスラッシュの有無や、URI引数による内部リダイレクトの挙動に注意が必要です。問題発生時には、Nginxのerror_logを活用してデバッグを行いましょう。
この記事を通して、try_files ディレクティブの詳細な使い方や設定方法、そしてその応用例について深く理解できたはずです。これらの知識を活かして、より堅牢で高性能なNginx設定を構築してください。