Dev Study
← Webを支えるソフトウェア
レッスン 5 / 13·約 7 分·第3期 Webを支えるソフトウェア

Nginx設定を読む — locationはどれが選ばれるか

リクエストがアプリケーションに届くまで
  1. ブラウザURL入力
  2. DNS名前→IP
  3. ルータ経路選択
  4. ロードバランサ振り分け
  5. Nginx受け口今ここ
  6. アプリ処理
  7. DB保存

受け口に届いたリクエストを、設定のどのブロックが処理するかを決める段です。プロセス構成ではなく設定構文だけを扱います。

まず結論

最長一致した prefix は勝者ではなく「記憶」されるだけの暫定候補です。後から検査される正規表現が一致すれば逆転されます。

正規表現には最長一致も最具体一致もなく、先に書かれた方が勝ちます。第18週のルーティング表と違い、記述順が結果を変えます。

? 読む前に予測

次の設定に `/sel/long/a.jpg` が来ました。どれが使われるでしょうか。 location /sel/long/ { ... } ← prefix(最長一致する) location ~* \.(gif|jpg)$ { ... } ← 正規表現

当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。

抽象原理

prefix の最長一致は、まだ結果ではない

location 選択はよく「上から順に見て最初に当たったもの」と説明されます。これは誤りです。 公式が定める順序はこうです。

location が選ばれるまで
① prefix を全部見る最長一致を「記憶」○ まだ採用しない
② 記憶したものが `^~`なら、ここで確定○ 正規表現を検査しない
③ 正規表現設定ファイルの出現順○ 最初に一致したら採用して終了
④ predicate (1.31.5〜)出現順○ 一致すれば採用
⑤ どれも一致しない①で記憶したものへ○ prefix を採用
↓
①は候補の確保にすぎず、採用が決まるのは③④を通り抜けた後
  • ・`=` の完全一致は①の prefix 検査の中で見つかれば、その場で探索全体を終わらせる(②③④へ進まない)

肝心なのは①です。公式は最長一致した prefix を selected and remembered(選んで記憶する)と書きます。

具体実物

実機で逆転が起きる

nginx/1.30.4 での実測です。

設定(抜粋)と、実際に返ってきた応答設定ファイル
location /sel/long/ { return 200 "C longer-prefix\n"; }
location ^~ /sel/images/ { return 200 "D caret-tilde\n"; }
location ~* \.(gif|jpg)$ { return 200 "E regex-first-in-file\n"; }
location ~ \.jpg$ { return 200 "F regex-second-in-file\n"; }
 
/sel/long/a.jpg -> E ← 最長prefix C が逆転された
/sel/images/a.gif -> D ← ^~ なので正規表現が検査されない
/a.gif -> E ← F ではなく、先に書かれた E

/sel/long/a.jpg は prefix /sel/long/ に最長一致します。それでも **E が使われました。**記憶されていた C が正規表現に上書きされたのです。

.jpg には E と F が一致しますが、勝つのは 先に書かれた E。F の方が限定的でも関係ありません。

Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used.

**正規表現に「最長一致」も「最具体一致」も存在しません。**あるのは順序だけです。

✓ ここまでの確認

`.jpg` に一致する正規表現 location が2つあります。1つ目は `~* \.(gif|jpg)$`、2つ目は `~ \.jpg$` です。より限定的なのは2つ目ですが、選ばれるのはどちらですか。

⇄ 2つを見比べる
具体例 A

ルーティング表の最長一致(第18週)

宛先 192.168.1.130 には3行すべてが当てはまり、最も細かい /25 が選ばれます。重要なのは、この判定が行の順序に一切依存しないことです。

当てはまる3行から1つを選ぶ表
行 一致ビット数 結果
0.0.0.0/0 0 負ける
192.168.1.0/24 24 負ける
192.168.1.128/25 25 採用(確定)
具体例 B

nginx の location

`/sel/long/a.jpg` には prefix と正規表現の両方が当てはまります。最長一致するのは prefix ですが、採用されるのは正規表現です。しかも正規表現が2つあれば、先に書かれた方が勝ちます。

当てはまる候補から1つを選ぶ表
候補 土俵 結果
/sel/long/ prefix 最長一致 → 記憶(暫定)
~* \.(gif|jpg)$ 正規表現 先に書かれている → 採用
~ \.jpg$ 正規表現 後に書かれている → 検査されず

どちらも「当てはまる候補が複数あるとき1つを選ぶ」仕組みです。共通している部分はどこまでで、どこから違うでしょうか。

「設定ファイル/表の行を並べ替えたら、結果は変わるか」を両方で考えてみてください。

✓ ここまでの確認

「`^~` を付けた location は、見つかった瞬間に探索を打ち切る」という説明は正確ですか。

この章のまとめ

  • 最長一致した prefix は selected and remembered — 採用ではなく暫定候補。正規表現に逆転されうる。
  • 正規表現は出現順に検査され最初の一致で終了。最長一致も最具体一致も無い。
  • ^~ が省略を起こすのは「最長一致した prefix が結果的に ^~ だったとき」。即座に止まるのは =。
  • 第18週のルーティング表との決定的な違いは、記述順が結果を変えること。

自分の現場で確かめる

読んだだけでは身につきません。手元の環境で実際に見てみてください。

環境:

理解度チェック

読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。

問題 1 / 4正解: 0

「nginxの location は上から順に評価され、最初に当たったものが使われる」という説明の評価として正しいものはどれですか。

用語集(6語)
prefix location
修飾子なし、または `=` `^~` を伴う、前置文字列で定義された location。この土俵では最も長く一致したものが「記憶」される。
正規表現 location
`~`(大文字小文字を区別)/`~*`(区別しない)を伴う location。出現順に検査され最初の一致で終わる。長さや具体性は考慮されない。
`^~`
最長一致した prefix location がこの修飾子を持っていた場合に、正規表現と predicate location を検査しない。「見つかった瞬間に打ち切る」ではない。
`=`
URIとの完全一致を定義する修飾子。一致が見つかった時点で探索全体が終了する。入れ子の location を持てない。
named location (`@name`)
`@` を前置して定義する location。通常のリクエスト処理には使われず、リクエストの転送先として使われる。入れ子にできない。
predicate location (`$variable`)
nginx 1.31.5 で追加された形式。変数の値が空でなく `0` でもないときに一致する。正規表現の後に出現順で検査される。