HiFormance の VPS をぼちぼち実運用に供してみる準備編。
ずっと Apache を (というよりは Apache の ITK MPM を) 愛用してきたのだが、
- Apache 2.4.27 以降で mod_http2 が prefork MPM で動作しなくなる
- Debian stretch 収録の Apache は 2.4.25 だが、mod_http2 のパッチバックポートにより 2.4.25 でも mod_http2 が prefork MPM で動作しなくなった
- (ITK MPM は prefork MPM に依存している)
こんな感じで ITK MPM に未来がなくなってきてしまった。
というわけでまだ実運用に供していない環境で nginx を扱ってみることにした。
せっかくなので SSL Server Test で満点をとれる設定を目指してみたい。
まず nginx 自体を Debian 収録バージョンではなく、nginx 公式のリポジトリで mainline を入れる。
% echo 'deb http://nginx.org/packages/debian/ stretch nginx' | sudo tee /etc/apt/sources.list.d/nginx.list
% wget https://nginx.org/packages/keys/nginx_signing.key -O - | sudo apt-key add -
% sudo apt update
% sudo apt install nginx
Let’s Encrypt の証明書を RSA 4096 bit で作る。
% sudo certbot certonly --agree-tos -n --rsa-key-size 4096 --webroot -w /var/www/html -w webmaster@example.com -d example.com
nginx の SSL まわりの設定。
いつも通りだが、Mozilla SSL Configuration Generator を基本にする。
nginx 1.15.1、OpenSSL 1.1.0f、Modern 設定。
結論からいくと、下記の設定で満点になる。
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
root /var/www/html;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_dhparam /etc/nginx/dhparam.pem;
ssl_ecdh_curve secp384r1;
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
add_header Strict-Transport-Security max-age=15768000;
ssl_stapling on;
ssl_stapling_verify on;
resolver 127.0.0.1 valid=300s;
}
(resolver が 127.0.0.1 なのは、私はそこに Unbound を動かしているため)
変更点は次のとおり。
- ssl_ecdh_curve secp384r1;
- ssl_ciphers から ECDHE-RSA-AES128-GCM-SHA256、ECDHE-RSA-AES128-SHA256 を除去。
ただしこの設定では、Android 5/6、Windows Phone 8.1 の IE11 からはアクセスできなくなっている。
Mozilla SSL Configuration Generator の出力では ssl_ciphers はこうなっていた。
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
この設定だと SSL Server Test は A+ 100/100/100/90 で、Cipher Strength だけ満点が取れず90点。
Android 4.x 以降でアクセスできる、まずまずまともな対応範囲といえる。
- ECDHE-RSA-AES128-GCM-SHA256 を削ると、Android 5.x/6.x が NG になる。
- ECDHE-RSA-AES128-SHA256 も削ると Cipher Strength が満点になるが、Windows Phone 8.1 の IE11 が NG になる。
メモ
- Mozilla SSL Configuration Generator で Modern 設定の ssl_ciphers はもう全部 ECDHE-* なので、DH 鍵を 4096 bit で生成して ssl_dhparam を書いても意味ないっぽい。
- ssl_ecdh_curve を指定しないと secp256r1 や x25519 の 256 bit (RSA 3072 bit 相当) になり、Key Exchange が90点になる。
- 欲張って ssl_ecdh_curve secp521r1; なんてやると Chrome でアクセスできなくなる (Chrome というか BoringSSL が2015年に P-521 対応を削除したため)。ssl_ecdh_curve secp521r1:secp384r1; なら OK。
結論
古い環境の切り捨てがスコアに直結するとはいえ、さすがに Android 5.x/6.x はまだ合計 20% 以上のシェアがあって切り捨てられない。
副作用を考えると、結局 ssl_ciphers は Mozilla SSL Configuration Generator の通りにして A+ 100/100/100/90 で我慢するのが落としどころという感じ。
なお、当サイトは Netlify 収容のため、そこまでカリカリに詰めた設定にはなっていない。そもそも証明書からして RSA 2048 bit だし、スコアは A+ 100/100/90/90 である。たはは。