Nginxのlocationマッチングルールを実例で解説
Nginxの設定を調整してリロードしたのに、locationブロックが適用されない理由に悩んだことはありませんか? 静的ファイルのリクエストがPHPハンドラに渡されたり、APIルートがキャッチオールに吸収されたりすることがあります。原因は多くの場合、Nginxのlocationマッチングアルゴリズムにあります。見た目ほど単純ではありません。
このガイドでは、Nginxがどのようにlocationブロックを選択するのかを、実際にテストできる例を交えて詳しく解説します。読み終える頃には、どのブロックが優先されるのか、そしてその理由が正確にわかるでしょう。
Nginxのlocationマッチングの仕組み
リクエストが到着すると、NginxはURIを定義されたすべてのlocationブロックと比較します。マッチングプロセスは特定の順序に従います:
- 完全一致 (
=) — 最優先。見つかれば、Nginxはそこで停止し、それを使用します。 - 最長前方一致 — Nginxは最も長く一致する前方一致locationを記憶します。
- 正規表現一致 (
~または~*) — 出現順にチェックされます。最初に一致した正規表現が優先され、前方一致を上書きします(^~が使用されていない限り)。 ^~付き前方一致 — 最長一致の前方一致に^~が付いている場合、Nginxは正規表現チェックをスキップしてそれを使用します。- 正規表現に一致するものがない場合、最長前方一致が使用されます。
これがコアアルゴリズムです。実際の動作を見てみましょう。
location修飾子:クイックリファレンス
| 修飾子 | 構文 | マッチタイプ | 優先度 |
|---|---|---|---|
= | location = /path | 完全一致 | 最高 |
^~ | location ^~ /path | 前方一致(正規表現なし) | 高 |
~ | location ~ \.php$ | 正規表現(大文字小文字区別) | 中 |
~* | location ~* \.(jpg|png)$ | 正規表現(大文字小文字無視) | 中 |
| なし | location /path | 前方一致 | 最低 |
実例1:静的ファイル vs. PHP
次の一般的な設定を考えてみましょう:
server {
listen 80;
server_name example.com;
location / {
root /var/www/html;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
}
/index.phpへのリクエストは正規表現\.php$に一致するため、PHP-FPMに渡されます。/logo.pngへのリクエストは正規表現に一致しないため、前方一致/にフォールバックし、静的ファイルを配信します。簡単ですよね?
しかし、/uploads/photo.phpを静的ファイルとして配信したい場合(実際には画像である可能性がある)、完全一致を追加できます:
location = /uploads/photo.php {
root /var/www/html;
}
これで、その完全一致が正規表現よりも優先されます。
実例2:前方一致と正規表現によるAPIルーティング
/api/配下にAPIがあり、すべてのリクエストをバックエンドにプロキシしたいが、静的レスポンスを返すヘルスチェックだけは例外にしたいとします。
location = /api/health {
return 200 "OK";
}
location /api/ {
proxy_pass http://backend;
}
location ~ ^/api/v[0-9]+/special {
proxy_pass http://special-backend;
}
/api/healthを追跡してみましょう:完全一致が優先され、200を返します。/api/usersの場合:完全一致なし、正規表現なし(specialに一致しない)なので、最長前方一致/api/が使用されます。/api/v1/specialの場合:正規表現が一致するため、前方一致を上書きし、special-backendに転送されます。
これは正規表現が前方一致を上書きできることを示しています。前方一致を常に優先させたい場合は、代わりに^~を使用します。
実例3:^~の力
/static/ディレクトリに、たとえ.phpで終わっていてもPHPで処理されるべきではないファイルがあるとします。^~を使用すると、Nginxが正規表現のlocationをチェックしないようになります。
location ^~ /static/ {
root /var/www/html;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
/static/script.phpへのリクエストは前方一致^~ /static/に一致します。^~のおかげで、Nginxは正規表現チェックをスキップし、ファイルを直接配信します。^~がなければ、正規表現が一致し、PHP-FPMがそれを実行してしまうでしょう—これは潜在的なセキュリティリスクです。
よくある落とし穴と回避方法
- 正規表現の順序が重要: Nginxは設定に出現する順序で正規表現locationをチェックします。より具体的なパターンを先に配置しましょう。
- 末尾スラッシュの欠落:
location /apiとlocation /api/は異なります。前者は/apiと/apixに一致し、後者は/api/と/api/usersに一致します。正確に書きましょう。 - 前方一致の重複: 最長前方一致が優先されるため、
/api/v1/usersに対してはlocation /api/v1がlocation /apiより優先されます。 - 静的アセットに
^~を忘れる: 正規表現が静的ファイルリクエストを乗っ取るのを防ぐために使用します。 - 大文字小文字の区別:
~は大文字小文字を区別し、~*は区別しません。ファイル拡張子には~*を使用しましょう。
locationマッチングのデバッグ
どのlocationが使用されているかわからない場合は、Nginxでデバッグログを有効にします。serverブロックにerror_log /var/log/nginx/error.log debug;を追加し、リロードしてログを確認します。test location: "/api/users"やusing configuration "/api/"のような行が表示されます。
あるいは、各locationに一時的にreturn 200 "matched: /api/";を追加して、どれが応答するかを確認する方法もあります。
FAQ
Nginxのlocation修飾子の優先順位は?
完全一致(=)が最高で、次に^~付きの最長前方一致、次に順序に従った正規表現(~または~*)、最後に^~なしの最長前方一致です。
正規表現locationは前方一致locationを上書きできますか?
はい、前方一致locationが^~を使用していない限り可能です。正規表現locationは最長前方一致の後にチェックされ、一致すれば通常の前方一致よりも優先されます。
特定のファイルだけに一致するlocationを設定するには?
=を使った完全一致を使用します。例:location = /favicon.ico。これにより、その正確なURIのみが一致します。
Nginx設定をマスターする
locationマッチングを理解することは、信頼性の高いNginx設定の鍵です。設定はnginx -tでテストし、疑問がある場合はデバッグログを使用しましょう。Nginxログを扱い、トラフィックパターンを分析する必要がある場合は、Nginx Log Analyzerを試して、ログを迅速に解析・可視化してください。