簡単そうに見えたのだが思い通りにいかない.
優先順位というか, 処理順序というか. ここらの話.
location = / { # matches the query / only. [ configuration A ] } location / { # matches any query, since all queries begin with /, but regular # expressions and any longer conventional blocks will be # matched first. [ configuration B ] } location /documents/ { # matches any query beginning with /documents/ and continues searching, # so regular expressions will be checked. This will be matched only if # regular expressions don't find a match. [ configuration C ] } location ^~ /images/ { # matches any query beginning with /images/ and halts searching, # so regular expressions will not be checked. [ configuration D ] } location ~* \.(gif|jpg|jpeg)$ { # matches any request ending in gif, jpg, or jpeg. However, all # requests to the /images/ directory will be handled by # Configuration D. [ configuration E ] }
Nginx location priority - Stack Overflow
なので公式 wiki/recipe を見ながら少し整理.
公式にて書式はこう.
Syntax: location [ = | ~ | ~* | ^~ ] uri { ... }
複数のlocationブロックがある場合, リクエストのURL内該当文字列に対して優先順位の順番にマッチを確認していき, 最初にマッチしたロケーション設定(処理)ひとつが反映される.
1.「=」完全一致
2.「^~」前方検索 (マッチ文字列の長い順)
3.「~」正規表現 (記述順)
4.「~*」正規表現 (記述順・大小文字を考慮しない)
5.「(なし)」前方検索 (マッチ文字列の長い順)
これに加えて, それぞれの設定(処理)自体の優先順位を考慮しておかないと, 「アクセス拒否したつもりが丸出し」や「PHPスクリプトのダウンロード公開」などとなってしまう.
1. 特殊ファイルのログ制御
2. ディレクトリ単位のアクセス拒否
3. ファイル単位のアクセス拒否
4. PHPファイルの実行 (PHP-FPM)
5. 静的ファイルのキャッシュ期限の設定
6. フロントコントローラへのリクエスト付け替え
これら2つの優先順位を考慮にいれながら書かれている公式wiki/recipeの設定は, ある程度おおまかにパターン化できる.
1.「=」特殊ファイルのログ制御
2. 「^~」ディレクトリ単位のアクセス拒否
3.「~」ファイル単位のアクセス拒否
4.「~」PHPファイルの設定・実行 (PHP-FPM)
5.「~*」静的ファイルのキャッシュ期限の設定
6.「なし」フロントコントローラへのリクエスト付け替え
頻出しそうなのを順序を守って箇条書きに.
# 1. specific files location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { allow all; log_not_found off; access_log off; } # 2. deny directories location ^~ /conf/ { return 403; } # 3. deny files location ~ (^|/)\. { return 403; } location ~ \.(txt|log)$ { allow 192.168.0.0/16; deny all; } # 4. php scripts location ~ [^/]\.php(/|$) { fastcgi_split_path_info ^(.+?\.php)(/.*)$; if (!-f $document_root$fastcgi_script_name) { return 404; } fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; include fastcgi_params; } # 5. static content files location ~* \.(?:ico|css|js|gif|jpe?g|png)$ { expires max; } # 6. others(internal rewrite) location / { try_files $uri $uri/ index.php; }
実際はこれらに加えてさらに, 内部/外部での リライト/リダイレクトなどを記述して location 設定を複数またいでいくことになると, 大量に記述された apache mod_rewrite 設定のように直感的に設定できなくなっていくので locationブロックに関してはテンプレ化しておくのがいいように思う.
そもそもは「if」や「locationを使った入れ子」で混乱したので.
nginxのlocation設定について、優先順位の基本と意外な罠
if ($request_uri = /) { set $test A; } if ($host ~* teambox.com) { set $test "${test}B"; } if ($http_cookie !~* "auth_token") { set $test "${test}C"; } if ($test = ABC) { proxy_pass http://teambox-cms.heroku.com; break; }
nginx hack for multiple conditions
手をつける前に, ある程度の歴史や経緯を分かっておく必要があったかな.
まあいいか.
みんなも reload したらチェックしてみよう.
$ curl -L http://yourhost.com/ -o /dev/null \ -w '%{http_code} %{content_type} %{size_download} %{url_effective}\n' \ -s 200 text/html; charset=UTF-8 1334 http://yourhost.com/