HEARTBEATS

mod_rewriteをnginxに移植するコツはifを使わないコト!

   

こんにちは。CTOの馬場です。

このエントリはnginxアドベントカレンダーの4日目です。

みんな大好き mod_rewrite をnginxに移植するコツをさらっと紹介します。

結論

  1. まず server とか location を使おうとする
  2. try_files など他の方法がないか考える
  3. どうしてもどうしてもダメなら mapif を使う

以上!

コツは「とにかく if を使わない」ことです。

手続き的な書き方から宣言的な書き方に頭を切り替えるとうまく馴染めると思います。

例: wwwありでアクセスがきたらwwwなしに転送する


server {
    listen 80;
    listen 443;
    server_name www.example.com;

    return 301 $scheme://example.com$request_uri;
}

rewrite 要りません。

例: サブディレクトリごとに違うupstreamに流す

/wp/〜php-fpm/redmine/〜unicorn に流したい場合。


upstream fpm {
    server 192.168.0.10;
}
upstream unicorn {
    server 192.168.0.11;
}
location /wp/ {
    proxy_pass http://fpm;
}
location /redmine/ {
    proxy_pass http://unicorn;
}

rewrite 要りません。

例: ファイルがあれば表示、なければbackendに流す


try_files $uri $uri/ @backend;

rewrite 要りません。

try_filesに @〜 は1つしか書けないので、 複数書きたい場合は飛んだ先でまた try_files して多段にしましょう。

例: 特定URLの接続元制限

/wp/〜 は 192.168.0.0/24、172.16.0.0/16からのみアクセス許可する場合


map $remote_addr $wpadmin {
    default 0;
    ~*192\.168\.0\. 1;
    ~*172\.16\. 1;
}
location /wp/ {
    if ($wpadmin = 0) {
        return 403;
    }
    ...
}

rewrite 要りません。

なお map 内の条件列挙では ~~* と条件分の間にスペースは要りません(あってはいけない)。

例: User-Agentごとの出し分け


upstream pc {
    server ...;
}
upstream sp {
    server ...;
}
upstream fp {
    server ...;
}
...
map $http_user_agent $ua_type {
    default "pc";
    ~*android "sp";
    ~*iphone "sp";
    ~*docomo "fp";
    ~*kddi "fp";
    ~*softbank "fp";
}
location / {
    proxy_pass http://$ua_type;
    ...
}

つらみ。

デバッグのコツ

色々方法がありますが、個人的には変数とアクセスログを利用するのが簡単でお勧めです。



log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for" "$trace"';

...

set $trace "";
location ~* \.(css|js|swf|jpeg|jpg|png|gif|ico) {
    set $trace "$trace,location1";
}
location /maintenance/ {
    set $trace "$trace,location2";
}
location / {
    set $trace "$trace,location3";
    rewrite .* /maintenance/;
}

このように設定して / にアクセスすると


127.0.0.1 - - [29/Nov/2014:22:54:06 +0900] "GET / HTTP/1.0" 200 612 "-" "curl" "-" ",location3,location2"

みたいな感じで出力されます。

おまけ

......とまぁこんな話が書籍になってそのうちリリースされるかもしれません(可能性)