WordPress サイトに nginx を導入する

nginxWordPress サイトにリバースプロキシサーバとして nginx を導入する際の tips。
nginx (エンジンエックス)とは、オープンソースの軽量高性能なHTTPサーバ且つリバースプロキシです。

従来の HTTP サーバのようにリクエストの処理をスレッドで行わず、非同期のアーキテクチャーを用いるイベントループモデルのサーバです、
そのため、多数のリクエストが着た場合に実行スタックをコピーする必要があるスレッドモデルのサーバと違い、1プロセスでリクエストを処理できるため、メモリ消費量が極端に少なくてすむという利点があります。
# 話題の node.js もイベントループモデルですね。

さて、そんな nginx を WordPress サイトに導入する際の tips です。

CentOS, RHEL に最新の nginx をインストールする

CentOS, RHEL に nginx をインストールしたい場合、EPEL リポジトリを有効にすることで yum からインストールすることができます。
ただし EPEL からインストールされる nginx は Ver.0.6 と、ちょっと古いです。
試してみたところ Ver.0.6 では proxy_cache が使えなかったため、最新の 0.8.5x (stable version) または 0.9.x (development version) をインストールしておきたいところです。
そこで、以下の手順で最新の nginx ソースを使って rpmbuild しました。

作業したサーバは RHEL4

# wget http://ftp.iij.ad.jp/pub/linux/fedora/epel/4/SRPMS/nginx-0.6.39-5.el4.src.rpm
# rpm -i nginx-0.6.39-5.el5.src.rpm
# cd /usr/src/redhat/SOURCES
# wget http://nginx.org/download/nginx-0.9.4.tar.gz
# cd ../SPECS/

続いて、nginx.spec を修正。

# vi nginx.spec
%define _unpackaged_files_terminate_build 0              <- 追加
 :
Version:        0.9.4
 :
#Patch0:     nginx-auto-cc-gcc.patch                         <- コメントアウト
#Patch1:     nginx-cve-2009-3555.patch                       <- コメントアウト
 :
#%patch0 -p0                                     <- コメントアウト
#%patch1 -p0                                     <- コメントアウト
 :
%build
# nginx does not utilize a standard configure script.  It has its own
# and the standard configure options cause the nginx configure script
# to error out.  This is is also the reason for the DESTDIR environment
# variable.  The configure script(s) have been patched (Patch1 and
# Patch2) in order to support installing into a build environment.
export LANG='ja_JP.UTF-8'                                      <- 追加
export DESTDIR=%{buildroot}&#91;/text&#93;

rpmbuild して、インストールする。
&#91;text&#93;# rpmbuild -ba nginx.spec
# rpm -Uvh /usr/src/redhat/RPMS/i386/nginx-0.9.4-4.i386.rpm&#91;/text&#93;
<cite>via. <a href="http://d.hatena.ne.jp/kopug/20100918/1284817454" title="CentOS5.5 x86_64 で 最新のnginx を rpmbuildする - 名古屋で働くWebプログラマの覚書">CentOS5.5 x86_64 で 最新のnginx を rpmbuildする - 名古屋で働くWebプログラマの覚書</a></cite>

<h3>gzip 圧縮転送設定</h3>
CSS, JavaScript, html などのテキストファイルを gzip 圧縮転送するように設定する方法。
gzip 圧縮転送する対象を MIME タイプで nginx.conf に以下のように設定しましょう。
[text] :
http {
 :
  gzip              on;
  gzip_http_version 1.0;
  gzip_vary         on;
  gzip_comp_level   6;
  gzip_types        text/html text/xml text/css application/xhtml+xml application/xml application/rss+xml application/atom_xml application/x-javascript application/x-httpd-php;
  gzip_disable      "MSIE [1-6]\.";
 :
}

MSIE 6.0 に対する gzip 圧縮転送は、不安定らしいので IE6 に対しては gzip 圧縮転送しないようにしています。
# gzip_disable "MSIE [1-6]\."; という箇所
via. IE6ではgzip圧縮されたJavaScriptが、実行されたりされなかったりする? – 水の森ノート

PHP の出力結果は MIME 形式としては text/html 等になるため、php.ini で zlib.output_compression を on にしておかなくても gzip 圧縮転送されます。

expires ヘッダを追加する

expires ヘッダを追加して、送信するには expires xxd と書くだけでおっけです。

 :
http {
 :
  server {
    listen 80;
    server_name  example.com;
    # static files
    location ~ .*\.(txt|xml|html?|jpe?g|JPE?G|gif|GIF|png|PNG|swf|SWF|wmv|WMV|flv|FLV|css|CSS|js|JS|inc|ico|gz) {
      root    /var/www/html;
      index   index.html;
      expires 14d;
      break;
    }
 :
  }
 :
}

これで、有効期限14日の expired ヘッダが出力されるようになります。

nginx + fastCGI で WordPress を動作させる

まずは spawn-fcgi のインストール

# yum install spawn-fcgi

続いて php fcgi 動作用のスクリプトを作成。
/etc/rc.d/init.d/php-fastcgi という名前で、こんな感じのスクリプトを作りましょう。

#!/bin/sh
#
# spawn-fcgi   Start and stop FastCGI processes
#
# chkconfig:   - 80 20
# description: Spawn FastCGI scripts to be used by web servers

# Source function library.
. /etc/rc.d/init.d/functions

RETVAL=0
SPAWNFCGI="/usr/bin/spawn-fcgi"
PHPFCGI="/usr/bin/php-cgi"
FCGIPORT="9000"
FCGIADDR="127.0.0.1"
PHP_FCGI_CHILDREN=5
PHP_FCGI_MAX_REQUESTS=1000
ALLOWED_ENV="PATH USER"
USER=nginx
GROUP=nginx
PIDFILE=/var/run/phpfcgi.pid

ALLOWED_ENV="$ALLOWED_ENV PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS FCGI_WEB_SERVER_ADDRS"

case "$1" in
  start)
        PHPFCGI_START=$"Starting ${NAME} service: "
        echo -n $PHPFCGI_START

        # clean environment
        E=
        for i in $ALLOWED_ENV; do E="$E $i=${!i}"; done
        daemon $SPAWNFCGI -a ${FCGIADDR} -p ${FCGIPORT} -u ${USER} -g ${GROUP} -P ${PIDFILE} -C ${PHP_FCGI_CHILDREN} -f ${PHPFCGI}
        RETVAL=$?
        ;;
  stop)
        echo -n "Stopping php-fcgi: "
        killproc -p $PIDFILE phpfcgi
        echo
        RETVAL=$?
        ;;
  *)
        echo "Usage: $0 {start|stop}"
        exit 1
esac
exit $RETVAL

サービスを登録して、起動しておきます。

# chmod a+x /etc/rc.d/init.d/php-fastcgi
# chkconfig --add php-fastcgi
# chkconfig php-fastcgi on
# service php-fastcgi start

nginx.cnf には、こんな感じで登録しておけば良いはずです。

 :
http {
 :
  server {
 :
    listen       80;
    server_name  example.com;
    access_log  /var/log/nginx/example.com.access.log  main;
    location / {
      root   /var/www/html;
      index  index.php index.html index.htm;
      # static files
      if (-f $request_filename) {
        expires 14d;
        break;
      }
      # request to index.php
      if (!-e $request_filename) {
        rewrite ^(.+)$  /index.php?q=$1 last;
      }
    }
    #
    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    location ~ \.php$ {
      root           html;
      fastcgi_pass   127.0.0.1:9000;
      fastcgi_index  index.php;
      fastcgi_param  SCRIPT_FILENAME  /var/www/html/$fastcgi_script_name;
      include        fastcgi_params;
    }
  }
 :
}

via. WordPress on nginx with FastCGIのCentOSの場合 – stnard.jp

proxy cache を有効にする

proxy cache を有効にして WordPress の出力をキャッシュしちゃいましょう。
まずは、直前の設定(nginx + fastCGI で WordPress を動作させる)で listen 80; と設定して80番ポートを見ていた所を listen 8080; に修正して、Web サーバが8080番ポートでリクエストを待つように修正しておきましょう。
代わりにリバースプロキシサーバとして動作する nginx が80番ポートでリクエストを待ちます。

 :
http {
 :
  proxy_cache_path  /var/cache/nginx levels=1:2 keys_zone=czone:4m max_size=50m inactive=120m;
  proxy_temp_path   /var/tmp/nginx;
  proxy_cache_key   "$scheme://$host$request_uri";
  proxy_set_header  Host               $host;
  proxy_set_header  X-Real-IP          $remote_addr;
  proxy_set_header  X-Forwarded-Host   $host;
  proxy_set_header  X-Forwarded-Server $host;
  proxy_set_header  X-Forwarded-For    $proxy_add_x_forwarded_for;
 :
  upstream backend {
    ip_hash;
    server 127.0.0.1:8080;
  }
 :
  server {
    listen       80;
    server_name  example.com;
    location /wp-admin { proxy_pass http://backend; }
    location ~ .*\.php { proxy_pass http://backend; }
    location / {
      set $mobile "";
      if ($http_user_agent ~* '(DoCoMo|J-PHONE|Vodafone|MOT-|UP\.Browser|DDIPOCKET|ASTEL|PDXGW|Palmscape|Xiino|sharp pda browser|Windows CE|L-mode|WILLCOM|SoftBank|Semulator|Vemulator|J-EMULATOR|emobile|mixi-mobile-converter)') {
        set $mobile "@ktai";
      }
      if ($http_user_agent ~* '(iPhone|iPod|Opera Mini|Android.*Mobile|NetFront|PSP|BlackBerry)') {
        set $mobile "@mobile";
      }
      if ($http_cookie ~* "comment_author_|wordpress_(?!test_cookie)|wp-postpass_" ) {
        set $do_not_cache 1;
      }
      proxy_no_cache     $do_not_cache;
      proxy_cache_bypass $do_not_cache;
      proxy_cache czone;
      proxy_cache_key "$scheme://$host$request_uri$is_args$args$mobile";
      proxy_cache_valid  200 301 302 10m;
      proxy_cache_valid  404 5m;
      proxy_pass http://backend;
    }
  }
 :
}

この設定で、以下のような動作をするはずです。

  • wp-admin 以下、または *.php と行ったファイルに対するアクセスは proxy cache せずにバックエンドのウェブサーバに直接リクエストを投げる
  • UA を判断して、PC・ケータイ・スマートフォンからのアクセスは、別々にキャッシュする
  • cookie を判断して、WordPress にログインしている場合は proxy cache せずにバックエンドのウェブサーバに直接リクエストを投げる


via. HsbtDiary(2010-04-27)
via. WordPressを100倍速くする! MySQLの調整やnginx proxy cache | KRAY Inc

また、バックエンドのサーバとして Apache を利用する場合、このままだと Apache のログには nginx が動作しているサーバのIPアドレスが記録されてしまいます。
mod_extract_forwarded とか mod_rpaf とかを使用して、あくせすログにクライアントのIPアドレスが記録されるようにしてあげましょう。
mod_extract_forwarded を使用する場合は mod_proxy も有効にしておいてあげないと、エラーが出るので注意が必要です。

via. reverse proxy 越しの IP アクセス制御 with mod_extract_forwarded 編 – にぽたん研究所
via. Apacheをnginxにリプレイスした | cloudrop
via. mod-rpaf

まとめ

とりあえず WordPress サイトに nginx を導入してみるための設定でした。

dogmap.jp現在、このサイトを設置してあるサーバの構成は、右図のような感じです。

  • クライアントからのリクエストを nginx が受ける
  • 静的ファイルへのリクエストならば nginx が、そのまま返す
  • 動的コンテンツへのリクエストならば proxy cache を通して、バックエンドの Apache サーバにリクエストを投げ、結果を返す
  • PC・ケータイ・スマートフォンからのアクセスに応じて、それぞれ別のキャッシュを保持する
  • WordPress にログインしている場合は proxy cache を通さず、直接バックエンドの Apache サーバから返す

もちろん、バックエンドのサーバは Apache + mod_php ではなく nginx + fastcgi でも構成できます。
メモリの最大量が少ない VPS で使用する場合は、バックエンドのサーバも nginx + fastcgi にしたほうが余裕を持って運用できるでしょう。

WordPress が遅いとか言ってる人は nginx とか Varnish とかのリバースプロキシを試したり、Apache に拘らずに nginx や lighttpd とかの高速軽量な Web サーバ+ fastcgi の環境を試してみれば良いと思うよ。
nginx は WordPress.comWordPress.org でも採用されているので、大規模なサイトでも安心して使えるしね。

WordPress サイトに nginx を導入する」への11件のフィードバック

  1. ピンバック: さくらVPS:Nginx + Apache 構成の設定方法 | ブレン

  2. ピンバック: さくらの VPS に nginx を入れてリバースプロキシ設定するまでの作業メモ(検証用) | ウェブル

  3. MorphMorph

    初めまして。WordPressとの連携時のキャッシュ設定周り、とても参考になりました。
    設定内容について気付いたことがありますので、どうしたものか悩んだのですが失礼ながらコメントさせていただきます。
    proxy_cache_keyについてなのですが、場合によっては閲覧対象と違うコンテンツのキャッシュを読みにいってしまう場合がありませんでしょうか。例えば下記のような場合です。

    1.http://hogehoge.com/fugafugaとhttp://hogehoge.com/fugafuga2という2つのコンテンツを配置
    2.fugafuga2にPCでアクセス → “…fugafuga2”のキーでキャッシュされる
    3.キャッシュの有効期間内にiPhoneでfugafugaにアクセス → “…fugafuga”+“2”のキーが生成されるため、fugafuga2のキャッシュが返される

    ですので、proxy_cache_keyとしては$request_uriと$mobileとの間に何か固定の記号等を挟んだ方が安全かも知れません。
    突然のコメント失礼しました。

    返信
    1. をかもと 投稿作成者

      MorphMorph さん、はじめまして。

      proxy_cache_keyとしては$request_uriと$mobileとの間に何か固定の記号等を挟んだ方が安全かも知れません。
      突然のコメント失礼しました。

      ですよねー。
      なので、僕も最近は

      set $mobile "";
      if ($http_user_agent ~* '(DoCoMo|...)') {
        set $mobile "@ktai";
      }
      if ($http_user_agent ~* '(iPhone|...)') {
        set $mobile "@mobile";
      }

      みたいにして proxy_cache_key が、ユニークになるようにしてます。

      返信
  4. ピンバック: nginxとWordPress – MorphMorph

  5. ピンバック: Nginx + lsyncd で WordPress を負荷分散させる : dogmap.jp

  6. ピンバック: ちょっとだけNGINXを « 12net.jp

  7. ピンバック: 分からない人が書いたCentOSにnginxとfastcgiを入れてWordPressを動かすまでのメモなので、分からない人が読んだら分かりそうその2 - Shinichi Nishikawa's blog

  8. ピンバック: ものすごく簡単に書いたCentOSにnginxとfastcgiを入れてWordPressを動かすまでのメモ - Shinichi Nishikawa's blog

  9. ピンバック: WordPress サイトに nginx を導入する | WPPP - WordPress Powered Publishing

  10. ピンバック: Tweets that mention WordPress サイトに nginx を導入する : dogmap.jp -- Topsy.com

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください