先日このサイトを常時SSL(AOSSL、または常時HTTPSとも)に対応させました。いろいろと知見がありましたのでまとめておきます。
要点
私は今回以下のことを実施しました。
- Apacheからnginxへの変更とconfigの書き直し
- Let’s Encryptの導入
- HSTSの導入(※必須ではない)
- ドメインのネームサーバの変更(※必須ではない)
それによって得たTips/注意点は大きく以下のとおりです。
- SSL/TLS対応状況確認について
- SSL Server TESTで対応状況をチェックしよう
- nginxのconfigについて
- “/.well-known/acme-challenge/”へのルールを設定しよう
- HSTS設定を有効にするのは最後にしよう
- SSL/TLSプロトコルバージョンの指定はよく確認しよう
- Let’s Encryptの導入について
- 試行錯誤は”–test-cert”オプションを使おう
- cron実行時に”–force-renewal”指定は避けよう
- WordPressについて
- 混在コンテンツのデバッグにはSearch Regexなどのプラグインが便利
- 混在コンテンツを許容する場合はネットワークパス参照が使える
- ソーシャル連携では「いいね」数やブックマーク数の引き継ぎ対応が必要
- ネームサーバについて
- 今後証明書を発行するならCAAレコードが必須になりそう
SSL/TLS対応状況確認について
確認のための便利なサイトがあります。
SSL Server TEST
https://www.ssllabs.com/ssltest/
このように、うまく対応できていれば「A+」の結果になります。
nginxのconfigについて
nginx1.12+PHP7.1環境において、nginxのconfファイルは最終的に以下のようになりました。
(一部改変しています)
server {
server_name example.com;
listen 80;
listen [::]:80;
root /var/www/html;
# Let's Encryptで使用するディレクトリ
location ^~ /.well-known/acme-challenge/ {
}
# Let's Encryptで使用するディレクトリそのものには404を返す
# (つまり配下に実在するファイルのみ200を返す)
location = /.well-known/acme-challenge/ {
return 404;
}
# 上記以外のすべてをHTTPSにリダイレクトする
location / {
return 301 https://$host$request_uri;
}
}
server {
server_name example.com;
listen 443 ssl http2;
listen [::]:443 ssl http2;
root /var/www/html;
location / {
index index.html index.php;
try_files $uri $uri/ @wordpress;
}
location ~ .php$ {
try_files $uri @wordpress;
fastcgi_pass unix:run/php/php7.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
include fastcgi_params;
}
location @wordpress {
fastcgi_pass unix:run/php/php7.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
include fastcgi_params;
}
charset utf-8;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# Let's Encryptで設置されたファイル
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# HSTSの設定(最大365日間は常時リダイレクトする)
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
# プロトコル設定など
ssl_protocols SSLv2 SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
}
基本的にはこのコピペでいけると思いますが、初めてnginxの表示を確認するなど常時SSLがまだ始まっていないときは以下の行(19、53、54、57行目)をコメントアウトしてください。
# 上記以外のすべてをHTTPSにリダイレクトする
location / {
return 301 https://$host$request_uri;
}
まず19行目。当然ながらnginxインストール直後でHTTPでの表示を確認したい場合はここをコメントアウトしてリダイレクトを無効にしてください。
# Let's Encryptで設置されたファイル
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
その場合、まだ53~54行目のファイルが存在していないので(19行目が無効であっても)エラーになりnginxが起動できません。あわせてここもコメントアウトしておいてください。Let’s Encryptのcertbotを起動しファイルが作成されたらコメントインしてHTTPSでの表示確認を行ってください。
# HSTSの設定(最大365日間は常時リダイレクトする)
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';
57行目は常時SSLを実現するHSTSの設定です。HSTS(HTTP Strict Transport Security)はHTTP接続を強制的にHTTPSへリダイレクトし、以後はすべてHTTPSで接続する機能です。上記では1度接続したら最大365日間(31536000秒間)HTTPSを使い続ける設定になっています。HTTPSの表示確認中の段階ではこの行はコメントアウトしてください。でないと手元の表示環境でHSTSが効いてしまい、一度HTTPSで表示したページをHTTP表示に戻したい場合などにうまく表示されなくなってしまいます。都度ブラウザのキャッシュをクリアするか、最後の最後にコメントインするようにしてください。
includeSubDomainsの指定はサブドメインにもHSTSが適用されるようにするための設定です。preloadはプリロード登録のためのものです。今のところ私はプリロード登録をしていませんがいちおう残しています。
HSTSの設定についてはこちらのページも参考になります。
常時SSL化(https)するときのHSTS設定の方法と注意点
http://tuono034s.com/web-entry/2310/
それから、63行目のプロトコル指定はnginxのバージョンによりますので確認して指定してください。2017年10月現在、最新バージョンのnginxにおいてTLS1.3はドラフト版のみの対応となっており、厳密には以後の動作保証ができないため外しています。
Let’s Encryptの導入について
導入方法については他のサイトを参照するとして、まだ試行錯誤段階である場合はcertbotの実行時に”–test-cert”オプションを付けてテストサーバに接続するようにしてください。メインサーバの方には一定期間内の接続回数に上限があり、何回か繰り返すと弾かれます。
テストサーバでテスト用証明書を取得した後、証明書をそのままにしてメインサーバへと接続すると、既にある証明書を置き換えるかどうか尋ねられるので自動実行の際は注意してください。
また、certbotのrenewコマンドをcronで実行する時は”–force-renewal”オプションを使わないようにしましょう。Let’s Encryptのサーバに不要な負荷をかけることになります。
以下のページも参考になります。
Let's encrypt運用のベストプラクティス – Qiita
https://qiita.com/tkykmw/items/9b6ba55bb2a6a5d90963
WordPressについて
WebサーバだけをHTTPS対応させても、読み込むコンテンツ(JavascriptやCSS、iframeなど)がHTTPだと混在コンテンツ(Mixed Content)となり、ブラウザで警告が出ます。これらを取り除くためにはブラウザの開発者ツール機能などを利用しながら一つ一つ取り除いていく必要があります。
読み込み元によっては “http://example.com” を “https://example.com” に置き換えればよいだけのものもありますし、URLが変わるために丸ごと書き換えが必要なものもあります。
特定のサービスを利用しているなどで一括置換できる場合は、Search Regexなどのプラグインを利用するのがよいでしょう。正規表現が使えますし、置換前後を確認しながら置換していくことができます。
これらのツールはエントリ内などで内部リンク(aタグやimgタグ)を絶対指定で行っている場合の置き換えにも使うことができます。便利。
◇
もし常時SSLを行わない場合で、あるページがHTTPでアクセスされるかHTTPSでアクセスされるか一定しない場合、埋め込まれたリソースを「src=”http://example.com~”」などと指定して読み込んでしまうとブラウザで警告が出ることがあります(混在コンテンツ)。この場合はネットワークパス参照を使用してURIスキームを省略し、「src=”//example.com~”」などと指定することで、ブラウザ側で読み込み元ページのURIスキームに合わせて解釈してくれます。あまり見ない記述方法ですが、RFCに準拠した方法であり、最近のブラウザでは正しく動きます。もちろんこの場合、どちらのURIスキームであっても埋め込みリソースに正常にアクセスできる必要があります。
◇
常時SSLを行うとURLが変わるため、ソーシャル連携していた場合「いいね」数やはてブ数が引き継がれません。特殊な対応が必要になります。
ネームサーバについて
今は必須ではありませんが、今後SSL/TLS証明書の取得には、第三者による発行を防止するためドメインのネームサーバにCAAレコードを設定するよう求められるようです。CAAレコードについての解説は以下が分かりやすいです。
DNS CAA レコード設定について – さくらのサポート情報
https://help.sakura.ad.jp/hc/ja/articles/115000139062-DNS-CAA-レコード設定について
現在CAAレコードに対応しているDNSサービスは少ないですが、HTTPS化の流れとそれに伴うCAA必須化の流れに乗って今後続々と対応が進むでしょう。私の場合はGoogle Cloud DNSを使用して有料で運用しています。