NginxのLocation設定とRewriteルールの実装方法

  1. 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&param=value の場合、/path/to/page.php の部分のみが書き換え対象になります。構文は rewrite regex replacement [flag];

ドメイン名やパラメータ文字列を操作するには、グローバル変数を使用するか、proxy_passによるリバースプロキシを利用します。

RewriteとLocationはどちらもリダイレクト機能を持っていますが、主な違いはRewriteが同一ドメイン内のリソース取得パスを変更するのに対し、Locationはパスのアクセス制御やリバースプロキシの制御を行う点です。多くの場合、RewriteはLocationブロック内で記述され、実行順序は以下の通り:

  1. serverブロック内のrewrite命令を実行
  2. locationマッチングを実行
  3. 選択された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の違いは以下の通り:

  1. lastはserverやifブロックで使用、breakはlocationで使用
  2. lastは書き換え後のURLマッチを継続、breakは書き換え後のマッチを停止
  3. 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関連のページ暗号化設定を参照してください。

タグ: nginx location rewrite 正規表現 リバースプロキシ

6月26日 17:34 投稿