GUiLZ Project Personal & Experimental Blog
このエントリーをはてなブックマークに追加
はてなブックマーク - GMOクラウド VPS環境を、h2o+PHP7に移行してWebアクセスを高速化する
Facebook にシェア
[`evernote` not found]



GMOクラウド VPS 設定記事一覧

 

およそ4ヶ月のご無沙汰ですが、一応生きておりますというか、ゲームばかりプレイしていた4ヶ月間でした。主にメタルギアソリッド5 ファントムペイン。僕の人生もペインがひどくてそろそろファントムになりそうです。(婉曲的な自死表現)

とまあ、お約束のひとネタはさておいて、そろそろ真面目にファントム化……じゃなかった、技術的なこともやってみようかなと思い立ち、少し前にリリースされたPHP7がチョッパヤでゴイスーという噂を聞いて、PHP7環境を作ろうかと思い立ったのが1月のこと。

で、PHP7にしただけでもWordPressなどはかなり高速化し、これだけでもいいかなーと思いつつも、以前にも記事にした h2o を導入したらもっと早くなるんじゃね? 最近PHPもphp-fpm経由で動くみたいだし? ということで、そちらもあわせて導入したのが1月末。

しばらくはその速さに満足していたものの、h2o 単独だとIPアドレスによるアクセス制御とかBASIC認証に対応していないので、mrubyを使えるようにしないといけないのですが、その辺りの設定で色々ハマって面倒になりしばらく放置、ようやく手を付けて動くようになったのが2月の今ごろということで、いやあ、時が流れるのは早いものですな。

とまあ、そんな感じで相変わらず前置き長いですが、CentOS 6.x 環境にて h2o + PHP7 環境を作ってみたので、参考になれば幸いです。

スポンサードリンク

 

動作環境

  • CentOS 6.x
  • すでにApache・PHPでWebサイトを運用している環境に、h2o 1.7.0(mruby有効化) + PHP7 を導入

上記のような環境を、h2o + PHP7 に移行します。GMOクラウド VPSでWeb・メール環境を設定する という記事で触れたように、外部レポジトリを追加している環境を前提にしていますので、レポジトリの追加がまだの方は、先に追加を行ってください。

 

PHP7の導入

まず、こちらのサイト様 の記事を参考に、PHP7用のレポジトリを追加します。

# vi /etc/yum.repos.d/remi.repo

 

として、以下の内容を追加します。

[remi-php70]
name=Les RPM de remi de PHP 7.0 pour Enterprise Linux 6 - $basearch
#baseurl=http://rpms.famillecollet.com/enterprise/6/php70/$basearch/
mirrorlist=http://rpms.famillecollet.com/enterprise/6/php70/mirror
# WARNING: If you enable this repository, you must also enable "remi"
enabled=0
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi
includepkgs=php* mysql*

 

続いて、立ち上がっているhttpdを終了させて、PHP関係のパッケージを削除します。自分の環境では、yum remove php-* と、phpと*の間にハイフンを入れなければ削除されませんでした。

# service httpd stop
# yum remove php-*

 

古いPHPパッケージの削除が終わったら、PHP7のパッケージを導入します。h2o で利用する php-fpm もこの段階で導入していますが、Apache でPHP7を使うなら導入しなくてもかまいません。

# yum --enablerepo=remi-php70 install php php-cli php-devel php-pear php-mcrypt php-mbstring php-mysql php-pdo php-gd php-pecl-imagick php-opcache php-pecl-apcu php-fpm

 

こちらのサイト様 の記事を参考に(というかそのまま)、OPcacheとAPCuの設定を行います。

# vi /etc/php.d/opcache.ini

 

として、以下の内容を入力します。

[opcache]
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.fast_shutdown=1

 

続けて、

# vi /etc/php.d/apcu.ini

 

として、以下の内容を入力します。

extension = apcu.so
apc.enabled=1
apc.shm_size=128M
apc.ttl=86400
apc.gc_ttl=86400
apc.mmap_file_mask=/tmp/apc.XXXXXX

 

また、以前は php-pecl-ssh2 と指定することで、yumからインストールできたSSH2ライブラリが現時点ではインストールできないので、こちらのサイト様の情報 を参考に、ソースからインストールします。自分の環境では libssh2.h が存在せずにコンパイルに失敗したため、libssh2-devel をインストールしました。

# yum install libssh2-devel
# cd /usr/local/src
# wget https://github.com/Sean-Der/pecl-networking-ssh2/archive/php7.zip
# unzip php7.zip
# cd pecl-networking-ssh2-php7
# phpize
# ./configure
# make
# make install
# echo "extension = ssh2.so" > /etc/php.d/ssh2.ini

 

あとは、過去記事でも設定した通り、/etc/php.ini を編集します。

# vi /etc/php.ini

 

として、以下の内容を編集・追加します。あくまで自分の場合の例なので、不要であれば変更しなくてもかまいません。

memory_limit = 256M
post_max_size = 128M
upload_max_filesize = 128M
max_file_uploads = 100
mysql.cache_size = 4000
mysqli.cache_size = 4000
date.timezone = Asia/Tokyo
mbstring.language = Japanese

 

httpd を起動して、動作に問題がなければPHP7の導入は完了です。

# service httpd start

 

ruby 2.3.0の導入

今回導入した h2o 1.7.0 ではmrubyがソースに含まれており、rubyがシステムに入っていれば自動でコンパイルされます。ただし、CentOS 6.xでyum経由のインストールを行うと、ruby 1.8.7 が導入されるため、1.9以上を要求するh2oではコンパイルに失敗します。(もしyum経由でrubyを導入済みであれば、先にアンインストールしておきましょう)

yumが使えないため、今回は rbenv を導入し、そこからruby 2.3.0の導入を行います。こちらのサイト様 の情報を参考に(というかほぼそのまま)、まずgitと後に必要となるライブラリを導入します。

# yum install git libffi-devel readline-devel

 

続いて、GitHub から rbenv を取得します。参考サイト様の内容の通り、/opt 以下に導入しました。

# cd /opt
# git clone git://github.com/sstephenson/rbenv.git
# mkdir /opt/rbenv/plugins
# cd /opt/rbenv/plugins
# git clone git://github.com/sstephenson/ruby-build.git

 

さらに、 /etc/profile に環境変数などを追記します。

# vi /etc/profile

 

として、以下の内容を追記します。

export RBENV_ROOT="/opt/rbenv"
export PATH="${RBENV_ROOT}/bin:${PATH}"
eval "$(rbenv init -)"

 

環境変数の設定が終わったら、一度シェルを再起動したりログオフしてからログインするなどして、変更した設定を適用しておきます。ここまで終わったら、rubyをインストールします。自分の場合は現時点で最新だった、2.3.0を導入しました。

# rbenv install 2.3.0

 

インストールにはしばらくかかりますが、プロンプトが出るまで待ちます。インストールが終わったら、普段使うバージョンとして登録し、動作確認をします。

# rbenv global 2.3.0
# ruby -v
ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux]

 

このように表示されれば、インストールは完了です。

 

h2o のインストール

ようやく h2o のインストールに移ります。以前書いた記事 と重複したり相違している部分もありますが、今回はこのようなやり方をした、ということで。

まず、必要なパッケージをインストールします。

# yum --enablerepo=rpmforge install bison bison-devel cmake libyaml-devel

 

yumで入るcmakeは2.8で、最近のh2oは2.9以上が必要という話も聞きましたが、自分が試した限り、h2o 1.7.0 beta4 ならびに 1.7.0 では、2.8で問題なくコンパイルできました。

続いて、h2oをコンパイルします。mrubyを有効にするオプションである、-DWITH_MRUBY オプションはデフォルトでオンになっているので、rubyが入っていれば指定する必要はありません。

# cd /usr/local/src
# git clone https://github.com/h2o/h2o.git /usr/local/src/h2o
# cd h2o
# git submodule update --init --recursive
# cmake -DWITH_BUNDLED_SSL=on .
# make h2o
# make install

 

インストールまで終わったら、バージョンを確認します。

# /usr/local/bin/h2o -v
h2o version 1.7.0
OpenSSL: LibreSSL 2.2.6
mruby: YES

 

これでようやく h2o の導入まで終わりました。続けて h2o の設定を行います。

 

h2o の設定 – 前提環境

今回の設定ファイル環境としては、

  • httpdからの移行であるため、念のためapacheユーザー権限で動作させる
  • WordPressサイトを https://www.example.com/ として待ち受ける
  • http://www.example.com/ や http://example.com/ などは、上記アドレスにリダイレクトする
  • https://www.example.com/ 以下で、phpmyadmin と munin をIPアドレスによるアクセス制限をかけた上で待ち受ける
  • リバースプロキシとして、localhost:8080 で動作しているサイトを http://redirect.example.com/ として待ち受ける

以上を前提としています。本来ならバックエンドでWordPressを走らせ、リバースプロキシでh2oを利用するというやり方がメジャーかもですが、そういった分散処理を必要とするほどのサイトでもないですし、VPSひとつでそういった構成を取るとメモリをその分多く必要としそうですし、動かすサービスは少ないほど管理も楽かなということで、h2o のみで処理してもらうことにしました。

 

h2o の設定 – 事前準備

設定ファイル、ログファイル、pidファイルの置き場所を作っておきます。変更する意味はないかもですが、pidファイルを置くディレクトリは、apacheグループがアクセスできるようにしました。

# mkdir /etc/h2o
# mkdir /var/log/h2o
# mkdir /var/run/h2o
# chown root:apache /var/run/h2o

 

こちらのサイト様 の情報を参考に、起動ファイルを用意します。

# vi /etc/init.d/h2o

 

として、以下の内容を書き込みます。

#!/bin/bash
#chkconfig: 2345 85 15
#descpriction: h2o Web Server

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

RETVAL=0
SERVICE_NAME=`basename $0`

start() {
        echo -n $"Starting $SERVICE_NAME: "
        /usr/local/bin/h2o -m daemon -c /etc/h2o/h2o.conf
        RETVAL=$?
        if [ $RETVAL == 0 ]; then
          success
        else
          failure
        fi
        echo
}

stop() {
        echo -n $"Stopping $SERVICE_NAME: "
        kill -TERM `cat /var/run/h2o/h2o.pid`
        RETVAL=$?
        if [ $RETVAL == 0 ]; then
          success
        else
          failure
        fi
        echo
}

reload() {
        echo -n $"Graceful $SERVICE_NAME: "
        kill -HUP `cat /var/run/h2o/h2o.pid`
        RETVAL=$?
        if [ $RETVAL == 0 ]; then
          success
        else
          failure
        fi
        echo
}

case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  reload|graceful)
        reload
        ;;
  restart)
        stop
        start
        ;;
  *)
        echo $"Usage: $0 {start|stop}"
        exit 1
esac

exit $RETVAL

 

起動ファイルが用意できたら、実行権限を付けて自動起動を有効にします。が、いま起動してしまうと、設定ファイルを用意していないのでエラーが出てしまうため、あくまで自動起動できるようにだけしておきます。

# chmod 755 /etc/init.d/h2o
# chkconfig h2o on
# chkconfig httpd off

 

あわせて、出力されるログのローテーション設定も事前にしておきます。同じく上記サイト様の情報をそのままに、

# vi /etc/logrotate.d/h2o

 

として、以下の内容を記載します。

/var/log/h2o/*log {
    missingok
    notifempty
    sharedscripts
    delaycompress
    postrotate
        /sbin/service h2o graceful > /dev/null 2>/dev/null || true
    endscript
}

 

h2o の設定 – 設定ファイルの作成

続いて、設定ファイルの用意を行います。

# vi /etc/h2o/h2o.conf

 

として、設定ファイルを書き込みます。

user: apache
pid-file: /var/run/h2o/h2o.pid
error-log: /var/log/h2o/error.log
http2-reprioritize-blocking-assets: ON
max-connections: 1024
num-threads: 3

# ヘッダー出力を調整
header.set: "X-Content-Type-Options: nosniff"
header.unset: "X-Powered-By"

# GZIP圧縮を有効にする
gzip: ON
file.send-gzip: ON

file.index: ['index.php', 'index.html']
file.etag: OFF
expires: 1 day

# cssとjsの圧縮を有効にして、HTTP/2での優先順位を変更
file.mime.settypes:
    "text/css":
         extensions: [".css"]
         is_compressible: yes
         priority: highest
    "application/javascript":
         extensions: [".js"]
         is_compressible: yes
         priority: highest

# php-fpmを有効にする
file.custom-handler:
  extension: .php
  fastcgi.spawn: "PHP_FCGI_CHILDREN=10 exec /usr/bin/php-cgi"

hosts:
  "example.com:80":
    listen:
      host: 0.0.0.0
      port: 80
    paths:
      /:
        redirect:
          status: 301
          url: https://www.example.com/

  "www.example.com:80":
    paths:
      /:
        redirect:
          status: 301
          url: https://www.example.com/

  "example.com:443":
    paths:
      /:
        redirect:
          status: 301
          url: https://www.example.com/

  "www.example.com:443":
    access-log: /var/log/h2o/example.com-access.log
    listen:
      host: 0.0.0.0
      port: 443
      ssl:
        certificate-file: /etc/h2o/example.com.crt
        key-file:         /etc/h2o/example.com.key
        cipher-suite: ECDHE+RSAGCM:ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!aNULL!eNull:!EXPORT:!DES:!3DES:!MD5:!DSS
    paths:
      /:
        file.dir: /var/www/html/
        file.dirlisting: OFF
        redirect:
          url: /index.php/
          internal: YES
          status: 307

      /phpmyadmin/:
        mruby.handler-file: /etc/h2o/ipfilter.rb
        file.dir: /var/www/phpmyadmin/

      /munin/:
        mruby.handler-file: /etc/h2o/ipfilter.rb
        file.dir: /var/www/munin/

  "redirect.example.com:80":
    access-log: /var/log/h2o/redirect.example.com-access.log
    listen:
      host: 0.0.0.0
      port: 80
    paths:
      "/":
        proxy.reverse.url: http://localhost:8080/
        proxy.preserve-host: ON

 

この設定例では、/var/www/html に WordPress、/var/www/phpmyadmin に phpMyAdmin、/var/www/munin に Munin がインストールされている前提となっています。利用する際には、各自の環境に読みかえてご利用ください。

また、この設定ファイルから呼び出しているファイルはそれぞれ、

  • /etc/h2o/example.com.crt
    SSLサーバ証明書と中間証明書、ルート証明書を結合したもの
  • /etc/h2o/example.com.key
    SSL秘密鍵
  • /etc/h2o/ipfilter.rb
    mruby IPアドレスでのアクセス制限用スクリプト

となっています。SSL証明書については、Apache ならサーバー証明書やクロスルート証明書、ルート証明書を別々に読み込ませれば動きましたが、nginxやh2oでは一つに結合しないと動作しないようなので、以下のようにして結合しました。(StartSSLでの例です)

# cat server.crt sub.class1.server.sha2.ca.pem ca-sha2.pem > /etc/h2o/example.com.crt

 

IPアドレスでのアクセス制限用スクリプトについては、こちらのサイト様の情報 を参考に(というかそのままですが)、

# vi /etc/h2o/ipfilter.rb

 

として、スクリプトファイルを開き、以下の内容を記載します。

ALLOW_HOSTS = %w(
192.168.0.100
192.168.0.101
192.168.0.102
)

class Acl
  def call(env)
    if ALLOW_HOSTS.include?(env['REMOTE_ADDR'])
      [399, {}, []]
    else
      [403, {'Content-Type' => 'text/plain;charset=utf-8'}, ['Forbidden']]
    end
  end
end

Acl.new

 

このスクリプト例では、192.168.0.100~102のIPアドレスからのみ接続を許可する設定となっています。

ここまで設定できたら、Apache を停止して、h2o を起動します。

# service httpd stop
# service h2o start

 

として、Apache を停止した後、h2o を立ち上げます。正常にサービスが立ち上がり、各サイトが正しく表示されたらOKです。

 

あとがきというか余談

上記では、IPアドレスでのアクセス制限用スクリプトを外部に別途用意しましたが、h2o の公式サイト によると、外部スクリプトを呼ばなくても

paths:
  "/":
    mruby.handler: |
      lambda do |env|
        if /\A192\.168\./.match(req["REMOTE_ADDR"])
          return [399, {}, []]
        end
        [403, {'content-type' => 'text/plain'}, ["access forbidden\n"]]
      end

 

このように設定ファイルを書けば、192.168.~ のIPアドレスのみ接続できるようになるとありますが、自分の環境では Internal Server Error となり、エラーログを見ると下記のようなエラーが発生していました。

[h2o_mruby] in request:/munin/:mruby raised: /etc/h2o/h2o.conf:2: undefined method 'req' for main (NoMethodError)

 

自分の場合、rubyに詳しくなく解決方法が分からなかったため、おとなしく外部ファイル呼び出しでの制限を実施しました。まあ、この方法についても、Twitterでも書きましたが、mruby.handler-file: と file.dir: の書く順番を逆にしていたせいで、正しく動作しないという点にハマったりもしましたが……。

この例でいうと、

      /munin/:
        mruby.handler-file: /etc/h2o/ipfilter.rb
        file.dir: /var/www/munin/

 

を、

      /munin/:
        file.dir: /var/www/munin/
        mruby.handler-file: /etc/h2o/ipfilter.rb

 

こんな風に逆に書いてしまうと、正常に動作しない(どのIPアドレスからでも接続できてしまう) ので注意してください。だからといって、例えば

      /munin/:
        mruby.handler-file: /etc/h2o/ipfilter.rb

 

と、file.dir: を省略すると、許可されていないIPアドレスからの接続は403となり、接続は遮断されますが、許可したIPアドレスからの接続も404エラーとなり、接続できません。(muninをドキュメントルート以下に設置し、mruby.handler-file: を記載しなければ正常に接続できていたとしても)

Apache だと、この辺り割とルーズというか、そんなに気を使って書かなくても問題ないことが多い印象なので(もちろん気を使わないといけない部分もありますが)、他のWebサーバーをほとんど使ったことがない自分にとっては、いい勉強になりました。

 

……と、望んだ通りに動作するまでは多少苦労しましたが、正しく動作するようになってからは、思わず笑っちゃうくらいの速さに大満足しています。Apache + PHP7 でも速度の改善は体感できましたが、それをさらに高速化してくれる h2o は、設定などに慣れが必要なものの、お勧めなhttpサーバかなと。

まあ、このブログが動いているサーバーは、PHP7対応ではあるものの、Apache なレンタルサーバーに GMO クラウドVPS から移転したので、h2o の恩恵はまるっきり受けていないんですけどね。さんざん h2o 推しておいてそれかよ、というオチもついたところで、おあとがよろしいようで。(幕)

スポンサードリンク

コメントを残す

メールアドレスが公開されることはありません。

当サイトのコメント欄は承認制となっております。また、日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

スポンサードリンク

Twitter
利用中のサービス

GUiLZ Project では、以下のサービスを利用しています。


関連サイト
巡回先サイト様
アーカイブ