Let’s EncryptでHTTPSを有効にする (1)

2016年4月にLet’s Encryptが正式化されてからずっと気になってはいたのですが、先日まとまった時間が取れたので、お名前.comのVPSで運用している本サイトのSSL化に挑戦してみました。Wordpressの既存サイトをHTTPS化するにはいくつかの段階がありますが、本稿ではまずWebサイトにLet’s Encryptから発行を受けた証明書を利用して、HTTPSで通信できるようになるまでの手順を解説します。

非常に簡単な証明書の発行

証明書の発行はこちらで紹介されている手順をそのまま実行しただけで、簡単に発行を受けることができました。重要なのは、”どのドメインに対して発行を受けるか”ということで、理由は後述しますが、-dの引数に目的のサブドメイン(本サイトの場合www.starplatinum.jp)だけでなく親ドメイン(starplatinum.jp)も設定しておきましょう

少し面倒なnginxへのHTTPS関連設定追加

本サイトで利用しているお名前.comのVPSサービスの場合、CentOS + nginxという組み合わせでWordpressが動いており、/etc/nginx/nginx.confを見ると、/etc/nginx/conf.d/*.confがインクルードされる設定になっています。/etc/nginx/conf.dをに置かれている条件を満たすファイルはdefault.conf, default.backend.conf, ssl.default.confの3つなので、基本的にこれらに対して設定を行うことになります。ちなみに初期状態ではssl.default.confはすべてコメントアウトされています。

さて、これからHTTPSを利用できるようにするわけですが、既存サイトへの影響を最小限に抑えるため、ssl.default.confを設定することでHTTPSを有効にし、最終的にHTTPのリクエストをすべてHTTPSに転送するようにします。まずオリジナルのssl.default.confを適当な名前で退避させ、default.confをssl.default.confという名前でコピーしてから以下(当サイトの設定そのもの)を参考に修正します。黄色い部分がHTTPS用に新たに追加する部分です。

server {
    listen      443 ssl http2;
    server_name starplatinum.jp;
    root        /var/www/vhosts/your_host_name;
    index       index.html index.htm;
    charset     utf-8;

    ssl_certificate /etc/letsencrypt/live/your_domain_name/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/your_domain_name/privkey.pem;

    ssl_session_timeout  1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    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-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
    ssl_prefer_server_ciphers   on;
    ssl_dhparam /etc/ssl/certs/dhparams.pem;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Xss-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;

    # OCSP Stapling ---
    # fetch OCSP records from URL in ssl_certificate and cache them
    ssl_stapling on;
    ssl_stapling_verify on;

    ## verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /etc/letsencrypt/live/www.starplatinum.jp/fullchain.pem;

    access_log  /var/log/nginx/your_host_name.ssl.access.log  main;
    error_log   /var/log/nginx/your_host_name.ssl.error.log;

以下、それぞれについて簡単に解説します。

listen 443 ssl http2;

443番ポートでHTTPSを待ち受けるための設定です。HTTP2もついでに有効化してあります。2016/9/24時点でCentOS 6.8のOpenSSLのバージョンが1.0.1eであるため、1.0.2以上を必要とするALPNの動作要件を満たさない = HTTP2においてALPNを必須とするChromeとは通信できませんが、将来的に更新されることを期待して有効にしてあります。

ssl_certificate /etc/letsencrypt/live/your_domain_name/fullchain.pem;
ssl_certificate_key  /etc/letsencrypt/live/your_domain_name/privkey.pem;

Let’s Encryptで生成した鍵を指定します。説明にある通り、nginxの場合はサーバ証明書を指定するssl_certificateに、サーバ証明書と中間証明書が結合されたファイル(Let’s Encryptで作成した場合fullchain.pem)を設定するので注意してください。

ssl_session_timeout  1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;

SSLのセッション保持時間に関する設定です。設定の意味が分からない方はそのままにしておきましょう。

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-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers   on;
ssl_dhparam /etc/ssl/certs/dhparams.pem;

ここがHTTPS関連の設定の中で最も重要な部分です。ここで設定しているのは利用を許すSSLプロトコル(ssl_protocols)、そのプロトコルで利用する共通鍵暗号方式(ssl_ciphers)、利用する暗号方式についてサーバ側の設定を優先するか(ssl_prefer_server_ciphers)、DH鍵交換で利用する鍵(ssl_dhparam)になります。

ここが重要なのは、この設定により古いクライアントからのアクセスができなくなってしまう場合があるためです。上記設定はもっとも厳格 = 高いセキュリティレベルを実現できる設定ではありますが、代償としてAndroid 5.0未満やJava 8未満からの接続ができなくなってしまいます。あえて古いクライアントに対応させたい場合は、Mozilla SSL configuration generatorを参照してください。なお、最後のssl_dhparamで指定する鍵は、以下のコマンドで生成した鍵のパスを指定します。

$ openssl dhparam 2048 -out /path/to/key/dhparams.pem

上記のパスは特に意味はなく、デフォルトで用意されていたSSL関連のディレクトリに置いたというだけです。

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Xss-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;

これらはHTTPSで通信を行う際に追加で設定することが可能になるHTTPヘッダ群です。それぞれについてMozillaが秀逸な解説をしているページがあるので、詳細についてはそれぞれ以下を参照してください。

HTTP Strict Transport Security
X-Frame-Options レスポンスヘッダ
X-XSS-Protection
X-Content-Type-Options

この中で注意が必要なのがStrict-Transport-Seucurityで、見ての通り”includesSubDomains”というパラメータがあります。結論だけ書くと、インストールする証明書が証明するのがサブドメインのみの場合はこのパラメータは設定しても無意味で、親ドメインが含まれている場合にのみ意味を持ちます。このため、証明書が証明するドメインに親ドメインも含める必要があるということになります。

# OCSP Stapling ---
# fetch OCSP records from URL in ssl_certificate and cache them
ssl_stapling on;
ssl_stapling_verify on;
## verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /etc/letsencrypt/live/www.starplatinum.jp/fullchain.pem;

これらはOCSP(Online Certificate Status Protocol)関連の設定です。簡単に言えば、リアルタイムで任意の証明書の有効性を確認する仕組みで、この辺を参考にしてください。ssl_trusted_certificateに設定するfullchain.pemは、ssl_certificateに設定したファイルになります。なお、resolverは指定しないでも大丈夫です。

access_log /var/log/nginx/your_host_name.ssl.access.log main;
error_log /var/log/nginx/your_host_name.ssl.error.log;

最後に、HTTPSのアクセスログの保存先を指定します。最終的に完全にHTTPSのみにしてHTTPを無効にしてしまったら一つでいいわけですが、少なくとも検索エンジンのリンクがすべて書き換わったと確信できるまでは、別ファイルに個別にログを取った方がいいでしょう(同一ファイルを指定するとどうなるかわからないし)。

(以下省略)の部分については、default.confの設定そのままでOKです。default.confにバーチャルホストの記述がある場合は、設定の重複を避けるためssl.default.confの当該部分をコメントアウトしておきましょう。ここまでの作業が完了したら、nginxを再起動(rootで”service nginx restart”)します。エラーが出なければひとまず成功です。

HTTPSでの接続確認

さて、実際にHTTPSで接続してみましょう。これはブラウザから”https://(サイト名)”で接続すれば一目瞭然なので、特に難しいことはありません。接続に成功したら、証明書の詳細を開いて”Certificate Subject Alt Name”という項目を確認しましょう。当サイトの証明書の場合、以下のようになっています(この投稿を見ている方も自分で確認できます)。

cert

証明書発行の際に-dで複数のドメインを指定していた場合、それらが列挙されているのが確認できると思います。

HTTP => HTTPSの強制リダイレクトを設定する

HTTPSで正常にアクセスできることを確認したら、HTTPのアクセスをすべてHTTPSにリダイレクトするような設定を追加します。この時点で必要な設定はすべてssl.default.confに記載されているので、default.confにはリダイレクトの設定だけあればいいことになります。具体的には以下のようになります(当サイトの設定そのもの)。

server {
    listen      80 default;
    server_name www.starplatinum.jp;
    return 301 https://$host$request_uri;
}

もちろんHTTPを無効化するという手もあるのですが、外部の既存ブックマークなどがすべてHTTPSに書き換わることはまず考えられないため、恒久的にリダイレクトを行うようにしておくのが現実的でしょう。

ここまでの手順で、WebサイトがHTTPSで通信できるようになり、かつHTTP経由の接続要求もHTTPSにリダイレクトされるようになったはずです。しかし、Wordpressのサイトとして正常に機能するには、もう少し手間をかけてやる必要があります。そちらについては次の投稿で紹介します。

コメントする