およそ4ヶ月のご無沙汰ですが、一応生きておりますというか、ゲームばかりプレイしていた4ヶ月間でした。主にメタルギアソリッド5 ファントムペイン。僕の人生もペインがひどくてそろそろファントムになりそうです。(婉曲的な自死表現)
とまあ、お約束のひとネタはさておいて、そろそろ真面目にファントム化……じゃなかった、技術的なこともやってみようかなと思い立ち、少し前にリリースされたPHP7がチョッパヤでゴイスーという噂を聞いて、PHP7環境を作ろうかと思い立ったのが1月のこと。
で、PHP7にしただけでもWordPressなどはかなり高速化し、これだけでもいいかなーと思いつつも、以前にも記事にした h2o を導入したらもっと早くなるんじゃね? 最近PHPもphp-fpm経由で動くみたいだし? ということで、そちらもあわせて導入したのが1月末。
しばらくはその速さに満足していたものの、h2o 単独だとIPアドレスによるアクセス制御とかBASIC認証に対応していないので、mrubyを使えるようにしないといけないのですが、その辺りの設定で色々ハマって面倒になりしばらく放置、ようやく手を付けて動くようになったのが2月の今ごろということで、いやあ、時が流れるのは早いものですな。
とまあ、そんな感じで相変わらず前置き長いですが、CentOS 6.x 環境にて h2o + PHP7 環境を作ってみたので、参考になれば幸いです。
スポンサードリンク
上記のような環境を、h2o + PHP7 に移行します。GMOクラウド VPSでWeb・メール環境を設定する という記事で触れたように、外部レポジトリを追加している環境を前提にしていますので、レポジトリの追加がまだの方は、先に追加を行ってください。
まず、こちらのサイト様 の記事を参考に、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
今回導入した 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 のインストールに移ります。以前書いた記事 と重複したり相違している部分もありますが、今回はこのようなやり方をした、ということで。
まず、必要なパッケージをインストールします。
# 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 の設定を行います。
今回の設定ファイル環境としては、
以上を前提としています。本来ならバックエンドでWordPressを走らせ、リバースプロキシでh2oを利用するというやり方がメジャーかもですが、そういった分散処理を必要とするほどのサイトでもないですし、VPSひとつでそういった構成を取るとメモリをその分多く必要としそうですし、動かすサービスは少ないほど管理も楽かなということで、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 }
続いて、設定ファイルの用意を行います。
# 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 がインストールされている前提となっています。利用する際には、各自の環境に読みかえてご利用ください。
また、この設定ファイルから呼び出しているファイルはそれぞれ、
となっています。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 推しておいてそれかよ、というオチもついたところで、おあとがよろしいようで。(幕)
スポンサードリンク
当サイトのコメント欄は承認制となっております。また、日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)
コメントを残す