PHP 7.0 & HTTP2 アップグレードへの道
PHP7 がリリースされ、nginx も HTTP2 に対応するようになり、ともにサイトの高速化が期待できるとのことで、早速導入してみました。
PHP 7.0 の導入
PHP7 を入れるための remi リポジトリを追加。依存関係にある EPEL リポジトリも追加。
wget http://ftp.iij.ad.jp/pub/linux/fedora/epel/7/x86_64/e/epel-release-7-5.noarch.rpm
rpm -Uvh epel-release-7-5.noarch.rpm
wget http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
rpm -Uvh remi-release-7.rpm
yum で インストール
yum -y install --enablerepo=remi-php70 php php-devel php-common php-mbstring php-mysqlnd php-pdo php-mcrypt php-pear php-xml php-gd php-pecl-apcu-bc php-fpm
でも、エラーでこけました。いくつかのパッケージで
要求: libc.so.6(GLIBC_2.15)(64bit)
と出てくるのでどうやら glibc 2.15 (64bit) が必要なようです。 調べてみると現時点の CentOS 6 系では yum で glibc は 2.12 までしかアップデートできませんでした。
CentOS のバージョンを 7 にするのは影響がデカくて流石に避けたいところです。
ソースからビルドすれば大丈夫そうですが、yum 管理から外れるのもなぁ…とひとしきり悩んだ結果、
入れ直しついでにせっかくなので PHP の管理は phpBrew で行うようにしてみました。
phpBrew は各バージョンをビルドから行うので、おそらく CentOS 6 のままでもイケるであろうと期待して…
公式の手順に沿って、Cent OS 用の phpBrew インストールの必要環境を構築します。
まずはPHPに特化したリポジトリ、webtaticを追加。
rpm -Uvh http://mirror.webtatic.com/yum/el6/latest.rpm
基本パッケージとしてPHP5.3をインストールします。
yum install --enablerepo=webtatic php php-xml
普通にインストールされたものの、phpをコールするたびに
PHP Warning: PHP Startup: Unable to load dynamic library ‘/usr/lib64/php/modules/apc.so’ - /usr/lib64/php/modules/apc.so: cannot open shared object file: No such file or directory in Unknown on line 0
とエラーがでて鬱陶しいので、APCを有効にするべく、PECLに必要なライブラリをインストールします。
yum install --enablerepo=webtatic php-pear php-devel httpd-devel pcre-devel
そしてAPCをインストール
pecl install APC
引き続き、phpBrew の必要環境の準備を行います。
rpmforgeリポジトリを登録
wget http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm
rpm -Uvh rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm
phpBrewの依存パッケージのインストール
yum install --enablerepo=rpmforge re2c libmhash
準備が完了したので phpBrew 経由で
phpbrew install 7.0.1 +default+dbs+mcrypt+gd+fpm
と PHP 7.0.1 をインストールしてみたものの、途中でいろいろエラーが出てコケまくります。
コンパイルに必要なライブラリがないことが原因のようです。
結局、試行錯誤した結果、以下、PHP のビルドに足らないライブラリを yum で追加インストールしておくことになりました。
yum --enablerepo=epel install libxml2-devel openssl-devl bzip2-devel readline-devel libxslt-devel libjpeg-devel libpng-devel libXpm-devel freetype-devel
今度こそ、と思いきやOpen SSLのライブラリがないというエラーが…
configure: error: Cannot find OpenSSL’s libraries
また、phpBrew の公式には以下のような記述があり、指定しないと後でGD拡張を有効にしようとしてもエラるので、
GD拡張を指定してPHPをビルドするには、libpng dirとlibjpeg dirを指定する必要があります。 例えば、
$ phpbrew install php-5.4.10 +default +mysql +intl +gettext +apxs2=/usr/bin/apxs2 \ -- --with-libdir=lib/x86_64-linux-gnu \ --with-gd=shared \ --enable-gd-natf \ --with-jpeg-dir=/usr \ --with-png-dir=/usr
最終的な結果として以下のようなコマンドになりました。
phpbrew install 7.0.1 +default+sqlite+mysql+mcrypt+gd+fpm+openssl=/usr -- --with-libdir=lib64 --with-gd=shared --enable-gd-natf --with-jpeg-dir=/usr --with-png-dir=/usr
ビルドに時間はかかるけど、何とか動作するところまではこぎつけられました。
拡張も有効化して完了です。
phpbrew ext install gd
phpbrew ext install opcache
phpbrew ext install apcu
OPcacheの設定
vim ~/.phpbrew/php/php-7.0.1/var/db/opcache.ini
zend_extension=/path/to/.phpbrew/php/php-7.0.1/lib/php/extensions/no-debug-non-zts-20151012/opcache.so
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
APCUの設定
vim ~/.phpbrew/php/php-7.0.1/var/db/apcu.ini
extension = apcu.so
apc.enabled=1
apc.shm_size=128M
apc.ttl=86400
apc.gc_ttl=86400
HTTP2 の有効化
nginx 1.9.5 から HTTP2 をサポートするようになったので、まずは nginx のバージョンを上げます。
現時点では nginx 1.9 系 は Stable ではなく mainline バージョンなので、
以前登録した nginx repo の baseurl を変更します。
vim /etc/yum.repos/nginx.repo
-baseurl=http://nginx.org/packages/centos/6/$basearch/
+baseurl=http://nginx.org/packages/mainline/centos/6/$basearch/
あとは通常通り、アップデートすればOKでした。
yum --enablerepo=nginx update nginx
また、php-fpm と nginx の参照を unix socketで接続すると Bad Gateway が発生してどうにもならなかったので、 127.0.0.1:9000 に書き直したところ、正常にアクセスできました。
既にStartSSL導入済みのサイトでは niginx.conf の以下の点を変更することでHTTP2を有効にできました。
vim /etc/nginx/conf.d/www.example.com.conf
-listen 443 ssl;
+listen 443 ssl http2;
-ssl_ciphers HIGH:!aNULL:!MD5;
+ssl_ciphers AESGCM:HIGH:!aNULL:!MD5;
また、ちょうど Let’s Encrypt が公開されたので新規のSSLはこちらはで取得してみることにします。
まずは任意の場所で公式のリポジトリからデータを取得します。
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
letsencrypt-auto コマンドを実行すると依存ライブラリが自動的にインストールされます。
./letsencrypt-auto --help
# 問答無用で突然インストールが始まるので心臓に悪いです…
インストール中にものすごい数の warning がでるのですが、これは動作には Python2.7 が必要なためです。
自分の環境は CentOS 6.7 で、 yum の標準リポジトリ経由では 2.6 までしかアップデートできないため、IUS リポジトリを追加して、Python 2.7 をインストールしました。
rpm -UhV https://centos6.iuscommunity.org/ius-release.rpm
yum install --enablerepo=ius python27 python27-devel python27-pip python27-setuptools python27-virtualenv
これで warnning も出ずに平穏に証明書の生成ができます。
証明書の発行コマンドを打ち込むと
./letsencrypt-auto certonly --webroot -d www.example.com --webroot-path /path/to/public_html
何かエラーが返ってきました。
IMPORTANT NOTES:
- The following 'urn:acme:error:unauthorized' errors were reported by
the server:
Domains: www.example.com
Error: The client lacks sufficient authorization
これは nginx.conf で ドットから始まるリソースへのアクセスを制限しているために発生したエラーでした。
location ~ /\. {
deny all;
log_not_found off;
access_log off;
}
こんな記述をしていると403エラーで正常に処理が完了しません。
nginx.conf に letsencrypt が生成して利用する .well-known/acme-challenge ディレクトリのみ、アクセスを開放する記述を追記します。
location ^~ /.well-known/acme-challenge/ {
allow all;
}
再度証明書の発行コマンドを実行したら、めでたく証明書が発行されました。
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/www.example.com/fullchain.pem. Your cert will
expire on YYYY-MM-DD. To obtain a new version of the certificate in
the future, simply run Let's Encrypt again.
nginx.conf の server 以下、発行された証明書を参照するSSLの記述を追加します。
-listen 443 ssl;
+listen 443 ssl http2;
+ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
+ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
+ssl_session_cache shared:SSL:1m;
+ssl_session_timeout 5m;
+ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA;
+ssl_prefer_server_ciphers on;
nginx を再起動してサイトがSSLでアクセスできることを確認できました。
service ngingx restart
また、Let’s Encrypt の証明書は3か月で有効期限が切れるため、crontab で定期的に証明書の更新コマンドを実行するようにします。
crontab -e
0 0 1 * * /[letsencryptのインストールパス]/letsencrypt-auto certonly --webroot --agree-tos -w /path/to/public_html -d www.example.com --renew-by-default && service nginx reload
参考サイト
- http://boel.jp/tips/vol36_php7.html
- http://mitpage.seesaa.net/article/353421367.html
- http://blog.sunone.me/2011/06/07/php-peclをインストールする/
- https://github.com/phpbrew/phpbrew/blob/master/README.ja.md
- https://github.com/phpbrew/phpbrew/wiki/Requirement#cent-os-requirement
- http://qiita.com/dimgraycat/items/6154cd3a19b0b6cb8c17
- http://www.karakaram.com/mac-install-phpbrew
- http://inside.pixiv.net/entry/2015/12/10/153114
- http://inaba-serverdesign.jp/blog/20151217/lets-encrypt.html
- https://community.letsencrypt.org/t/redhat-centos-6-x-users-need-python-2-7/2190
- https://github.com/letsencrypt/acme-spec/issues/221
- http://qiita.com/TsutomuNakamura/items/4166423699061e38d296