[nginx] リバースプロキシ(+キャッシュサーバ)とWEBサーバを1台で実現する


nullpopopo96x96nginxをWEBサーバに、あるいはリバースプロキシにして後ろにApacheやアプリケーションサーバを運用している人は多いと思いますが、nginx1台だけでリバースプロキシ(+キャッシュ)とWEBサーバを実現できないものか、というテーマでやってみました。

ユーザからのリクエストは以下の順に受け取られます。

[ ユーザの{PC,スマホ}] -> [nginxのリバースプロキシ] -> [nginx (WEBサーバ)] -> [アプリケーション]


構築した環境は以下の通りです。
OS: CentOS release 6.4 (Final)
nginx: nginx-1.4.1-1.el6.ngx.x86_64 (nginxリポジトリからインストール)

nginxは最新のパッケージが入手できるので、nginx公式からリポジトリファイルをコピペして作ってインストールすることをおすすめします。あと、リーダー曰く nginxの古いバージョンはDNSのTTLを無視するっぽい ので、epelからインストールしないほうがよさげです。

[ (っ´∀`)っ@友の会 ~]$ sudo yum install nginx
(中略)
Dependencies Resolved

========================================================================================================================================================================
 Package                              Arch                                  Version                                          Repository                            Size
========================================================================================================================================================================
Installing:
 nginx                                x86_64                                1.4.1-1.el6.ngx                                  nginx                                311 k

Transaction Summary
========================================================================================================================================================================
Install       1 Package(s)

Total download size: 311 k
Installed size: 770 k
Is this ok [y/N]: y
(中略)
----------------------------------------------------------------------

Thanks for using NGINX!

Check out our community web site:
* http://nginx.org/en/support.html

If you have questions about commercial support for NGINX please visit:
* http://www.nginx.com/support.html

----------------------------------------------------------------------
  Verifying  : nginx-1.4.1-1.el6.ngx.x86_64                                                                                                                         1/1 

Installed:
  nginx.x86_64 0:1.4.1-1.el6.ngx                                                                                                                                        

Complete!

上記の方法でインストールしたnginxですが、全体の設定を /etc/nginx/nginx.conf に、キャッシュの設定を /etc/nginx/conf.d/000_PROXY.conf に、バーチャルホストの設定を /etc/nginx/conf.d/100_VHOSTS.conf に施すことにします。 nginx.conf ですが、 worker_processes の調整をするくらいで、 log_format や gzip の設定などはお好みで構いません。

000_PROXY.conf ですが、今回はバーチャルホストが2つある前提でこんなconfigにしてみました。1つ目のサイト SITE1 は同じサーバの20001番ポートで、SITE2 は 20002番ポートで待ち受けることにします。

proxy_cache_path /var/cache/nginx/static_file_cache levels=1:2 keys_zone=cache_static_file:128m inactive=7d max_size=480m;
proxy_temp_path /var/cache/nginx/temp;

upstream LB_WEB_001{
    server    127.0.0.1:20001;
}

upstream LB_WEB_002{
    server    127.0.0.1:20002;
}

###
### http://SITE1/
###
server {
    listen       80;
    server_name  SITE1;
    proxy_set_header        Host            $host;
    proxy_set_header        X-Real-IP       $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;

    location / {
    client_max_body_size 100M;
    proxy_pass  http://LB_WEB_001;
    set $do_not_cache 0;
    if ($request_method != GET) {
      set $do_not_cache 1;
    }
    if ($uri !~* ".(jpg|png|gif|jpeg|css|js|swf|pdf|html|htm)$") {
      set $do_not_cache 1;
    }
    proxy_no_cache $do_not_cache;
    proxy_cache_bypass $do_not_cache;
    proxy_cache cache_static_file;
    proxy_cache_key $scheme$host$uri$is_args$args;
    proxy_cache_valid 200 2h;
    proxy_cache_valid any 1m;
    break;
    }
    error_page  404              /404.html;
    location = /404.html {
        root   /usr/share/nginx/html;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

###
### http://SITE2/
###
server {
    listen       80;
    server_name  SITE2;
    proxy_set_header        Host            $host;
    proxy_set_header        X-Real-IP       $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;

    location / {
    client_max_body_size 100M;
    proxy_pass  http://LB_WEB_002;
    set $do_not_cache 0;
    if ($request_method != GET) {
      set $do_not_cache 1;
    }
    if ($uri !~* ".(jpg|png|gif|jpeg|css|js|swf|pdf|html|htm)$") {
      set $do_not_cache 1;
    }
    proxy_no_cache $do_not_cache;
    proxy_cache_bypass $do_not_cache;
    proxy_cache cache_static_file;
    proxy_cache_key $scheme$host$uri$is_args$args;
    proxy_cache_valid 200 2h;
    proxy_cache_valid any 1m;
    break;
    }
    error_page  404              /404.html;
    location = /404.html {
        root   /usr/share/nginx/html;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

次に、 100_VHOSTS.conf はこう書きます。

#
# http://SITE1/
#
server {
    listen       127.0.0.1:20001;
    server_name  SITE1;
    proxy_set_header        Host            $host;
    proxy_set_header        X-Real-IP       $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    access_log  /home/vhosts/SITE1/logs/access_log  main;
    error_log  /home/vhosts/SITE1/logs/error_log;
    location / {
        root   /home/vhosts/SITE1/public_html;
        index  index.php index.html index.htm;
    }
    location ~ .php$ {
        root   /home/vhosts/SITE1/public_html;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root/$fastcgi_script_name;
        include        fastcgi_params;
    }
    error_page  404              /404.html;
    location = /404.html {
        root   /usr/share/nginx/html;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

#
# http://SITE2/
#
server {
    listen       127.0.0.1:20002;
    server_name  SITE2;
    proxy_set_header        Host            $host;
    proxy_set_header        X-Real-IP       $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    access_log  /home/vhosts/SITE2/logs/access_log  main;
    error_log  /home/vhosts/SITE2/logs/error_log;
    location / {
        root   /home/vhosts/SITE2/public_html;
        index  index.php index.html index.htm;
    }
    location ~ .php$ {
        root   /home/vhosts/SITE2/public_html;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root/$fastcgi_script_name;
        include        fastcgi_params;
    }
    error_page  404              /404.html;
    location = /404.html {
        root   /usr/share/nginx/html;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

ここまでできたら、ドキュメントルートやログのディレクトリを作成するのと、忘れてはいけないのはキャッシュディレクトリの作成です。

[ (っ´∀`)っ@友の会 ~]$ sudo mkdir -p /var/cache/nginx/{temp,static_file_cache}

キャッシュ領域ですが、ハードディスクではキャッシュを作る意味がないので、RAMDISK上に作成します。 容量512MBでramdiskを作成するので、 /etc/fstab にはこう追記します。

tmpfs       /var/cache/nginx        tmpfs defaults,noatime,mode=1777,size=512m 0 0

fstab に書き込んだら、マウントしましょう。

[ (っ´∀`)っ@友の会 ~]$ sudo mount /var/cache/nginx

そしていよいよ nginx を起動します。

[ (っ´∀`)っ@友の会 ~]$ sudo service php-fpm start
[ (っ´∀`)っ@友の会 ~]$ sudo service nginx start
[ (っ´∀`)っ@友の会 ~]$ sudo chkconfig php-fpm on
[ (っ´∀`)っ@友の会 ~]$ sudo chkconfig nginx on

それぞれのサイトに何度かアクセスして、キャッシュが蓄積されているか確認してみましょう。

[ (っ´∀`)っ@友の会 ~]$ df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/root             195G   11G  175G   6% /
none                  939M     0  939M   0% /dev/shm
tmpfs                 512M  3.1M  509M   1% /var/cache/nginx

こんな風に、 /var/cache/nginx パーティションの使用量が蓄積されればキャッシュされてることがわかります。

※ キャッシュコントロールについて

nginxのキャッシュコントロールですが、RAMDISKのアンマウント/リマウントによる全クリアか、TTL切れによるexpire待ちの2種類になります。個別のキャッシュコントロールは、URLなどのキーで探して個別にクリアするプログラムを書くしかなさそうです。また、キャッシュがある状態でRAMDISKのリマウントを行った場合は、必ずnginxを再起動しないと、キャッシュミスのエラーが発生しますので、これらの動作をワンセットにしたスクリプトを書くのもよいでしょう。

でわ~♪