- Locationの正規表現構文
実際の設定例:
<p>location = / {</p>
<p> # ルートパスを完全一致でマッチング、ドメイン直後に文字列が続く場合は対象外</p>
<p> [ configuration A ]</p>
<p>}</p>
<p>location / {</p>
<p> # 全てのリクエストは / で始まるため、このルールが適用される</p>
<p> # ただし正規表現や最長一致が優先される</p>
<p> [ configuration B ]</p>
<p>}</p>
<p>location /assets/ {</p>
<p> # /assets/ で始まるすべてのパスにマッチ、その後続処理が必要</p>
<p> # 正規表現が一致しない場合のみこの設定が有効</p>
<p> [ configuration C ]</p>
<p>}</p>
<p>location ~ /assets/Images {</p>
<p> # /assets/Images で始まるパスを正規表現でマッチ</p>
<p> # 後続チェックを行うが正規表現が優先される</p>
<p> [ configuration CC ]</p>
<p>}</p>
<p>location ^~ /media/ {</p>
<p> # /media/ で始まるパスにマッチ、正規表現検索を中断する</p>
<p> [ configuration D ]</p>
<p>}</p>
<p>location ~* \.(png|bmp|tiff)$ {</p>
<p> # png,bmp,tiff拡張子のリクエストをマッチ</p>
<p> # ただし/media/以下のファイルはconfig Dで処理される</p>
<p> [ configuration E ]</p>
<p>}</p>
<p>location /media/ {</p>
<p> # 文字列マッチ後、^~ の存在により処理が変化</p>
<p> [ configuration F ]</p>
<p>}</p>
<p>location /media/content {</p>
<p> # 最長一致で/media/contentにマッチ、^~ の影響を受ける</p>
<p> # FとGの順序は結果に影響しない</p>
<p> [ configuration G ]</p>
<p>}</p>
<p>location ~ /media/content/ {</p>
<p> # config DがなければGのマッチ後にこの正規表現が有効になる</p>
<p> [ configuration H ]</p>
<p>}</p>
<p>location ~* /scripts/.*/\.js</p>
=で始まる:完全一致モード^~で始まる:プレフィックス文字列マッチ、正規表現を無視~で始まる:大文字小文字を区別する正規表現~*で始まる:大文字小文字を区別しない正規表現/は汎用マッチ、他の条件がない場合に適用
優先順位:
(location =) > (location 完全パス) > (location ^~ パス) > (location ~,~* 正規表現) > (location 部分一致) > (/)
上記設定でのマッチ結果:
/→ config A (完全一致)/downloads/download.html→ config B (汎用マッチ)/media/1.png→ configuration D (プレフィックスマッチで停止)/media/content/detail→ config D (最長マッチ後のプレフィックスで停止)/assets/document.pdf→ config C (汎用マッチ)/assets/1.jpg→ configuration E (正規表現マッチ)/assets/Images.jpg→ config CC (最長マッチ後の正規表現)
実運用における推奨設定
実際の運用では以下の3つの基本ルールを設定することが望ましい:
<p># ドメイン直アクセスの高速化、ホームページへのアクセス頻度が高い場合に有効</p>
<p># バックエンドアプリケーションへ直接転送</p>
<p># 最初の必須ルール</p>
<p>location = / {</p>
<p> proxy_pass http://backend:8080/main</p>
<p>}</p>
<p># 静的ファイル処理、nginxの得意分野</p>
<p># ディレクトリマッチまたは拡張子マッチ、組み合わせ可能</p>
<p>location ^~ /static-content/ {</p>
<p> root /app/static/;</p>
<p>}</p>
<p>location ~* \.(svg|webp|avif|css|js|ico)$ {</p>
<p> root /app/resources/;</p>
<p>}</p>
<p># 動的リクエストの転送、静的ファイル以外は動的と見なす</p>
<p># 現代的なフレームワークでは.php,.jsp拡張子は稀</p>
<p>location / {</p>
<p> proxy_pass http://backend:8080/</p>
<p>}</p>
2. Rewrite機能の仕組み
Rewrite機能は、Nginxが提供するグローバル変数やユーザー定義変数を使用し、正規表現とフラグを組み合わせてURLの書き換えやリダイレクトを実現します。Rewriteはserver{}, location{}, if{}ブロック内で使用でき、ドメイン名以降のパラメータ以外の文字列にのみ作用します。例えば http://example.com/path/to/page.php?id=1¶m=value の場合、/path/to/page.php の部分のみが書き換え対象になります。構文は rewrite regex replacement [flag];
ドメイン名やパラメータ文字列を操作するには、グローバル変数を使用するか、proxy_passによるリバースプロキシを利用します。
RewriteとLocationはどちらもリダイレクト機能を持っていますが、主な違いはRewriteが同一ドメイン内のリソース取得パスを変更するのに対し、Locationはパスのアクセス制御やリバースプロキシの制御を行う点です。多くの場合、RewriteはLocationブロック内で記述され、実行順序は以下の通り:
- serverブロック内のrewrite命令を実行
- locationマッチングを実行
- 選択されたlocation内のrewrite命令を実行
途中でURIが書き換えられた場合、1-3のプロセスを繰り返し実行し、実際に存在するファイルが見つかるまで続きます。10回を超えるループの場合、500 Internal Server Errorを返します。
2.1 フラグの種類
last: Apacheの[L]相当、rewrite完了を示すbreak: 現在のサーバーの後続rewrite命令を停止redirect: 302一時リダイレクト、ブラウザアドレスバーに反映permanent: 301恒久リダイレクト、ブラウザアドレスバーに反映
301と302はステータスコードだけでなくリダイレクトURLも必要となるため、return命令では301,302を返せません。lastとbreakの違いは以下の通り:
- lastはserverやifブロックで使用、breakはlocationで使用
- lastは書き換え後のURLマッチを継続、breakは書き換え後のマッチを停止
- breakとlastはともに後続のrewrite命令の実行を阻止
2.2 if命令とグローバル変数
条件判定命令
構文はif(condition){...}で、指定された条件を評価します。真の場合、中括弧内のrewrite命令が実行されます。条件(condition)には以下のいずれかを指定可能:
- 単純な変数の場合、空値や0から始まる文字列はfalseとして扱われる
- 変数と文字列の比較には
=または!=を使用 ~は正規表現マッチ、~*は大文字小文字を区別しない、!~は大文字小文字を区別する否定
-fと!-fはファイル存在確認
-dと!-dはディレクトリ存在確認
-eと!-eはファイルまたはディレクトリ存在確認
-xと!-xは実行可能ファイル確認
例:
<p>if ($http_user_agent ~ Chrome) {</p>
<p> rewrite ^(.*)$ /chrome/$1 break;</p>
<p>} // UAがChromeを含む場合、/chrome/ディレクトリへリライト</p>
<p>if ($http_cookie ~* "session=([^;]+)(?:;|$)") {</p>
<p> set $session_id $1;</p>
<p> } // クッキーが正規表現に一致する場合、変数$session_idを設定</p>
<p>if ($request_method = PUT) {</p>
<p> return 406;</p>
<p>} // PUTメソッドの場合、406エラーを返す</p>
<p>if ($slow_request) {</p>
<p> limit_rate 20k;</p>
<p>} // スロー応答、$slow_requestはset命令で設定</p>
<p>if (!-f $request_file_path){</p>
<p> break;</p>
<p> proxy_pass http://127.0.0.1:9000;</p>
<p>} // リクエストファイルが存在しない場合、localhostへプロキシ</p>
<p>if ($query_params ~ action=delete){</p>
<p> rewrite ^ http://backup-site.com/ permanent;</p>
<p>} // クエリにaction=deleteを含む場合、永続リダイレクト</p>
<p>location ~* \.(mp4|avi|mov)$ {</p>
<p> valid_referers none blocked secure.example.com trusted.example.com;</p>
<p> if ($invalid_referer) {</p>
<p> return 403;</p>
<p> } // ホットリンク防止</p>
<p>}</p>
グローバル変数 if条件で使用可能な変数:
$query_args: リクエストパラメータ、$argsと同じ$content_length_header: リクエストヘッダのContent-length$content_type_header: リクエストヘッダのContent-Type$document_root_path: root命令で指定された現在のリクエスト値$request_host: リクエストホストヘッダ、ない場合はサーバー名$client_agent: クライアントエージェント情報$client_cookie: クライアントクッキー情報$bandwidth_limit: 接続速度制限に使用$method_type: クライアントリクエストメソッド、GETまたはPOST$client_ip: クライアントIPアドレス$client_port: クライアントポート$auth_user: Auth Basic Moduleで認証済みのユーザー名$current_file_path: 現在のリクエストファイルパス$protocol_scheme: HTTP方式(http、https)$protocol_version: 使用プロトコル、通常HTTP/1.0またはHTTP/1.1$server_ip: サーバーIPアドレス$server_hostname: サーバー名$server_port_num: リクエスト受信ポート$full_request_uri: パラメータを含む元のURI$current_uri: パラメータなしの現在URI$uri_path:$current_uriと同じ
例:http://domain.local:90/app1/module2/file.php
$server_hostname:domain.local
$server_port_num:90
$full_request_uri:http://domain.local:90/app1/module2/file.php
$uri_path:/app1/module2/file.php
$document_root_path:/var/webroot
$current_file_path:/var/webroot/app1/module2/file.php
2.3 正規表現パターン
.: 改行以外の任意の文字?: 0回または1回繰り返し+: 1回以上繰り返し*: 0回以上繰り返し\d: 数字にマッチ^: 文字列の開始$: 文字列の終了{n}: n回繰り返し{n,}: n回以上繰り返し[c]: 単一文字cにマッチ[a-zA-Z]: アルファベットにマッチ
括弧()で囲まれた部分は$1で参照、$2は2番目の括弧内を示します。正規表現では\による特殊文字のエスケープに注意が必要です。
2.4 Rewrite実装例
例1:
<p>http {</p>
<p> # 画像ログフォーマット定義</p>
<p> log_format image_access_log '[$time_local] ' $image_name ' ' $extension_type ' ' $bytes_transferred ' ' $response_status;</p>
<p> # リライトログ有効化</p>
<p> rewrite_log on;</p>
<p> server {</p>
<p> root /www/application;</p>
<p> location / {</p>
<p> # リライトルールログ</p>
<p> error_log logs/rewrite_debug.log notice;</p>
<p> # {}のためシングルクォート使用</p>
<p> rewrite '^/thumbnails/([a-z]{2})/([a-z0-9]{5})/(.*)\.(jpeg|webp|gif)$' /storage?target=$3.$4;</p>
<p> # "last"を使用するとset命令が実行されないため注意</p>
<p> set $image_name $3;</p>
<p> set $extension_type $4;</p>
<p> }</p>
<p> location /storage {</p>
<p> # 画像専用ログフォーマット</p>
<p> access_log logs/thumbnails.log main;</p>
<p> root /data/thumbnails;</p>
<p> # ファイル→ディレクトリ→最終URLの順に確認</p>
<p> try_files /$arg_target /placeholder404.html;</p>
<p> }</p>
<p> location = /placeholder404.html {</p>
<p> # 画像が存在しない場合の応答</p>
<p> return 404 "requested image not available\n";</p>
<p> }</p>
<p>}</p>
/thumbnails/ab/xyz12/sample.jpegのようなリクエストを/storage?target=sample.jpegにリライトし、location /storageにマッチします。/data/thumbnails/sample.jpegファイルの存在を確認し、あれば応答、なければtryfilesでimage404 locationにリライトして404を返します。
例2:
<p>rewrite ^/gallery/(.*)_(\d+)x(\d+)\.(webp|png|jpg)$ /processor/$1.$4?w=$2&h=$3? last;</p>
/gallery/photo_800x600.webpのリクエストを/processor/photo.webp?w=800&h=600にリライトし、locationマッチングを継続します。
例3: SSL関連のページ暗号化設定を参照してください。