monoの開発ブログ

Let's Encrypt でサイトを HTTPS 化

ついに Let's Encrypt の Public Beta が始まりましたね。私は Closed Beta の時から参加していて、このサイトも HTTP からのリダイレクトはしないけど HTTPS でも見れるという状態にはしてあったのですが、Public Beta になったということで、リダイレクトするようにして HSTS も設定してみました。

ということで、Let's Encrypt を導入してサイトを HTTPS 化する中でわかったことを書いておきます。

証明書の発行・更新

手順に沿ってやれば証明書を発行してもらうこと自体は簡単です。しかし、Let's Encrypt の証明書は有効期限が3ヶ月しかありません。これは beta だからというわけではなく、自動更新することを前提としているためだそうです。手動で頑張れなくも無い間隔ではありますが、面倒ですし、忘れる可能性もあるので自動化するのが無難でしょう。また、最初の1回だけだからと言うことで80番ポートを listen しているプログラムを停止させていた方もいらっしゃるかもしれませんが、そんな方も証明書の更新のたびにダウンタイムが発生するとなるとちょっとイケてないんじゃないかと感じるんじゃないかと思います。

結論としては、以下のリンク先に従って設定すれば80番ポートを listen するプログラムをダウンさせることなく証明書を更新できますし、cron でスクリプトを叩けば自動化も簡単です。Let's Encrypt を試す方は、証明書を手に入れておしまいではなく、ぜひ Let's Encrypt が目指すところである証明書の自動更新まで取り組んでみてください。

外部リソースのロード

HTML を HTTPS でロードするのであれば、画像や JS なんかも当然 HTTPS で読み込むことになります。自分で用意しているものはなんとかしましょうという話なのですが、外部のサービスが提供するものを読み込んでいる場合は、そのサービスが HTTPS でリソースを提供しているかどうか確認する必要があります。このブログの場合、はてなスターと Disqus の JS は HTTPS での読み込みに対応していたのでそのまま残している一方、Live Dwango Reader での購読を促すバナー画像は HTTP でしか提供されていなかったので、よい機会かなと思って外しました。

TLS の設定

SSL や TLS は単にオンオフを切り替えればよいというものではなく、それなり設定を頑張る必要があって、ここがザルだとブラウザが鍵マークを表示してくれません。

私自身は誰かに説明するほど正確には理解していないのですが、以下のリンクを参考に設定しました。

ssl_certificate_key /etc/letsencrypt/live/mono0x.net/privkey.pem;
ssl_certificate /etc/letsencrypt/live/mono0x.net/fullchain.pem;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers '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:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';

ssl_prefer_server_ciphers on;

ssl_dhparam /etc/nginx/dhparam.pem;

ssl_session_timeout 10h;
ssl_session_cache builtin:1000 shared:ssl:10m;
ssl_stapling on;
ssl_stapling_verify on;

ssl_session_ticket_key /etc/nginx/ticket.key;

これでざっくり言うと以下のような設定になっているはず。IE 7 以上、Android 2.3 以上、Java 7 以上に対応しているつもりです。

  • SSL 3.0 は無効、TLS 1.0 は有効
  • サーバ側の暗号化スイート指定を優先した上で、脆弱な暗号化スイートは無効
  • Perfect Forward Security (PFS) 有効
  • OCSP Stapling 有効

今後の予定

せっかく HTTPS になったからには、やはり HTTP/2 を導入したいですね。h2o はすごく魅力的なソフトウェアだなぁと思いつつも、nginx の設定ファイルを移行するのが面倒なので、まずは nginx から試してみることになりそうです。