nginx で HTTP/2 を動かしてみる。

Web サイト

Web サイト用の SSL 証明書を手に入れたので、以前から気になっていた HTTP/2 対応をしてみることにしました。

今回は nginx を使って HTTP/2 サーバーを個別に立ててみることにします。


先日に SSL 用の電子証明書を手に入れたので、せっかくなので Web サーバーの HTTP/2 対応を試みてみました。HTTP/2 を導入すると従来よりも Web の応答速度が改善されるらしいので、それに期待です。

もともとの環境は CentOS 5.11 + apache 2.2.3 で、既存の運用環境をいじって HTTP/2 対応を試みるには難がありそうだったので、今回は nginx を HTTP/2 専用で新たに立ち上げてみることにします。

まずは改善状況から

まず、実際に HTTP/2 対応を終わらせてみての改善状況から紹介すると、数値的にはそれほど変わらないような印象になりました。

ただし、体感的には apache のときより nginx に変えたときの方が、ずいぶん早くページをみられるような印象がします。もっとも、HTTP/2 を有効化する前からそんな印象だったので、単純に apache を nginx に置き換えたことが功を奏した可能性もありそうです。

画像の多いサイト

この頃に更新した画像をふんだんに使ったページで速度を計測してみたのですけど、結果的には apache の HTTP/1.1 の方が nginx の HTTP/2.0 で接続したときの方が、トータルで時間がかかる様子ででした。

まず、CentOS 5.11 + apache 2.2.3 + TLSv1.0 で SSL 接続したときは、HTTP/1.1 接続で 47.63 秒になりました。

それに対して CentOS 5.11 + nginx 1.3.9 + TLSv1.2 で SSL 接続したときは、HTTP/2.0 接続で 53.79 秒と、もともとの apache 2.2.3 よりも時間がかかってしまう様子でした。

ただ、読み込み状況のグラフは明らかに印象が違っているようにも見えます。最後まで残っているのは、画像の読み込みみたいな感じなので、早い段階でページをみられるようになったりしているのかもしれません。

テキストの多いサイト

もしかして画像がたくさんあるのが問題なのかと思い、この頃にアップしたテキストが大半を占めるページで速度を計測してみたところ、こちらは apache の HTTP/1.1 と比べて nginx の HTTP/2.0 の方がわずかに速い結果になりました。

まず、CentOS 5.11 + apache 2.2.3 + TLSv1.0 で SSL 接続したときは、HTTP/1.1 接続で 5.74 秒になりました。計測完了と出た後も何かデータを受信している様子ですが。

それに対して CentOS 5.11 + nginx 1.3.9 + TLSv1.2 で SSL 接続したときは、HTTP/2.0 接続で 4.42 秒と、誤差の範囲かもしれませんが、わずかながら速度の改善がみられます。こちらも計測完了と出た後も何か受信している様子ですけど、さきほどの場合と同じような印象でした。

対応状況を確認してみる

HTTP/2 に対応させたつもりですけど、表面から見ても本当に対応できているかがわからないので、調べる方法を探してみました。

H2Check

そうしたところ H2Check - test your site for HTTP/2 support というサイトが見つかったので試してみたのですけど、結果は No support for HTTP/2 was found になってしまいました。

今のところ、理由はよくわかりません。

HTTP/2 and SPDY indicator (Firefox)

Firefox に HTTP/2 and SPDY indicator というプラグインがあったので試してみると、こちらは、アドレスバーの稲妻マークにマウスをのせると HTTP/2 is active for the top-level document と表示されました。

こちらで確認する限りは、HTTP/2 に対応できていそうな様子です。

HTTP/2 and SPDY indicator (Google Chrome)

Google Chrome にも HTTP/2 and SPDY indicator というプラグインがあったので試してみました。

こちらについても、アドレスバーの稲妻マークにマウスをのせると HTTP/2-enabled と表示され、問題なさそうな様子です。さらにマークをクリックすると、HTTP/2 のキャプチャ状況が表示され、よりそれらしく対応していそうな様子が窺えました。

nginx をインストールする

そんな感じの結果になりましたけど、ともあれ nginx 1.3.9 を CentOS 5.11 で動かすまでの道のりを記しておくことにします。

OpenSSL 1.0.2 をインストールする

CentOS 5.11 は標準で OpenSSL 0.9.8 がインストールされている様子でしたけど、TLSv1.1 以上を使うには OpenSSL 1.0.1 以上が必要になるようだったので、今回は手作業で、最新の OpenSSL をインストールすることにします。

OpenSSL は こちら からダウンロードできるようになっています。今回は 時点で最新の 1.0.2 をインストールすることにしました。


まずは次のようにして、/usr/local/src に OpenSSL 1.0.2d のソースファイルをダウンロードします。

cd /usr/local/src
wget https://www.openssl.org/source/openssl-1.0.2d.tar.gz

そして、ダウンロードしたアーカイブを展開して、出来上がったディレクトリに移動します。

tar xvzf openssl-1.0.2d.tar.gz
cd openssl-1.0.2d

あとは、次のようにして OpenSSL をインストールすれば完了です。

./config --prefix=/usr --openssldir=/etc/pki/tls shared
make
make install

新しいバージョンに差し替えられたかは openssl version を実行することで確認できます。

PCRE ライブラリをインストールする

nginx で URL の書き換え機能を使うには、PCRE (Perl Compatible Regular Expressions) ライブラリをインストールする必要があるようです。

CentOS 5.11 では yum を使って、次のようにして簡単に pcre.i386 0:6.6-9.el5 をインストールできます。

yum install pcre pcre-devel

pcre だけでなく pcre-devel パッケージが必要なところに注意が必要です。このライブラリがインストールされていないと、nginx の configure の手続きのときに、次のようなエラーメッセージが表示されることになります。

./configure: error: the HTTP rewrite module requires the PCRE library.

You can either disable the module by using --without-http_rewrite_module

option, or install the PCRE library into the system, or build the PCRE library

statically from the source with nginx by using --with-pcre=<path> option.

nginx をインストールする

まずは nginx のプロセスを動かすのに使うアカウントを登録しておくことにします。

groupadd nginx
useradd -s /sbin/nologin -g nginx -d /usr/local/nginx nginx

そして nginx のソースコードを取得します。nginx の HTTP/2 サポートはパッチを当てることで対応できるようなので、それぞれを次の URL からダウンロードすることになります。

今回は 時点で最新の nginx 1.9.4 と、それ用の HTTP/2 対応パッチをダウンロードすることにしました。

cd /usr/local/src

wget http://nginx.org/download/nginx-1.9.4.tar.gz
wget http://nginx.org/patches/http2/patch.http2-v6_1.9.4.txt

ダウンロードしたら nginx を展開して、作成されたディレクトリに移動し、パッチを当てます。

tar zxvf nginx-1.9.4.tar.gz
cd nginx-1.9.4

patch -p1 < ../patch.http2-v6_1.9.4.txt

そして、コンパイルに必要な下準備を行います。なるべく CentOS 環境に合うようにオプションをたくさん指定していますが、今回は HTTP/2 対応が目的なので --with-http_v2_module が特に大切なところかもしれません。

./configure --with-http_ssl_module --with-http_v2_module --prefix=/usr/local/nginx --user=nginx --group=nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --pid-path=/var/run/nginx.pid --lock-path=/var/lock/subsys/nginx

このようにすると、コンパイル環境が次のように設定されました。

Configuration summary
  + using system PCRE library
  + using system OpenSSL library
  + md5: using OpenSSL library
  + sha1: using OpenSSL library
  + using system zlib library

  nginx path prefix: "/usr/local/nginx"
  nginx binary file: "/usr/sbin/nginx"
  nginx configuration prefix: "/etc/nginx"
  nginx configuration file: "/etc/nginx/nginx.conf"
  nginx pid file: "/var/run/nginx.pid"
  nginx error log file: "/var/log/nginx/error.log"
  nginx http access log file: "/var/log/nginx/access.log"
  nginx http client request body temporary files: "client_body_temp"
  nginx http proxy temporary files: "proxy_temp"
  nginx http fastcgi temporary files: "fastcgi_temp"
  nginx http uwsgi temporary files: "uwsgi_temp"
  nginx http scgi temporary files: "scgi_temp"

ここまでできたら、次のようにしてコンパイルとインストールを行います。

make
make install

nginx を設定して HTTP/2 を有効化する

nginx のインストールができたら、続いて nginx の設定を行います。

SSL で使う電子証明書を用意する

今回は SSL を有効化しようと思うので、それに必要な電子証明書を準備します。

SSL で使用する電子証明書は こちら で取得した Rapid SSL のものを使うことにします。


Rapid SSL の電子証明書の場合は中間 CA 証明書も必要になりますけど、nginx では、サイト用の電子証明書と中間 CA 証明書を 1 つのファイルにまとめる必要があるようなので、次のようにしてひとつにまとめた電子証明書ファイルを作成します。

たとえば、サイト用の電子証明書が ez-net.jp.crt というファイルで、中間 CA 証明書が rapidssl.crt というファイルで用意されているときに、それらをまとめた電子証明書ファイル ez-net.jp+rapidssl.crt を作成します。

(cat ez-net.jp.crt; echo; cat rapidssl.crt) > ez-net.jp+rapidssl.crt

このようにすることで、次のような内容のファイルが出来上がります。

-----BEGIN CERTIFICATE-----
MIIElTCCA32gAwIBAgIDBww5MA0GCSqGSIb3DQEBCwUAMEcxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMSAwHgYDVQQDExdSYXBpZFNTTCBTSEEy
NTYgQ0EgLSBHMzAeFw0xNTA5MTkxMTM2NTFaFw0xODA5MjAxMTEwMDBaMIGNMRMw
EQYDVQQLEwpHVDQwNTAyMDAyMTEwLwYDVQQLEyhTZWUgd3d3LnJhcGlkc3NsLmNv
g6GJR0Mfz2MKKXTRmeW7PWiu8PA9QjTouA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEJTCCAw2gAwIBAgIDAjp3MA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
YWwgQ0EwHhcNMTQwODI5MjEzOTMyWhcNMjIwNTIwMjEzOTMyWjBHMQswCQYDVQQG
ZI3NjGFVkP46yl0lD/gdo0p0Vk8aVUBwdSWmMy66S6VdU5oNMOGNX2Esr8zvsJmh
gP8L8mJMcCaY
-----END CERTIFICATE-----

nginx.conf を調整する

電子証明書の準備ができたら、設定ファイル /etc/nginx/nginx.conf を調整します。

今回は通常の http アクセスは受け付けないようにしようと思うので、既定で有効化されている http 関連の server 設定はざっくりとコメントアウトしておくことにします。

    #server {
    #    listen       80;
    #    server_name  localhost;
    #
    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

そして HTTP/2 で使う SSL 周りの設定を、次のように有効化しました。

    server {
        listen       443 ssl http2;
        server_name  ez-net.jp;

        ssl_certificate      /etc/pki/tls/certs/ez-net.jp+rapidssl.crt;
        ssl_certificate_key  /etc/pki/tls/private/ez-net.jp.key;

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_ciphers  AESGCM:HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;

        access_log /var/log/nginx/ez-net.jp.ssl.log;
        error_log /var/log/nginx/ez-net.jp.ssl.error.log;

        location / {
            root   /home/ez-net/public_html;
            index  index.html;
        }
    }

設定する上で気をつけたいところは次のとおりです。

設定が正しいかテストする

設定が終わったら、次のようにすると、設定内容が正しいかどうか確認できます。

nginx -t

秘密鍵にパスフレーズが設定されている場合は、ここで Enter PEM pass phrase: と聞かれるのでパスフレーズを入力します。

そうすると、設定内容が書式的に正しい場合は、次のようなメッセージが表示されます。

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

nginx を起動する

設定ファイルを準備できたら、いよいよ nginx の起動です。

起動スクリプトを用意する

nginx を起動するにあたっては、起動スリプトを用意したいところです。

nginx の起動スクリプトは、公式からも Red Hat NGINX Init Script | NGINX で公開されてるようでした。

CentOS は RedHat 互換でもありますし、先ほど nginx をインストールする過程でパスなども調整しておいてあるので、この起動スクリプトをそのまま使えそうです。


上記のページから閲覧できる起動スクリプトの内容を /etc/init.d/nginx という名前で保存して、実行権限を次のようにして与えておきます。

chmod +x /etc/init.d/nginx

念のため nginx.txt にも 時点での内容を残しておきます。

nginx を起動する

起動スクリプトを用意したら、次のようにして nginx を起動できるようになります。

service nginx start

これで nginx が起動します。

SSL で使う秘密鍵にパスフレーズが設定されている場合は、起動するたびに入力を求められます。正しいパスフレーズを入力することで nginx が起動します。

OS 起動時に nginx を自動起動する

起動スクリプトを用意したら、次のようにすることで、Linux 起動時に nginx が自動で起動されるようになります。

chkconfig --add nginx
chkconfig nginx on

これで、起動スクリプトに関する準備は完了です。

もし秘密鍵にパスフレーズが設定されていると、起動のたびにその入力を求められます。それを避けるためには、秘密鍵からパスフレーズを削除したり、nginx 起動時にパスフレーズを自動入力するなどの対処が必要になります。

秘密鍵からパスフレーズを削除する方法は Apache 2 で SSL 電子証明書のパスフレーズ入力を省略する の中に記してあります。

nginx 起動時にパスフレーズを自動入力させる方法は こちら に記してあります。