h2oによるhttp/2に対応した備忘録。
主要ブラウザは、HTTP/2に対応しているが、HTTP/2 over TLSのみなので、
SSLサーバ証明書が必要になる。
そのため、証明書には最近話題のLet’s Encrypt を利用した。

SSLサーバ証明書を発行

Let’s Encryptのソースをgitリポジトリからcloneしてくる。

1
2
# cd /usr/local/
# git clone https://github.com/letsencrypt/letsencrypt

Let’s Encrypt の依存するパッケージを自動でインストールする。

1
2
# cd letsencrypt
# ./letsencrypt-auto --help

証明書を作成するために、ドメインへのアクセスがあるのでアクセスできるようにしておく。
h2oのでのアクセスログは以下のようなログだった。

1
192.168.0.1 - - [10/Feb/2016:10:04:11 +0900] "GET /.well-known/acme-challenge/4cHoLYVoyqHvhKcW7zMz08ixIUfxT3cO5uQc6wx-cYk HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"

証明書発行のコマンドは以下。

1
2
3
4
5
# ./letsencrypt-auto certonly \
--webroot -w /var/www/html/example.com/ \ # ドキュメントルート
-d example.com \ # FQDN
-m hoge@example.com \ # メールアドレス
--agree-tos # Let's Encryptの利用規約に同意する。

なんらかの原因でアクセスできない場合は以下のようなエラーになる。

1
2
3
4
5
6
7
8
9
10
11
12
# ./letsencrypt-auto certonly --webroot -w /var/www/html/example.com/ -d example.com -m hoge@example.com --agree-tos
Updating letsencrypt and virtual environment dependencies......
Requesting root privileges to run with virtualenv: /root/.local/share/letsencrypt/bin/letsencrypt certonly --webroot -w /var/www/html/example.com/ -d example.com -m hoge@example.com --agree-tos
Failed authorization procedure. example.com (http-01): urn:acme:error:connection :: The server could not connect to the client to verify the domain :: Could not connect to http://example.com/.well-known/acme-challenge/QlsKdh9xfkuDr2mm-iIEyC58ep0tsy2gqX3K1nhJo0M

IMPORTANT NOTES:
- The following errors were reported by the server:

Domain: example.com
Type: urn:acme:error:connection
Detail: Could not connect to http://example.com/.well-known
/acme-challenge/QlsKdh9xfkuDr2mm-iIEyC58ep0tsy2gqX3K1nhJo0M

ちなみに今回は、firewallで弾かれていたので、80/443ポートを解放してあげた。

1
2
3
# firewall-cmd --permanent --add-port 80/tcp
# firewall-cmd --permanent --add-port 443/tcp
# systemctl restart firewalld.service

再度実行で、証明書が作成された。

1
2
3
4
5
6
7
8
9
10
11
12
13
# ./letsencrypt-auto certonly --webroot -w /var/www/html/example.com/ -d example.com -m hoge@example.com --agree-tos
Updating letsencrypt and virtual environment dependencies......
Requesting root privileges to run with virtualenv: /root/.local/share/letsencrypt/bin/letsencrypt certonly --webroot -w /var/www/html/example.com/ -d example.com -m hoge@example.com --agree-tos

IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/example.com/fullchain.pem. Your cert
will expire on 2016-05-10. To obtain a new version of the
certificate in the future, simply run Let's Encrypt again.
- If you like Let's Encrypt, please consider supporting our work by:

Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

証明書の実態は/etc/letsencrypt/archive/[ドメイン]配下にでき、 /etc/letsencrypt/live/[ドメイン] がsymlinkとなっている。設定する際は、/etc/letsencrypt/live/[ドメイン] を利用すると良い。

h2oの設定

/etc/h2o/h2o.conf にSSL証明書の設定をする。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
http2-casper: ON
http2-reprioritize-blocking-assets: ON
max-connections: 128
num-threads: 1
user: nobody
hosts:
"example.com":
listen: 80
listen:
port: 443
ssl:
certificate-file: /etc/letsencrypt/live/example.com/fullchain.pem
key-file: /etc/letsencrypt/live/example.com/privkey.pem
minimum-version: TLSv1
cipher-suite: 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:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
paths:
"/":
file.dir: /var/www/html/example.com
access-log: /var/log/h2o/access.log
error-log: /var/log/h2o/error.log
pid-file: /var/run/h2o/h2o.pid

h2oがうまく起動しない場合、 systemctl status h2o.service で確認する。以下は、keyファイル名を間違っていて起動できなかった時のログ(h2oのログには出なかった)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# systemctl status h2o.service
● h2o.service - H2O - the optimized HTTP/1, HTTP/2 server
Loaded: loaded (/usr/lib/systemd/system/h2o.service; enabled; vendor preset: disabled)
Active: failed (Result: exit-code) since 水 2016-02-10 10:27:27 JST; 1min 16s ago
Process: 2496 ExecStop=/bin/kill -TERM ${MAINPID} (code=exited, status=1/FAILURE)
Process: 9099 ExecReload=/bin/kill -HUP ${MAINPID} (code=exited, status=0/SUCCESS)
Process: 2495 ExecStart=/usr/bin/h2o -m master -c /etc/h2o/h2o.conf (code=exited, status=78)
Main PID: 2495 (code=exited, status=78)

210 10:27:27 example.com systemd[1]: Starting H2O - the optimized HTTP/1, HTTP/2 server...
210 10:27:27 example.com h2o[2495]: [/etc/h2o/h2o.conf:13] in command listen, failed to load private key file:/etc/letsencrypt/live/example.com/privkey1.pem
210 10:27:27 example.com h2o[2495]: 139896520619968:error:02001002:system library:fopen:No such file or directory:bio/bss_file.c:255:fopen('/etc/letsencrypt/live/cra...1.pem', 'r')
210 10:27:27 example.com h2o[2495]: 139896520619968:error:20074002:BIO routines:FILE_CTRL:system lib:bio/bss_file.c:257:
210 10:27:27 example.com h2o[2495]: 139896520619968:error:140B0002:SSL routines:SSL_CTX_use_PrivateKey_file:system lib:ssl_rsa.c:596:
210 10:27:27 example.com systemd[1]: h2o.service: main process exited, code=exited, status=78/n/a
210 10:27:27 example.com kill[2496]: kill: cannot find process ""
210 10:27:27 example.com systemd[1]: h2o.service: control process exited, code=exited status=1
210 10:27:27 example.com systemd[1]: Unit h2o.service entered failed state.
210 10:27:27 example.com systemd[1]: h2o.service failed.
Hint: Some lines were ellipsized, use -l to show in full.

該当箇所を修正後、無事にh2oが起動した。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# systemctl status h2o.service
● h2o.service - H2O - the optimized HTTP/1, HTTP/2 server
Loaded: loaded (/usr/lib/systemd/system/h2o.service; enabled; vendor preset: disabled)
Active: active (running) since 水 2016-02-10 10:29:31 JST; 28min ago
Process: 2496 ExecStop=/bin/kill -TERM ${MAINPID} (code=exited, status=1/FAILURE)
Process: 3155 ExecReload=/bin/kill -HUP ${MAINPID} (code=exited, status=0/SUCCESS)
Main PID: 2523 (perl)
CGroup: /system.slice/h2o.service
├─2523 perl -x /usr/share/h2o/start_server --pid-file=/var/run/h2o/h2o.pid --log-file=/var/log/h2o/error.log --port=0.0.0.0:80 --port=[::]:80 --port=0.0.0.0:443 --port=[::]:443 -- /usr/bin/...
├─3157 /usr/bin/h2o -c /etc/h2o/h2o.conf
├─3158 /usr/bin/h2o -c /etc/h2o/h2o.conf
└─3163 perl -x /usr/share/h2o/annotate-backtrace-symbols

210 10:29:31 example.com systemd[1]: Started H2O - the optimized HTTP/1, HTTP/2 server.
210 10:29:31 example.com systemd[1]: Starting H2O - the optimized HTTP/1, HTTP/2 server...
210 10:29:31 example.com h2o[2523]: start_server (pid:2523) starting now...
210 10:42:03 example.com systemd[1]: Reloaded H2O - the optimized HTTP/1, HTTP/2 server.

動作確認

firefoxで、httpsでアクセスしてみると、SSLにてアクセスできていることが確認出来た。

[screenshot.png]

イナヅママークが青くなっていれば、http/2 でアクセスしている。
(※ firefoxのアドオン HTTP/2 and SPDY indicator をインストールする事で利用可能となる)

なお、アクセスログでも確認ができる。

1
192.168.0.1 - - [11/Feb/2016:12:40:14 +0900] "GET / HTTP/2" 200 493 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:40.0) Gecko/20100101 Firefox/40.0"

SSL証明書は以下の通り。

[letsencrypt.png]

SSL評価

Qualys SSL Report にてSSL評価チェック。

[report.png]

まずまずではないだろうか。

Let’s Encrypt 自動更新設定

Let’s Encryptの証明書有効期間が90日と短いため、自動で更新されるように以下、登録する。

1
00 05 01 * * /usr/local/letsencrypt-auto certonly --webroot -w /var/www/html/example.com -d example.com -m hoge@example.com --renew-by-default && /bin/systemctl reload h2o

参照URL