HTTP/2 WEBサーバ設定メモ【Nghttp2 (nghttpd) + CentOS 7】

Linux
Linux
スポンサーリンク

HTTP/2 は「WEBの高速化、通信量の削減、安全な接続」を目的とした、WEB通信プロトコルの最新バージョンです。2015年2月17日に、IETFの運営グループにより正式な仕様として承認されました。これまで長い間 HTTP/1.1 が使われていましたが、16年ぶりのバージョンアップになります。そこで今回は、HTTP/2 の実装として有名な Nghttp2 の nghttpd を使って、HTTP/2 WEBサーバを設定してみました。

(更新)2017年5月14日 各種インストール手順を最新版に更新しました。

HTTP/2 の特徴

HTTP/2 には以下の特徴があります。

バイナリフレームの採用
ストリームによる多重化
ヘッダー圧縮
サーバープッシュ
ストリームの優先度

HTTP/2 入門 - Yahoo! JAPAN Tech Blog より引用

HTTP/1.1 では、同時に処理できるリクエストは4〜6程度でしたが、HTTP/2では「ストリームによる多重化」により同時に100以上のリクエストを処理できるそうです。

HTTP/2 の普及状況

HTTP/2 に対応しているWEBブラウザ

Firefox、Chrom、IEなど、ほとんどWEBブラウザの最新バージョンでは、HTTP/2 に対応しています。http://caniuse.com/#search=HTTP%2F2(2015年4月14日現在)
http2-01

 
また、各WEBブラウザは、HTTP/2 接続にはTLS(SSL)暗号化通信を必須としていますので、HTTP/2 のWEBサーバには、SSLサーバ証明書が必要になります。

HTTP/2 を使っている主なWEBサイト

WEBサイトで HTTP/2 が使われているかを確認するには、Firefox用の機能拡張「HTTP/2 Indicator 」が便利です。インストールすると、HTTP/2 が使われている場合は、アドレスバーの右側に、青い稲妻マークが表示されます。
http2-02

この青い稲妻を頼りに、HTTP/2 の対応状況を調べてみると、Google、Twitter、Facebook(SPDY3.1) など、膨大な通信量があるWEBサイトで、導入が進んでいるようです。特にGoogleについては、HTTP/2 の元となった SPDY(スピーディ)を開発していたこともあって、ほとんどのサービスで、HTTP/2 が使われています。

Nghttp2 について

HTTP/2 サーバの実装は、数多く公開されていますが、その中でも Nghttp2 は、HTTP/2 プロトコルの実装の最有力とされているようです。tatsuhiro-t さんという日本の方が、開発されています。

Nghttp2 には、HTTP/2 対応のクライアント、サーバ、プロキシー、ベンチマーキングツールが含まれています。今回は、そのうち HTTP/2 サーバの「nghttpd」を使います。

開発ツールのインストール

サーバOSは CentOS7.3 (1611) です。CentOS6系は、ライブラリが古いため Nghttp2 のインストールが大変そうだったので、あきらめました。(^^;)

Nghttp2 はソースからコンパイルしますので、基本コマンドと開発ツールをインストールしておきましょう。

yum -y groupinstall base
yum -y groupinstall development

OpenSSL 1.0.2 のインストール

ALPN(Application-Layer Protocol Negotiation)に対応している、OpenSSLバージョン1.0.2以上をインストールします。

Google Chrome バージョン51以降は、NPNが削除され、ALPNのみ対応となったようですので、WEBサーバでHTTP/2を使うには、事実上OpenSSL1.0.2以上が必須になります。
Transitioning from SPDY to HTTP/2 | Chromium Blog

 
まずはじめに OpenSSLのコンパイルに zlib を使うので、インストールしておきます。

yum -y install zlib-devel

OpenSSLのインストール(そこそこの時間がかかります)

cd /usr/local/src/
wget https://www.openssl.org/source/openssl-1.0.2k.tar.gz
tar xvzf openssl-1.0.2k.tar.gz
cd openssl-1.0.2k/
./config --prefix=/usr/local/openssl-1.0.2k shared zlib
make depend
make
make test
make install

OpenSSL1.0.2 のライブラリにパスを通しておきます。

echo /usr/local/openssl-1.0.2k/lib > /etc/ld.so.conf.d/openssl102k.conf
ldconfig

Nghttp2 (nghttpd) のインストール

Nghttp2 が必要とするライブラリのインストール

yum -y install libev-devel c-ares-devel

Nghttp2 のダウンロード
※頻繁にバージョンアップされているようです。ダウンロードの前に最新リリースを確認しましょう。
https://github.com/tatsuhiro-t/nghttp2/releases/latest

cd /usr/local/src/
wget https://github.com/nghttp2/nghttp2/releases/download/v1.22.0/nghttp2-1.22.0.tar.gz

Nghttp2 のインストール。環境変数 OPENSSL_CFLAGS と OPENSSL_LIBS に先ほどインストールした、OpenSSL1.0.2 のディレクトリパスを指定してコンパイルします。また nghttpd をコンパイルするため「-enable-app」オプションを付けます。

tar xvzf nghttp2-1.22.0.tar.gz
cd nghttp2-1.22.0/
env OPENSSL_CFLAGS="-I/usr/local/openssl-1.0.2k/include" OPENSSL_LIBS="-L/usr/local/openssl-1.0.2k/lib -lssl -lcrypto" ./configure -enable-app
make
make install

/usr/local/bin/ 下に、「nghttpd」などの Nghttp2 のコマンド群がインストールされます。

SSLサーバ証明書(自己署名)の作成

前述しましたが、HTTP/2 を使ったWEBサーバには、SSLサーバ証明書が必須です。

(2015年12月15日追記)正規の認証局が発行した、サーバー証明書を無料で取得できるようになりました。よければご参照ください → Let's Encrypt サーバー証明書の取得と自動更新設定メモ

・秘密鍵の作成

openssl genrsa 2048 > server.key 

・CSR(証明書署名要求)の作成

openssl req -new -key server.key > server.csr
---下記を入力--------------------------- 
Country Name (2 letter code) [XX]:JP 
State or Province Name (full name) []:<空エンター> 
Locality Name (eg, city) [Default City]:<空エンター> 
Organization Name (eg, company) [Default Company Ltd]:<空エンター> 
Organizational Unit Name (eg, section) []:<空エンター> 
Common Name (eg, your name or your server's hostname) []:<ドメイン名> 
Email Address []:<空エンター> 

Please enter the following 'extra' attributes 
to be sent with your certificate request 
A challenge password []:<空エンター> 
An optional company name []:<空エンター> 
------------------------------ 

・SSLサーバ証明書の作成(有効期限10年)

openssl x509 -days 3650 -req -signkey server.key < server.csr > server.crt 

・秘密鍵とSSLサーバ証明書を適当な場所に移動

mv -i server.key /etc/pki/tls/private/ 
mv -i server.crt  /etc/pki/tls/certs/ 

・セキュリティ確保のため nghttpd の実行ユーザ「nghttp2」を作成

useradd -d /run/nghttp2 -s /sbin/nologin nghttp2

・秘密鍵とSSLサーバ証明書のオーナーを「nghttp2」ユーザに変更

chown nghttp2:nghttp2 /etc/pki/tls/private/server.key
chown nghttp2:nghttp2 /etc/pki/tls/certs/server.crt
chmod 600 /etc/pki/tls/private/server.key 
chmod 600 /etc/pki/tls/certs/server.crt 

・CSRを削除

rm server.csr  

nghttpd の設定

・nghttpd の設定ファイルを作成します。
vi /etc/sysconfig/nghttpd

# worker スレッド数 
WORKERS=1 

# ドキュメントルート 
HTDOCS=/var/www/html 

# 待受ポート番号 
PORT=8080 

# サーバ秘密鍵 
PRIVATE_KEY=/etc/pki/tls/private/server.key 

# サーバ証明書 
CERT=/etc/pki/tls/certs/server.crt

・nghttpd 用の systemd設定ファイルを作成します。
vi /etc/systemd/system/nghttpd.service

[Unit] 
Description=nghttpd 
After=network.target 

[Service] 
Type=simple
User=nghttp2
EnvironmentFile=-/etc/sysconfig/nghttpd 
ExecStart=/usr/local/bin/nghttpd -n $WORKERS -d $HTDOCS $PORT $PRIVATE_KEY $CERT 

[Install] 
WantedBy=multi-user.target 

・上記設定を systemd に反映

systemctl daemon-reload 

・systemd に反映されているか確認

systemctl list-unit-files | grep nghttpd 
---(下記のような表示であればOKです)--------------------------- 
nghttpd.service                             disabled 

・起動

systemctl start nghttpd

・自動起動設定

systemctl enable nghttpd 

・「nghttp2」ユーザで、nghttpd が実行されているかを確認します。

ps aux | grep nghttpd
---(下記のような表示であればOKです)---------------------------
nghttp2  22977  0.0  0.1  52816  3532 ?        Ss   5:54   0:00 /usr/local/bin/nghttpd -n 1 -d /var/www/html 8080 /etc/pki/tls/private/server.key /etc/pki/tls/certs/server.crt
 

・動作確認
「https://<サーバのアドレス>:8080」に、WEBブラウザで接続して確認します。ドキュメントルートに、なにもファイルが無ければ、以下の様に表示されます。しっかり HTTP/2 を示す青い稲妻マークが表示されていますね。
http2-03-02

※サーバに接続できない場合は、firewallでブロックされているかもしれません。以下のコマンドで8080/tcp の接続を許可しておきましょう。

 
firewall-cmd --add-port=8080/tcp --permanent 
firewall-cmd --reload

終わりに

HTTP/2 の話からは外れますが、Nghttp2 関連コマンドの manマニュアルが、とても分かりやすく書いてあるので、英語が苦手な私でも、少しの時間でオプションの内容を理解することが出来ました。

Cのコードがあまり読めない私(^^;)としては、マニュアルが分かりやすい Nghttp2 が HTTP/2 WEBサーバの定番になって欲しいものです。

次回は、今回設定した HTTP/2 WEBサーバ と、HTTP/1.1のWEBサーバとの、スピート比較をしてみたいと思います。

コメント

  1. 匿名希望 より:

    Google Chrome 51以降のバージョンでは、NPNがサポートされなくなったこと(https://ma.ttias.be/chrome-drops-npn-support-for-http2-alpn-only/ および https://osdn.jp/magazine/16/05/27/202000)を理由としてこの方法を変える必要がありそうです。
    実際、私のホームページはCentOSのリポジトリからもってきたnginxを利用していましたが、opensslを起因としてhttp2通信ができなくなったので、ソースコードからコンパイルする方法に切り替えました。
    CentOSのopensslが古いことが原因なので、1.0.2以降をソースコードからひっぱってきてコンパイルするか、libresslやboringsslなどのフォークプロジェクトを利用するのがよさそうです(私はlibresslに切り替えました)。

タイトルとURLをコピーしました