パッケージのみで CentOS の Apache を HTTP/2 対応にする

## HTTP/2
CentOS 7.4 から OpenSSL が 1.0.2 にバージョンアップされたため、完全にパッケージのみで Apache を HTTP/2 に対応させることが可能になりました。

VirtualBox 上の CentOS 7.4 minimal の仮想環境で検証する手順を紹介します。

Nginx については後日公開される別記事で紹介します。

## Apache
### RHSCL (SCLo rh) の導入
```bash
yum -y install centos-release-scl-rh yum-utils
yum-config-manager --enable centos-sclo-rh-testing
```
標準リポジトリでは Apache は 2.4.6 のため、RHSCL クローンの SCLo rh リポジトリ `centos-release-scl-rh` を導入します。

このままでは HTTP/2 に対応出来ても ALPN に対応できず、モダンブラウザで確認することができないため、 SCLo rh Testing リポジトリ `centos-sclo-rh-testing` を有効にします。

### 必要ライブラリのインストールと環境整備
```bash
yum -y install httpd24{,-mod_ssl,-nghttp2}
source scl_source enable httpd24
echo -e '#!/bin/bash\nsource scl_source enable httpd24' > /etc/profile.d/httpd24.sh
ln -s {/opt/rh/httpd24/root,}/etc/httpd
ln -s {/opt/rh/httpd24/root,}/var/www
ln -s /etc/httpd/logs /var/log/httpd
ln -s /{usr/lib/systemd/system/httpd24-,etc/systemd/system/}httpd.service
systemctl daemon-reload
```
`httpd` `mod_ssl` `libnghttp2` に相当するパッケージをインストールします。
`httpd24` パッケージはソフトウェアコレクションのためファイルの配置等が標準パッケージと異なり管理しづらいので、影響が少ない範囲で極力同じパス参照ができるように調整します。

### MPM を Prefork から Event に変更
```bash
sed -i '/mod_mpm_prefork/ s/^/#/' /etc/httpd/conf.modules.d/00-mpm.conf
sed -i '/mod_mpm_event/ s/#//' /etc/httpd/conf.modules.d/00-mpm.conf
```
Apache 2.4.27 から Prefork モードでは HTTP/2 が無効になるようになった [^prefork] ため、 Events モードに変更する必要があります。
[^prefork]: http://www.apache.org/dist/httpd/CHANGES_2.4

### プロトコルの指定
```apache
cat << "_EOF_" > /etc/httpd/conf.d/vhosts.conf
<VirtualHost *:80>
    Protocols h2c http/1.1
</VirtualHost>
<VirtualHost *:443>
    ServerName localhost
    Protocols h2 http/1.1
    SSLCertificateFile /etc/pki/tls/certs/localhost.crt
    SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
</VirtualHost>
_EOF_
```
ここでは証明書は OpenSSL の標準のサンプルを使用しています。
なお　443 ポート向けの `DocumentRoot` を指定する場合は `/var/www/html` などのシンボリックリンクを指定するとエラー出力なしに無視されるので気をつけましょう。

### FirewallD
```bash
firewall-cmd --add-service=http{,s} --permanent && firewall-cmd --reload && firewall-cmd --list-services | grep http
```

### 起動
```bash
systemctl start httpd && systemctl enable $_
```

### サンプルファイル
```bash
echo "HTTP/2 Test" >> /var/www/html/index.html
```

## ローカル PC の設定
```:hosts
192.168.56.101 localhost
```
VirtualBox などの仮想環境の場合は hosts ファイルを編集して localhost ドメインで参照できるようにする必要があります。

## ブラウザ参照
<img width="630" alt="スクリーンショット 2017-11-25 2.31.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/15175/fcf33256-1a9d-dcd9-5ba6-5bcbb1bbfe7b.png">

Firefox や Safari などのブラウザでデベロッパーツールを表示して https://localhost/ を参照すると、プロトコルが `h2` になっていることが確認できます。（Chrome だと hosts 書き換えによる localhost 参照できないようです。回避策をご存じの方がいたら情報提供をお願いいたします。）

## Let's Encrypt
### 証明書の取得
```bash
yum -y install certbot
certbot certonly --standalone -d example.jp -m admin@example.com --agree-tos
```
実ドメインで試す場合は Let's Encrypt で取得するとよいでしょう。
RHSCL の `httpd24` パッケージを利用している都合上、要求される標準の `httpd` パッケージと競合してしまい `python-certbot-apache` パッケージが利用できないので、面倒ですが `certonly` で実行する必要があります。

### 証明書の指定
```apache
    SSLCertificateFile    /etc/letsencrypt/live/example.jp/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.jp/privkey.pem
```
証明書は上記パスにシンボリックリンクが生成されるので、`<VirtualHost *:443>` ディレクティブ内で指定します。