プライム・ストラテジー「KUSANAGI」開発チームの石川です。
KUSANAGIでも採用している nginx は非常に高性能なWebサーバです。
しかし、Webサーバとして長い間使われてきた Apache HTTP Server と比較すると設定ファイルの記述が難しい部分があります。
Apache HTTP Serverでは .htaccess ファイルなどを利用して、リダイレクトやディレクトリ・ファイル毎の個別の処理を行えます。
この際には Directory や Files ディレクティブを用いて対象となるディレクトリやファイルを指定します。
これに相当する nginx の設定が location ディレクティブです。
今回は location ディレクティブの適用順番を例を含めて説明します。
location の書き方の種類
location ディレクティブと対象のURI (および正規表現) の間に指定する modifier によって、5種類 の書き方があります。
- 完全一致
= - 正規表現
~ - 大文字小文字を区別しない正規表現
~* - 正規表現を適用させない一致
^~ - modiferなしの一致
完全一致 =
文字通り URI が完全一致した際に適用される location です。
特定の処理を行う決まったファイルや決まったディレクトリに使われます。
正規表現 ~ と 大文字小文字を区別しない正規表現 ~*
URI のディレクトリ名やファイル名の条件として正規表現を用いて適用させる location です。
大文字小文字を区別しない (例えば .jpg と .JPG など) 場合は ~* を用います。
正規表現を適用させない一致 ^~
ちょっと特殊な location です。後で説明します。
modifierなしの一致
location と URI の間にmodiferを書かない場合です。一般的な location の書き方になります。
しかし、上記の4つの書き方によって影響を受けます。
location の適用の優先順位
location は以下の優先順位で評価されます。
- ネストされない限り、locationは最終的に一箇所のみが適用される
- 完全一致
=と正規表現~~*は 最初にマッチしたもの が優先される - modifierなしの一致と正規表現を適用させない一致
^~は 最長マッチしたもの が優先される - modifierなし、よりも、正規表現
~~*が優先される - 正規表現を適用させない一致
^~より下のURIには正規表現が適用されない - いずれの location にも一致しない場合、URIがディレクトリの場合は index に従って処理される
- いずれの location にも一致しない場合、URIはファイルとして処理される
ここでのポイントは 最初にマッチしたもの が優先される location と 最長マッチしたもの が優先される location があることです。
location の適用例
nginx の 公式ドキュメント の例をもとに説明します。
location = / {
[ configuration A ]
}
location / {
[ configuration B ]
}
location /documents/ {
[ configuration C ]
}
location ^~ /images/ {
[ configuration D ]
}
location ~* \.(gif|jpg|jpeg)$ {
[ configuration E ]
}- / :
- 完全一致
=/ により configuration A- ここでマッチが終了するので modifier なし / には進まない
- 完全一致
- /index.html :
- modifierなし / により configuration B
- /documents/document.html :
- modifierなし / にマッチ
- modifierなし /documents/ にマッチ
- modifierなしは 最長マッチ が優先されるため、modifierなし /documents/ により configuration C
- /images/1.gif :
- modifierなし / にマッチ
- 正規表現を適用させない一致
^~/images/ にマッチ - 大文字小文字を区別しない正規表現
~*\.(gif|jpg|jpeg)$にマッチするが、正規表現を適用させない一致^~/images/ の配下のURIのため、除外される- modifierなしと正規表現を適用させない一致
^~は 最長マッチ が優先されるため、 正規表現を適用させない一致^~/images/ により configuration D
- modifierなしと正規表現を適用させない一致
- /documents/1.gif :
- modifierなし / にマッチ
- modifierなし /documents/ にマッチ
- 大文字小文字を区別しない正規表現
~*\.(gif|jpg|jpeg)$にマッチ- modifierなし、よりも、正規表現
~*が優先されるため、 大文字小文字を区別しない正規表現~*\.(gif|jpg|jpeg)$により configuration E
- modifierなし、よりも、正規表現
詳細はnginx の 公式ドキュメント を参照してください。
location の適用のポイント
これを整理すると以下のようになります。
- 最初のマッチが優先されるlocation
- 完全一致
=- 特定のファイルのURIに対しての処理で使うこと
- 特定のディレクトリには使わない (indexディレクティブから /index.php を呼ぶことを期待する処理ができない)
- マッチさせたい優先順に前に書く
- 正規表現
~~*- 特定のファイルのURIに対しての処理で使うこと
- 特定のディレクトリには使わない (最初のマッチで適用されるため、modifierなしをオーバーライドしてしまう)
- マッチさせたい優先順に前に書く
- 完全一致
- 最長マッチが優先されるlocation
- 正規表現を適用させない一致
^~- 特定のディレクトリのURIに対しての処理で使うとよい
- 特定のファイルには使わない (indexディレクティブから /index.php を呼ぶことを期待する処理ができない)
- マッチしたパス以下には正規表現
~~*location が適用されない - 正規表現
~~*location から除外したいディレクトリのみを書くこと - できるだけ厳密なマッチを書く
- modifierなし
- 特定のディレクトリのURIに対しての処理で使うとよい
- 特定のファイルには使わない (正規表現が優先されてしまう)
- 適用後に正規表現
~~*が適用されてしまう場合があることを忘れないこと - できるだけ厳密なマッチを書く
- 正規表現を適用させない一致
- どこにも一致しなかった場合
- ディレクトリの場合は index ディレクティブに従う
- その結果 index.php で処理されることになると、index.phpをURIとしてマッチを再度やり直す
- そうでなければ、ファイルとして扱う
- ディレクトリの場合は index ディレクティブに従う
また location 内に try_files ディレクティブが存在すると、 /index.php のように再度URIのマッチが実行される場合があります。
KUSANAGI の nginx 設定ファイル
以下は KUSANAGI でプロビジョンした WordPress 用プロファイルの設定ファイルの抜粋です。
また、注釈としてコメントを入れています。
server {
# HTTP用の設定
listen 80;
listen [::]:80;
# 途中省略
include conf.d/505.inc;
include conf.d/favicon.inc;
include conf.d/acme.inc;
include conf.d/profile.wp.inc;
include conf.d/static.inc;
}
server {
# HTTPS用の設定
include conf.d/ssl_listen.inc;
# 途中省略
include conf.d/505.inc;
include conf.d/favicon.inc;
include conf.d/acme.inc;
include conf.d/profile.wp.inc;
include conf.d/static.inc;
include conf.d/fcache_purge.inc;
}KUSANAGI の nginx の設定ファイルでは上記のように include ディレクティブを用いて、共通となる設定ファイルを外出しにして読み込む仕組みになっています。
location については、HTTPとHTTPSで処理が同じため、ここではHTTPを例に説明します。
まず、上記で include している設定ファイルの中で location に関する部分を抜粋しました。
文中にコメントで解説を入れています。
server {
# HTTP用の設定
listen 80;
listen [::]:80;
# 途中省略
# include conf.d/505.inc;
location = /50x.html {
# A
# /50x.html は Nginxのエラーページのテンプレートです。
# 省略
}
# include conf.d/favicon.inc;
location = /favicon.ico {
# B
# /favicon.ico はブラウザのブックマークに表示されるアイコンです。
# 省略
}
# include conf.d/acme.inc;
location ~* /\.well-known {
# C
# Let's Encrypt のSSL証明書を設定する際に認証情報 (challenge file) が格納される場所です。
# 省略
}
# include conf.d/profile.wp.inc;
index index.php index.html index.html;
# URLがディレクトリの場合には、ディレクトリ内で上記の順にファイルを検索して表示します。
location / {
# D
# アクセスされた際のデフォルトの設定です。
# まず URL をファイルとして解釈して存在すればそれを表示します。
# ファイルが存在しなければ、ディレクトリとして解釈し、上記 index に従ってファイルを探します。
# それもなかった場合には /index.php (WordPressのエントリーポイント) を実行します。
try_files $uri $uri/ /index.php?$args;
}
location ~* /\. {
# E
# .htaccess や .htpasswd など . から始まるファイルです。
# セキュリティ上の理由からアクセスできないようにします。
# 省略
}
location ~* /(?:uploads|files)/.*\.php$ {
# F
# WordPressの uploads ディレクトリなど画像などが配置されるディレクトリに
# PHPファイルが置かれても実行できないようにします。
# 省略
}
location ~* /wp-login\.php|/wp-admin/((?!(admin-ajax\.php|images/)).)*$ {
# G
# WordPressの管理画面のURLです。
# 途中省略
location ~ [^/]\.php(/|$) {
# H
# 拡張子が .php のものは fastcgi (php-fpm) で処理します。
# 省略
fastcgi_pass 127.0.0.1:9000;
# 省略
}
}
location ~ [^/]\.php(/|$) {
# I
# 拡張子が .php のものは fastcgi (php-fpm) で処理します。
# 省略
fastcgi_pass 127.0.0.1:9000;
# 省略
}
# include conf.d/static.inc;
location ~* \.(jpg|jpeg|gif|png|webp|css|js|swf|ico|pdf|svg|eot|ttf|woff|woff2)$ {
# J
# 画像やPDF、Webフォントといった静的ファイルです。
# 省略
}
}- 最初のマッチが優先されるlocation
- 完全一致
=- A
- B
- 正規表現
~~*- C
- E
- F
- G
- G の配下
*.phpでは H が適用され I が適用されることがない
- G の配下
- H
- I
- J
- 完全一致
- 最長マッチが優先されるlocation
- 正規表現を適用させない一致
^~- なし
- modifierなし
- D :
try_filesによって以下のようになる- ディレクトリの場合は
indexを参照し index.php ならそのURIで再マッチ- I になる場合がほとんどと考えられる
- ファイルの場合はそのまま表示
- ディレクトリもファイルのない場合は
/index.phpで処理されるため、そのURIで再マッチ- I になる場合がほとんどと考えられる
- ディレクトリの場合は
- D :
- 正規表現を適用させない一致
例えば /.well-known/img.jpg というURIは、一見 J に該当しそうですが、正規表現は最初のマッチが優先されるため C で処理されます。
同様に、 /.well-known/test.php というURIは、一見 I に該当しそうですが、正規表現は最初のマッチが優先されるため C で処理されます。
また /.hidden.jpg というURIは、 J ではなくて先にマッチする E で処理されます。
このように、ディレクトリを正規表現でマッチさせると、その下のファイルを拡張子で判定できない場合があります。
まとめ
KUSANAGI の nginx の設定ファイルに location を追加した際に思ったように動作しない場合は、既存の location の記述が優先されているためです。
ポイントに記載したルールを参考に見直してみてください。
- 完全一致、正規表現は最初のマッチが優先されるので、前に記述する
- modifierなし は最長マッチが優先されるので、他にマッチしている長い location がないかチェックする
- location の入れ子では、入れ子の中の location よりも外の location にマッチすることがある
また、Nginx の location でアクセス制限をかける際には間違いやすい落とし穴があります。こちらに関しては 別に記事 を書いていますので合わせて読んで理解を深めてください。






