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設定を構築してください。