2016-11-02

Apache+mod_phpなwordpressをh2o+php-fpmに置き換えた

H2Oの勉強がてらブログのアーキテクチャをApache + mod_phpからH2O + php-fpmの構成に変えてみました。ということで今回は移行に関する備忘録。

移行前の構成

恥ずかしいことにApacheは脆弱な状態でした↓…あぶね

IPA 独立行政法人 情報処理推進機構:ウェブサーバ「Apache HTTP Server」の脆弱性(CVE-2011-3192)について

H2Oのインストール

rpmのものをインストールします。

以下のリポジトリを追加。

$ sudo vim /etc/yum.repos.d/intray-tatsushid-h2o-rpm.repo
#bintray-tatsushid-h2o-rpm - packages by tatsushid from Bintray
[bintray-tatsushid-h2o-rpm]
name=bintray-tatsushid-h2o-rpm
#If your system is CentOS
baseurl=https://dl.bintray.com/tatsushid/h2o-rpm/centos/$releasever/$basearch/
#If your system is Fedora
#baseurl=https://dl.bintray.com/tatsushid/h2o-rpm/fedora/$releasever/$basearch/
gpgcheck=0
repo_gpgcheck=0
enabled=1

で以下インストール

$ sudo yum install h2o

旧構成のApacheのhtaccessの設定

``` Redirect permanent /blog/aws/671/ http://freedom-man.com/blog/swf_using_apex_2/ Redirect permanent /blog/aws/652/ http://freedom-man.com/blog/swf_using_apex/ ... RewriteEngine On RewriteBase /blog/

RewriteRule ^index.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{HTTPS} on RewriteRule . http://%{HTTP_HOST}%{REQUEST_URI} [L]

RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{HTTPS} off RewriteRule . /blog/index.php [L]

``` 基本的に以下の目的を達成するために記載しています。
  1. 旧パスでのアクセスは新パス(パーマリンク)にリダイレクトされる
  2. HTTPSでのアクセスはHTTPにリダイレクトされる。
  3. HTTPでのアクセスは/blog/index.phpに内部リダイレクトされる
1はもう無くても良いためH2Oには設定しません。2は全面HTTPSにするためリダイレクトも必要ありませんが、HTTP→HTTPSへの強制リダイレクトを行い、さらにパーマリンク対応である3の/blog/index.phpへの内部リダイレクトもするような設定を行います。

H2Oの設定

ということで、/etc/h2o/h2o.confは以下の通り
user: nobody

file.custom-handler:
  extension: .php
  fastcgi.connect:
    port: /var/run/php-fpm/php-fpm.sock
    type: unix

compress: ON
file.index: [ 'index.html', 'index.htm', 'index.txt', 'index.php' ]

hosts:
  "freedom-man.com:443":
    listen:
      port: 443
      host: 0.0.0.0
      ssl:
        certificate-file: "/path/to/server.crt" 
        key-file: "/path/to/server.key"
    paths:
      "/":
        redirect:
          status: 301
          url: /blog
      "/blog":
        mruby.handler-file: /etc/h2o/handler.rb
        file.dir: /path/to/wordpress
        redirect:                     
          url: /blog/index.php/
          internal: YES
          status: 307
  "freedom-man.com:80":
    listen:
      port: 80
      host: 0.0.0.0
    paths:
      "/":
        redirect:
          status: 301
          url:    "https://freedom-man.com/"        
access-log: /var/log/h2o/access.log
error-log: /var/log/h2o/error.log
pid-file: /var/run/h2o/h2o.pid

handler.rb

Proc.new do |env|
  headers = {}
  if /\.(css|js|png|jpg|jpeg|gif)\z/.match(env["PATH_INFO"])
    headers["cache-control"] = "max-age=86400"
  end
  [399, headers, []]
end

php-fpmのインストール&設定

phpは5.6を利用
$ sudo rpm -Uvh https://mirror.webtatic.com/yum/el6/latest.rpm
$ sudo rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
$ cd /etc/yum.repos.d
$ sudo curl -O http://rpms.famillecollet.com/enterprise/remi.repo
$ sudo yum install php-fpm -y --enablerepo=remi-php56

/etc/php-fpm.d/www.confではlistenポートをUNIXドメインソケットに変更してます。

; listen = 127.0.0.1:9000
listen = /var/run/php-fpm/php-fpm.sock
listen.owner = nobody
listen.group = nobody
listen.mode = 0660

WordPressの設定

設定>一般から、WordPressアドレスとサイトアドレスのURLをhttpsにします。 h2o-wordpress-setting

さらに、SearchRegexのプラグインを入れて、http://{Domain}になっている部分を一括置換します。

ブラウザでの確認

Apacheだとロードはこんな感じ。同時接続数6が効いちゃってます。 wordpress-apache-timeline

h2oだとロードはこんな感じ。HTTP/2が効いて同時リクエストをしているのが確認できます。

wordpress-h2o-timeline

ベンチマーク

wrkでベンチマークをとってみました。Apacheは以下のような設定です。
StartServers      50
MinSpareServers   50
MaxSpareServers   100
ServerLimit       200
MaxClients        100
MaxRequestsPerChild  4000

Apache: php+内部リダイレクトなパーマリンクページ

$ wrk -c 50 -d 1m -t 10 http://freedom-man.com/blog/h2o-http2/                                                                      
Running 1m test @ http://freedom-man.com/blog/h2o-http2/
  10 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.64s   355.70ms   1.99s    91.67%
    Req/Sec     2.75      4.00    19.00     81.97%
  441 requests in 1.00m, 23.05MB read
  Socket errors: connect 0, read 20, write 0, timeout 417
  Non-2xx or 3xx responses: 20
Requests/sec:      7.34
Transfer/sec:    393.04KB

Apache: 静的ページ

$ wrk -c 50 -d 1m -t 10 http://freedom-man.com/blog/wp-content/plugins/yet-another-related-posts-plugin/style/widget.css\?ver\=4.6.1
Running 1m test @ http://freedom-man.com/blog/wp-content/plugins/yet-another-related-posts-plugin/style/widget.css?ver=4.6.1
  10 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   133.90ms   84.46ms   1.53s    88.11%
    Req/Sec    29.32     16.66   100.00     59.52%
  14504 requests in 1.00m, 13.68MB read
  Socket errors: connect 0, read 27, write 0, timeout 56
  Non-2xx or 3xx responses: 25
Requests/sec:    241.34
Transfer/sec:    233.01KB

続いてはH2O。

H2O: php+内部リダイレクトなパーマリンクページ

$ wrk -c 50 -d 1m -t 10 /h2o-http2/
Running 1m test @ /h2o-http2/
  10 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   695.26ms  437.10ms   2.00s    66.79%
    Req/Sec     5.22      5.70    40.00     94.23%
  571 requests in 1.00m, 27.08MB read
  Socket errors: connect 139, read 25, write 0, timeout 23
  Non-2xx or 3xx responses: 76
Requests/sec:      9.50
Transfer/sec:    461.38KB

H2O: 静的ページ

$ wrk -c 50 -d 1m -t 10 /wp-content/plugins/yet-another-related-posts-plugin/style/widget.css\?ver\=4.6.1
Running 1m test @ /wp-content/plugins/yet-another-related-posts-plugin/style/widget.css?ver=4.6.1
  10 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    56.41ms   37.84ms 707.37ms   93.00%
    Req/Sec    33.99     17.11   110.00     76.98%
  17579 requests in 1.00m, 17.35MB read
  Socket errors: connect 174, read 0, write 0, timeout 0
Requests/sec:    292.52
Transfer/sec:    295.66KB

平均的に良くなっている感じです。

ちなみにApacheの方でKeepAlive Offにすると激遅で、静的ページすらスループットが出ずという結果でした。3way handshakeのオーバーヘッド恐るべし。

ハマりどころ

H2OでHTTPSでアクセスしているのにChrome Developer ToolでProtocolがHTTP/1.1のまま変わらず…。AVAST!のSSLインタラプトして内容を解析する機能が原因でした。以下のようにチェックを外せばOK。 avast-webshield

参考URL

このエントリーをはてなブックマークに追加