次世代HTTP候補のSPDYをWordpress + Nginxで有効にする

SPDY、流行ってますよね。

魔少年?それはビーディー。 ワンダー?それはスティービー。 次世代の香りがするシャレオツプロトコル?それはスピーディー。

というわけで、このブログをSPDY対応にしてみました。 このブログは、Nginxの2重構成となっていて、片方がリバースプロクシ、もう片方がWordPressのPHP実行環境とFastCGIでつながる用。

SPDYパッチを当てたNginxをビルドする

NginxでSPDYを有効にする場合、OpenSSL 1.0.1以降が必要とのことですが、システムにそれをインストールする必要はないようです。 Debianなので、aptitudeでもろもろ入れています。

# ビルドに必要なものを入れる
sudo aptitude install build-essential libpcre3-dev zlib1g-dev

# Nginxのtar ball取ってきて、SPDYパッチあてる
wget http://nginx.org/download/nginx-1.3.11.tar.gz
tar xvfz nginx-1.3.11.tar.gz
cd nginx-1.3.11
wget http://nginx.org/patches/spdy/patch.spdy.txt
patch -p1 < patch.spdy.txt

# Nginx用のOpenSSL 1.0.1cを解凍しておく
wget http://www.openssl.org/source/openssl-1.0.1c.tar.gz
tar xvfz openssl-1.0.1c.tar.gz

# Nginxの鬼configure
./configure \
  --prefix=/usr/local/nginx \
  --sbin-path=/usr/local/nginx/sbin/nginx \
  --conf-path=/usr/local/nginx/etc/nginx/nginx.conf \
  --http-log-path=/var/log/nginx/access \
  --error-log-path=/var/log/nginx/error \
  --pid-path=/var/run/nginx/nginx.pid \
  --lock-path=/var/run/nginx/nginx.lock \
  --user=nginx \
  --group=nginx \
  --http-client-body-temp-path=/var/tmp/nginx/req \
  --http-proxy-temp-path=/var/tmp/nginx/proxy \
  --http-fastcgi-temp-path=/var/tmp/nginx/fastcgi \
  --without-mail_pop3_module \
  --without-mail_imap_module \
  --without-mail_smtp_module \
  --with-pcre-jit \
  --with-md5-asm \
  --with-sha1-asm \
  --with-http_stub_status_module \
  --with-http_ssl_module \
  --with-http_realip_module \
  --with-rtsig_module \
  --with-select_module \
  --with-poll_module \
  --with-file-aio \
  --with-http_spdy_module \
  --with-openssl=openssl-1.0.1c
make
sudo make install

Nginxの設定

Nginxの設定ファイルを書く。

  • sslを有効にする。証明書も買ったよ。
  • reverse proxyしてキャッシュする用と、Wordpressホスト用と両方の設定を書く。reverse proxyのときにヘッダに各種情報を仕込んでおく。

user www-data;
worker_processes  1;

error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;

events {
  worker_connections  1024;
}

http {
  include     mime.types;

  access_log  /var/log/nginx/access.log;

  sendfile        on;
  #tcp_nopush     on;

  #keepalive_timeout  0;
  keepalive_timeout  65;
  tcp_nodelay        on;

  gzip  on;
  gzip_disable "MSIE [1-6]\.(?!.*SV1)";

  # wktk blog
  server {
    listen 8080;

    root /home/tasuku/blog_wktk;
    server_name blog.wktk.co.jp;

    include /home/tasuku/blog_wktk/nginx.conf;

    location / {
      index index.php;
      if (-f $request_filename) {
        expires 14d;
        break;
      }
      if (!-e $request_filename) {
        rewrite ^(.+)$ /index.php?q=$1 last;
      }
    }
    location ~ \.php$ {
      include       fastcgi_params;
      fastcgi_pass  127.0.0.1:9001;
      fastcgi_index index.php;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
      fastcgi_param SERVER_PORT 80;
      fastcgi_param SERVER_NAME blog.wktk.co.jp;
      expires 2h;
    }
  }

  # wktk blog reverse proxy

  proxy_cache_path  /var/cache/nginx levels=1:2 keys_zone=czone:180m max_size=512m 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;
  proxy_set_header  X-Forwarded-Proto  $scheme;
  proxy_buffers     32 16k;

  upstream backend {
    ip_hash;
    server 127.0.0.1:8080;
  }

  server {
    listen 80;
    listen 443 ssl spdy default_server;

    # ssl
    ssl_certificate /etc/nginx/certs/blog.wktk.co.jp.crt;
    ssl_certificate_key /etc/nginx/certs/blog_wktk.key;

    # spdy
    spdy_max_concurrent_streams 50;
    spdy_streams_index_size 32;
    spdy_recv_timeout 5s;
    spdy_keepalive_timeout 15s;
    spdy_headers_comp 9;

    # root /home/tasuku/blog_wktk;
    server_name blog.wktk.co.jp;

    location /wp-admin { proxy_pass http://backend; }
    location ~ .*\.php { proxy_pass http://backend; }

    expires off;

    set $do_not_cache 0;

    location / {
      set $mobile 0;
      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 1;
      }
      if ($http_user_agent ~* '(iPhone|iPod|Opera Mini|Android.*Mobile|NetFront|PSP|BlackBerry)') {
        set $mobile 2;
      }
      if ($http_cookie ~* "comment_author_[^=]*=([^%]+)%7C|wordpress_logged_in_[^=]*=([^%]+)%7C") {
        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 20m;
      proxy_cache_valid  404 5m;
      proxy_pass         http://backend;
    }

    location ~* \.(jpg|png|gif|jpeg|css|js|swf|pdf|ppt|pptx)$ {
      proxy_cache_valid  200 120m;
      expires            864000;
      proxy_cache        czone;
      proxy_pass         http://backend;
    }

    location  ~* \/[^\/]+\/(feed|\.xml)\/? {
      if ($http_cookie ~* "comment_author_[^=]*=([^%]+)%7C|wordpress_logged_in_[^=]*=([^%]+)%7C") {
        set $do_not_cache 1;
      }
      proxy_no_cache     $do_not_cache;
      proxy_cache_bypass $do_not_cache;
      proxy_cache        czone;
      proxy_cache_valid  200 60m;
      proxy_pass         http://backend;
    }
  }
}

WordPress側のSSL設定をする

wp-config.phpのwp-settings.php読み込み前に、Proxyに来たプロトコルを見てHTTPSかどうかを判定するロジックを入れる。 strtolowerはいらない気がするけど、wp-includes/functions.phpのis_sslと同じノリでやってみる。

// tasuku: added for proxy
if ( isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https' ) {
        $_SERVER['HTTPS'] = 'on';
}

Nginxのinitスクリプトを書く

initスクリプトを書く。Debianのnginxデフォルトのinitスクリプトのほぼコピペ。

#!/bin/sh

### BEGIN INIT INFO
# Provides:          nginx
# Required-Start:    $local_fs $remote_fs $network $syslog
# Required-Stop:     $local_fs $remote_fs $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts the nginx web server
# Description:       starts nginx using start-stop-daemon
### END INIT INFO

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/local/nginx/sbin/nginx
NAME=nginx
DESC=nginx

test -x $DAEMON || exit 0

set -e

. /lib/lsb/init-functions

test_nginx_config() {
  if $DAEMON -t $DAEMON_OPTS >/dev/null 2>&1
  then
    return 0
  else
    $DAEMON -t $DAEMON_OPTS
    return $?
  fi
}

case "$1" in
  start)
  echo -n "Starting $DESC: "
        test_nginx_config
  start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \
    --exec $DAEMON -- $DAEMON_OPTS || true
  echo "$NAME."
  ;;
  stop)
  echo -n "Stopping $DESC: "
  start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \
    --exec $DAEMON || true
  echo "$NAME."
  ;;
  restart|force-reload)
  echo -n "Restarting $DESC: "
  start-stop-daemon --stop --quiet --pidfile \
    /var/run/$NAME.pid --exec $DAEMON || true
  sleep 1
        test_nginx_config
  start-stop-daemon --start --quiet --pidfile \
    /var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS || true
  echo "$NAME."
  ;;
  reload)
        echo -n "Reloading $DESC configuration: "
        test_nginx_config
        start-stop-daemon --stop --signal HUP --quiet --pidfile /var/run/$NAME.pid \
            --exec $DAEMON || true
        echo "$NAME."
        ;;
  configtest)
        echo -n "Testing $DESC configuration: "
        if test_nginx_config
        then
          echo "$NAME."
        else
          exit $?
        fi
        ;;
  status)
  status_of_proc -p /var/run/$NAME.pid "$DAEMON" nginx && exit 0 || exit $?
  ;;
  *)
  echo "Usage: $NAME {start|stop|restart|reload|force-reload|status|configtest}" >&2
  exit 1
  ;;
esac

exit 0

動作確認する

Google Chromeであれば、

Firefoxであれば、

でSPDYが有効かどうかチェックできる。

なぜかChromeのSPDY indicatorでは有効判定されていないが、SPDYで通信はなされているようだ。

というわけで、以下のURLからSPDY版にアクセス!アクセス! あなたの知らない世界(by 新倉イワオ)