Mastodon インスタンスを運用しているサーバを HTTP/2 対応させた話 (CentOS7 + nginx + OpenSSL)

自分専用に立てた Mastodon (マストドン) インスタンスで、HTTP/2 を有効にしたのでその手順をメモ。サーバ環境は CentOS7。nginx 1.13.0 と OpenSSL 1.0.2k を使用してソースからビルド。

Mastodon (マストドン) インスタンスを自分専用に立ててから、この記事を書いている時点で 15日ほど経ちました。個人専用 (お一人様) インスタンスの始め方について、詳しい話は下記のエントリーで書いています。

その間、Mastodon インスタンス一覧 (Mastodon instances) に表示される 「HTTPS」「Obs」 の項目が 「+A」 になるように 「Content Security Policy(CSP)」 周りの設定をしたり (やっぱり掲載されちゃうと気になる......) とちょっとした調整はしていたのですが、HTTP/2 対応だけあとでやろうと思って放置してたのを今回対応しましたという話。

ちなみに本題とは少しズレますが、「HTTPS」「Obs」 の項目は、下記それぞれのチェックツールでの評価が反映されていますので、ここで 「+A」 が出るように設定して上げれば終わります。

また、「Content Security Policy(CSP)」 に関しては下記のリンク先が参考になると思います。

この Blog でも過去に簡単に書いていますが、2013年と、情報が古いのであまり参考になりません。最新の仕様を確認してください。

nginx で HTTP/2 を有効にする

さて本題に入ります。私の環境 (CentOS7) で nginx を使用して HTTP/2 を有効にした手順を備忘録としてまとめておきます。

まず、nginx で HTTP/2(ALPN) を有効 にするには、最低限下記の環境が必要です。

  1. nginx 1.9.5 以降
  2. OpenSSL 1.0.2
  3. HTTPS での接続が可能(今回は可能という前提でここの話は省きます)

このうち、1番目の nginx については、このエントリーを書いている時点で CentOS7 の標準リポジトリから yum install すれば 1.13.0 が入るので、最新のパッケージを使用すれば特に問題はありません。

しかし、OpenSSL については、現時点で CentOS7 の標準リポジトリから取得できるのは 1.0.1 系であり、ソースからビルドする必要があるのと、nginx が参照する OpenSSL も 1.0.2 にしてあげないといけません。結果 nginx もソースからビルドしないといけないということで、その辺をまとめて対応します。

nginx の最新版を一旦インストール

まずは一旦、

# yum update nginx

して、最新の nginx をインストールします。

次に、

# nginx -V

して nginx のバージョンと、configure の内容を確認し、控えておきます。

nginx version: nginx/1.13.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC)
built with OpenSSL 1.0.1
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx [...略...] --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'

概ね上記のような感じで表示されますので、nginx version: の値と、configure arguments: の値を間違いなくコピーしておきましょう。

OpenSSL のインストール

続いて OpenSSL 1.0.2 をインストールしていきます。

下記のページで、最新の 1.0.2 系 OpenSSL のダウンロード URL を確認して控えます。

以降、作業ディレクトリは /usr/local/src を前提とします。

# cd /usr/local/src
# wget https://www.openssl.org/source/openssl-1.0.2k.tar.gz
# tar zxvf openssl-1.0.2k.tar.gz
# cd openssl-1.0.2k
# ./configure shared -fPIC
# make
# make install

上記のように進めた場合、デフォルト設定によって、/usr/local/ssl/ に OpenSSL 1.0.2k がインストールされますので、下記のように今回インストールした新しいバージョンにシンボリック・リンクを張ります。

念のため旧バージョンのファイルは名前を変えてバックアップしておきます。

# cd /usr/bin/
# cp /usr/bin/openssl /usr/bin/openssl.old
# rm -f /usr/bin/openssl
# ln -s /usr/local/ssl/bin/openssl

バージョンチェックして下記のようになれば完了と。

# openssl version
OpenSSL 1.0.2k  26 Jan 2017

nginx のインストール

次に nginx のインストールです。OpenSSL の時と同じように、下記のダウンロードページで事前に確認したものと同じバージョンのダウンロード URL を確認します。

# cd /usr/local/src
# wget https://nginx.org/download/nginx-1.13.0.tar.gz
# tar zxvf nginx-1.13.0.tar.gz
# cd nginx-1.13.0.tar.gz

次に、configure します。nginx が先ほどインストールした OpenSSL 1.0.2k を参照するようにビルドしていきます。

# ./configure \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
[...略...] 
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' \
--with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' \
--with-openssl=/usr/local/src/openssl-1.0.2k \
--with-openssl-opt='-fPIC'

先ほど控えた configure の値をすべて記述し、最後に下記の 2行を追加しています。

--with-openssl=/usr/local/src/openssl-1.0.2k \
--with-openssl-opt='-fPIC'

これで yum によるデフォルトインストールと同じ設定を保ちつつ、参照する OpenSSL だけ任意のバージョンに変更して nginx をインストールすることができます。

私の場合はすでに稼働している nginx を入れ替えたので、こうしておけば設定が変わらず安心です。もし、まっさらな状態からの構築であれば ./configure の内容を必要に応じて変更すればよいと思います。

なお、途中で足りないパッケージがあると怒られた場合は都度入れてやり直しましょう。無事エラーが出ずに configure されたら、あとは、

# make
# make install

して、インストール。

バージョンを確認して、nginx のバージョンと、参照している OpenSSL のバージョンが意図した通りになっていれば完了です。

# nginx -V
nginx version: nginx/1.13.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC)
built with OpenSSL 1.0.2k  26 Jan 2017

nginx の設定を確認して再起動・動作確認

nginx のバーチャルホスト設定に、http2 が指定されているか確認。

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
...[略]...
}

問題なければ、nginx を再起動します。

# systemctl restart nginx

実際にサイトにアクセスしてみましょう。デベロッパーツールなどで、HTTP/2 が有効になっていることを確認して問題がなければ設定完了ですね。

HTTP/2 が有効になっていることをデベロッパーツールなどで確認

IPv6 を有効にする場合

余談ですが、上記、バーチャルホスト設定のサンプルを見ていただくとわかるとおり、私の環境では IPv6 も有効にしてあります。

この際、nginx で IPv6 を有効にするため、--with-ipv6 という configure が以前はあったのですが、1.11.5 で廃止、デフォルトで有効になっていることに注意しましょう。

nginx の Changelog に、下記のとおり記述があります。

Changes with nginx 1.11.5          11 Oct 2016
 
  *) Change: the --with-ipv6 configure option was removed, now IPv6
     support is configured automatically.

ということで、OS 側で IPv6 が有効になっていて、DNS の AAAA レコードが正しく設定されていれば、IPv6 対応も比較的簡単にできますよ。

関連エントリー