無料Wikiサービス | デモページ
Linuxなどのメモ書き

ApacheでのHTTP/2設定


概要

ApacheでHTTP/2を設定した時のメモ。

Fedora23で行った。Fedora 23ではhttpdはVer. 2.4.18で、mod_http2が組み込まれているため、設定の変更のみでHTTP/2が使えるようになる。

http通信(暗号化なし)での設定

まずは暗号化をしないhttp通信での設定。HTTP/2を使いたいVirtualHostかServer Configに以下の設定を追加するだけでよい(設定変更後のreload等の細かい手順は省略)。

Protocols h2c http/1.1
ProtocolsHonorOrder On

h2cはHTTP/2を使ったhttp通信を意味する。

次にHTTP/2での接続を確認する。

HTTP/2をサポートしたブラウザにはChrome,FireFoxがあるが、これらのブラウザは、http://へのHTTP/2接続をサポートしていないため、curlコマンドで確認する。curlは--http2オプションをつければ、HTTP/2での接続を試みる。

$ curl -v --http2 http://test.bit-hive.com/
*   Trying 127.0.0.1...
* Connected to test.bit-hive.com (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: test.bit-hive.com
> User-Agent: curl/7.43.0
> Accept: */*
> Connection: Upgrade, HTTP2-Settings
> Upgrade: h2c
> HTTP2-Settings: AAMAAABkAAQAAP__
> 
< HTTP/1.1 101 Switching Protocols
< Upgrade: h2c
< Connection: Upgrade
* Received 101
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=28
* http2_recv: 16384 bytes buffer at 0x557636819ba8 (stream 1)
* http2_recv: returns 390 for stream 1
< HTTP/2.0 200
< date:Mon, 01 Feb 2016 13:05:52 GMT
< server:Apache/2.4.18 (Fedora) OpenSSL/1.0.2e-fips PHP/5.6.16
< last-modified:Wed, 27 Jan 2016 10:35:34 GMT
< etag:"8d-52a4e5cb89cbe"
< accept-ranges:bytes
< content-length:141
< content-type:text/html

クライアントからのリクエストでConnection: Upgrade, HTTP2-Settings, Upgrade: h2cを送信し、HTTP/2へのアップグレードを試みているのがわかる。サーバーからのレスポンスではHTTP/1.1 101 Switching Protocolsが返り、HTTP1.1からHTTP/2への変更を受け付けている。

https通信(SSL通信)での設定

次はhttps通信での設定。VirtualHostに以下の設定を追加する。

Protocols h2 http/1.1
ProtocolsHonorOrder On

httpでの設定と違うのはh2cとh2。h2はHTTP/2を使ったhttps通信を意味する。

これで、curlを使って接続を確認してみる。先程と同じように--http2を付けて接続を試みる。SSL証明書がダミーのものなので、証明書のチェックをスキップするため、以下の例では、--insecureを付けている。

$ curl -v --insecure --http2 https://test.bit-hive.com/
*   Trying 127.0.0.1...
* Connected to test.bit-hive.com (127.0.0.1) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* ALPN, server accepted to use h2
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
* Server certificate:
* 	subject: E=root@localhost.localdomain,CN=localhost.localdomain,OU=SomeOrganizationalUnit,O=SomeOrganization,L=SomeCity,ST=SomeState,C=--
* 	start date:  1月 29 06:43:04 2016 GMT
* 	expire date:  1月 28 06:43:04 2017 GMT
* 	common name: localhost.localdomain
* 	issuer: E=root@localhost.localdomain,CN=localhost.localdomain,OU=SomeOrganizationalUnit,O=SomeOrganization,L=SomeCity,ST=SomeState,C=--
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x56020bac3260)
> GET / HTTP/1.1
> Host: test.bit-hive.com
> User-Agent: curl/7.43.0
> Accept: */*
> 
* http2_recv: 16384 bytes buffer at 0x56020bac3ba8 (stream 1)
* HTTP/2 stream 1 was not closed cleanly: error_code = 8
* Closing connection 0
curl: (16) HTTP/2 stream 1 was not closed cleanly: error_code = 8

 https通信では、http通信時とは異り、アップグレードではなく、ALPNというTLS拡張機能を使って、接続プロトコルを指定する。上記ログの"ALPN, server accepted to use h2"からHTTP/2で接続しようとしていることがわかる。

ただ、最終的には、接続が中断されていることがわかる("HTTP/2 stream 1 was not closed cleanly: error_code = 8")。これは、接続時にTLS_ECDHE_RSA_WITH_AES_256_CBC_SHA(ログの"SSL connection using TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"より)という暗号スイートが選択されたため。RFC 7540 Appendix A. によると、暗号スイートのブラックリストが列挙されているが、このブラックリストに入っている暗号スイートが選択された場合は、接続エラー(INADEQUATE_SECURITY)とすることになっている。TLS_ECDHE_RSA_WITH_AES_256_CBC_SHAはこのブラックリストに入っているため、接続が切断されている。

そこで、ブラックリストにはないTLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256を使って接続するように、--cipherオプションを指定するとHTTP/2で正常に接続できるようになる。

# curl -v --insecure --cipher ecdhe_rsa_aes_128_gcm_sha_256 --http2 https://test.bit-hive.com/
*   Trying 127.0.0.1...
* Connected to test.bit-hive.com (127.0.0.1) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* ALPN, server accepted to use h2
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
<略>
< HTTP/2.0 200
< date:Mon, 01 Feb 2016 13:41:20 GMT
< server:Apache/2.4.18 (Fedora) OpenSSL/1.0.2e-fips PHP/5.6.16
< last-modified:Wed, 27 Jan 2016 10:35:34 GMT
< etag:"8d-52a4e5cb89cbe"
< accept-ranges:bytes
< content-length:141
< content-type:text/html; charset=UTF-8

ただ、上記のようにクライアント側で暗号スイートを指定しないといけないのは具合が悪い。特にChromeやFireFoxなどのブラウザからアクセスする場合は、暗号スイートを細かく指定することはできない。

このため、ApacheのSSLCipherSuiteを適切に設定し、ブラックリストに載っていない暗号スイートが優先的に選択されるように設定しておく必要がある。

Fedora23のデフォルトの設定では"SSLCipherSuite PROFILE=SYSTEM"のようになっている。PROFILE=SYSTEMは何かというと、Fedora独自のcrypto policyという仕組みを使って、システム全体の設定を参照している。具体的には以下のような設定と同じになっている。crypto policyについての詳細はここでは省くので、こちらを参照のこと。

デフォルトのCipher Suite設定

SSLCipherSuite !SSLv2:kEECDH:kRSA:kEDH:kPSK:+3DES:!aNULL:!eNULL:!MD5:!EXP:!RC4:!SEED:!IDEA:!DES

この設定を変更して、ブラックリストに載っていない暗号スイートが選択されるようにする。今回は楽をして、crypto policyをDEFAULTからFUTURE(よりセキュリティレベルの高い設定)に変更することで対応する。

crypto policyを変更するには/etc/crypto-policies/configの設定をFUTUREに変えて、update-crypto-policiesを実行すればよい。これで、ポリシーは変更されるが、httpdにも反映させるために、reloadしてconfigを再読み込みさせてやる。

crypto policy変更の反映

# update-crypto-policies
Setting system policy to FUTURE
# service httpd reload

これでSSLCipherSuiteは以下の設定と等価になる。Fedora以外で設定する場合でも、SSLCipherSuiteを以下の設定にすれば、とりあえず接続はできるようになるはず。

crypto policyをFUTUREに変更後のSSLCipherSuite設定

SSLCipherSuite !SSLv2:!SSLv3:kEECDH:kRSA:kEDH:kPSK:!aNULL:!eNULL:!3DES:!MD5:!EXP:!RC4:!SEED:!IDEA:!DES

この状態で再度、curlからアクセスをしてみる。

$ curl -v --insecure --http2 https://test.bit-hive.com/
*   Trying 127.0.0.1...
* Connected to test.bit-hive.com (127.0.0.1) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* ALPN, server accepted to use h2
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* 	subject: E=root@localhost.localdomain,CN=localhost.localdomain,OU=SomeOrganizationalUnit,O=SomeOrganization,L=SomeCity,ST=SomeState,C=--
* 	start date:  1月 29 06:43:04 2016 GMT
* 	expire date:  1月 28 06:43:04 2017 GMT
* 	common name: localhost.localdomain
* 	issuer: E=root@localhost.localdomain,CN=localhost.localdomain,OU=SomeOrganizationalUnit,O=SomeOrganization,L=SomeCity,ST=SomeState,C=--
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x56338129a260)
> GET / HTTP/1.1
> Host: test.bit-hive.com
> User-Agent: curl/7.43.0
> Accept: */*
> 
* http2_recv: 16384 bytes buffer at 0x56338129aba8 (stream 1)
* http2_recv: 16384 bytes buffer at 0x56338129aba8 (stream 1)
* http2_recv: 16384 bytes buffer at 0x56338129aba8 (stream 1)
* http2_recv: returns 405 for stream 1
< HTTP/2.0 200
< date:Mon, 01 Feb 2016 14:14:25 GMT
< server:Apache/2.4.18 (Fedora) OpenSSL/1.0.2e-fips PHP/5.6.16
< last-modified:Wed, 27 Jan 2016 10:35:34 GMT
< etag:"8d-52a4e5cb89cbe"
< accept-ranges:bytes
< content-length:141
< content-type:text/html; charset=UTF-8

今回は--cipherを指定しなくても、暗号スイートにTLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256が選択されて、HTTP/2での接続が成功した。

Chromeからもアクセスして、chrome://net-internals/#http2 で確認したところ、ChromeからもHTTP/2で接続できていた。

Protocolsを指定しているはずなのに、ブラウザからHTTP/2で接続できずにHTTP/1.1になってしまうような場合は、どの暗号スイートが選択されているか確認してみるとよい。

 


最終更新 2016/02/02 18:47:43 - kztomita
(2016/02/01 22:16:27 作成)