※当ブログではアフィリエイト広告を利用しています。
Googleが検索結果のランキングシグナルにHTTPSを使用することを発表して1年以上経ち、常時SSL化のサイトを見かけることも多くなったように感じます。
当サイトも常時SSL化したため、その際の手順をできるだけ詳細にメモします。
常時SSL化を導入した環境
当サイトはさくらのVPSのCentOS6.7上で nginx + PHP + fastCGI + WordPress で動作しています。nginxはバックエンドだけでなくリバースプロキシとしても使用しています。
常時SSL化する上での注意点
常時SSLするだけならそれほど手順は複雑ではありませんが、サーバ側設定の他にもいろいろ注意する点があります。主なものを以下に挙げます。
外部から読み込むリソースもHTTPS化する必要がある
常時SSL化するためにはCSSやJavaScriptや画像など、内部・外部サイト問わずhttp://
で読み込んでいるリソースはすべてhttps://
に変更する必要があります。
WordPressの投稿画面で画像を挿入すると自動的にhttp://
からの絶対パスが付与されますがこれらもすべて変更の対象です。こちらはWordPressの「Search Regex」というプラグインで投稿内容を置換することで対応可能なので後述します。
SNSのシェア数が引き継がれない
SNSのシェア数はURLごとにユニークになっているせいかHTTPとHTTPSでは別のものとしてカウントされます。シェア数の引き継ぎは諦めようかと思ったのですが、WordPressの「SNS Count Cache」というプラグインを使えばHTTPとHTTPS両方のカウントをキャッシュとして合算して保持できることがわかったため、今回はプラグインの使用と、テーマファイルを修正してシェア数を表示するよう対応しました。
アクセス解析等のURL変更が必要
Google Search Consoleのプロパティ追加やGoogle Analyticsのプロパティ・ビュー設定が必要です。
nginx + PHP + fastCGI環境のWordPressを常時SSL化する手順
本題となる常時SSL化方法を順番に記載します。
1. 事前準備
1.1 WordPressテーマ内のURL変更
WordPressテーマ内で他サイトのリソースをhttp://
で読み込んでいる部分を検索し、https://
またはプロトコル相対URLに変更しておきます。
テーマ内で主に変更する必要がありそうなものは以下のとおりです。サービス側でURLを生成した時に既にHTTPSやプロトコル相対URLになっているものもあります。
サービス名 | HTTP | HTTPS or プロトコル相対URL |
---|---|---|
http://ajax.googleapis.com | //ajax.googleapis.com | |
Google Code Archive | http://html5shiv.googlecode.com | //html5shiv.googlecode.com |
はてな | http://b.st-hatena.com | https://b.st-hatena.com |
Google+ | なし | https://apis.google.com/js/platform.js |
http://platform.twitter.com | //platform.twitter.com | |
http://connect.facebook.net | //connect.facebook.net | |
Feedly | http://s3.feedly.com | https://s3.feedly.com |
http://widgets.getpocket.com | https://widgets.getpocket.com |
※はてなはエントリ公開時点でSHA-1証明書を使用しているようでChromeで閲覧すると警告が出ます。
1.2 投稿記事内の他サイトURL変更
投稿エントリの中で他サイトの画像などを読み込んでいる部分のURLを置換します。エントリ1つ1つを置換するの大変なので、WordPressプラグインの「Search Regex」を使用して一気に置換します。
Search Regexで置換する方法は下記の画像のように「Search pattern」に置換前のURLを、「Replace pattern」に置換後のURLを入力し、「Replace & Save」ボタンを押すだけです。青の「Search」ボタンを押すと変更を保存せずに置換対象の文字列を確認することができます。
エントリ内で主に変更する必要がありそうなものは以下のとおりです。
サービス名 | HTTP | HTTPS or プロトコル相対URL |
---|---|---|
Amazonアソシエイト | http://ecx.images-amazon.com/ | https://images-na.ssl-images-amazon.com/ |
Amazonアソシエイト | http://ir-jp.amazon-adsystem.com/ | https://ir-jp.amazon-adsystem.com/ |
iTunesアフィリエイト | http://axxx.phobos.apple.com/ | なし |
Amazonアソシエイトはhttps://
のURLも用意されていたのですが、iTunesアフィリエイトで使用するアートワークやアプリのアイコンなどの画像は本エントリ公開時点でhttp://
しか用意されていないようでした・・・。
iTunes Search APIのページでも返却されるURLのサンプルがhttp://
となっているようなのでApple側の対応を待つしかありません。iTunesアフィリエイトの商品を紹介しているエントリではやむなくhttp://
とhttps://
が混在することとなります。
1.3 SNS Count Cacheプラグインの導入
SNS Count Cacheプラグインを導入し、各エントリのSNSでのシェア数を保持できるよう準備しておきます。
SNS Count Cacheプラグインを使用するとシェア数の保持だけでなく関数からのシェア数呼び出しもできるため、独自にデザインしたSNSシェアボタンを作成することも可能です。
SNS Count Cacheを導入すると下記のように自動的にシェア数のキャッシュがスタートし、全てをキャッシュし終わるには少し時間がかかりますが、後にHTTPS化した時に再度キャッシュし直すため全てのキャッシュが完了するまで待つ必要はありません。
2. SSLサーバ証明書の準備
2.1 SSLサーバ証明書の購入
SSLサーバー証明書は有料・無料を含めてかなり多くの種類がありますが、今回は有料のRapidSSLを使用しました。
有料といっても私が購入したのは3年で3,456円(税込)というおそらく最安値のものです。SSLストアというサイトで「ファイル認証タイプ」を選択したとき限定での価格ですが、証明書自体は通常のものと同じでアクティベーションも難しくありません。
SSLストアで格安のRapidSSL証明書を購入する方法の詳細は下記のエントリに記載しています。
関連エントリ:SSLストアで格安のSSLサーバ証明書(RapidSSLファイル認証タイプ)を購入・取得する方法
ここでSSLサーバー証明書と秘密鍵を入手します。
2.2 SSLサーバ証明書の配置
前の手順で入手したSSLサーバ証明書と秘密鍵をサーバの任意のディレクトリに配置します。
今回は以下に配置しました。
種類 | パス |
---|---|
SSLサーバ証明書 | /etc/nginx/ssl/server.crt |
秘密鍵 | /etc/nginx/ssl/server.key |
SSLサーバー証明書は「SSLサーバ証明書」と「中間CA証明書」を連結したものとする必要があります。(SSL証明書購入時に両方とも入手できます)
「SSLサーバ証明書」と「中間CA証明書」を連結したものは以下のような中身になります。
-——BEGIN CERTIFICATE——- ここにSSLサーバー証明書の文字列 -——END CERTIFICATE——- -——BEGIN CERTIFICATE——- ここに中間CA証明書の文字列 -——END CERTIFICATE——-
2.3 秘密鍵のパスフレーズ解除
秘密鍵をエディタで開いてProc-Type: 4,ENCRYPTED
などど記載されている場合はパスフレーズで暗号化されているためそのままではアプリケーションから使用できません。
以下のコマンドでパスフレーズを解除します。encrypted.key
は複合前の、decrypted.key
は複合後のファイル名を指定します。コマンド実行するとパスフレーズを聞かれ、正しく入力すると暗号化が解除されたファイルが生成されます。
# openssl rsa -in encrypted.key -out decrypted.key
2.4 Diffie-Hellman鍵交換用パラメータファイルの準備
後にSSL安全性チェック用サイトでA+評価を取るため、Diffie-Hellman鍵交換用のパラメータファイルを作成します。
コマンドを実行後少し時間がかかり、数分で作成が完了します。
# openssl dhparam 2048 -out /etc/nginx/ssl/dhparam.pem
3. サーバ側設定変更の前準備
nginxの設定を変更する前の準備です。
3.1 iptablesで443ポートの通信を許可
HTTPS通信のためには443ポートの通信を許可する必要があるため、ポートが解放されているかを確認します。
# vi /etc/sysconfig/iptables
以下の記述があればiptablesでは443ポートの通信が許可されています。
-A INPUT -p tcp -m tcp —dport 443 -j ACCEPT
別のファイアウォールを導入している場合はそちらも443ポートの通信が可能であるかを適宜確認します。
3.2 OpenSSLのバージョン確認
OpenSSLは古いバージョンだと致命的な脆弱性を持つものがあるため、安全なパッケージがインストールされているかを確認し、そうでなければアップデートしておきます。
バージョンの確認は下記コマンドで可能です。
# openssl version
しかし上記だと最新のパッチが当たっているか分からないため、下記コマンドでインストール済みパッケージと利用可能なパッケージを比較します。
# yum list openssl
4. HTTPS通信を有効化
4.1 nginxの設定変更(HTTPS通信の確認用)
まずはSSLサーバ証明書が正しく機能してHTTPSで通信可能なことを確認するため、HTTPとHTTPS両方でアクセス可能な状態とします。
nginx設定ファイルの既存のserver
ブロックにSSL関連の設定を追加します。
server { listen 80 default; listen 443 ssl; server_name _; root /var/www/html/example.com; index index.html index.htm index.php; charset utf-8; # SSL # ssl on; ssl_certificate /etc/nginx/ssl/server.crt; ssl_certificate_key /etc/nginx/ssl/server.key; # TLS1.0 1.1 1.2のみ有効 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # サーバが提示した暗号スイートを優先する ssl_prefer_server_ciphers on; # 安全でない暗号化スイートはサポートしない ssl_ciphers 'kEECDH+ECDSA+AES128 kEECDH+ECDSA+AES256 kEECDH+AES128 kEECDH+AES256 kEDH+AES128 kEDH+AES256 DES-CBC3-SHA +SHA !aNULL !eNULL !LOW !kECDH !DSS !MD5 !EXP !PSK !SRP !CAMELLIA !SEED'; # SSLセッションキャッシュとサイズを指定 ssl_session_cache builtin:1000 shared:SSL:10m; # SSLセッションキャッシュのタイムアウトまでの時間 ssl_session_timeout 10m; # DH鍵交換パラメータファイル ssl_dhparam /etc/nginx/ssl/dhparam.pem; # OCSP応答をサーバー側にキャッシュ ssl_stapling on; #以降は既存の設定のまま
私が最初に実施した時はssl on
にしていたことが原因で「The plain HTTP request was sent to HTTPS port」というエラーが発生しました。この時点ではHTTPもHTTPSも有効にしたいため一旦コメントアウトします。
設定変更が完了したら下記コマンドで設定ファイルの再読み込みを行います。
# nginx -s reload
4.2 WordPressのURL変更
4.1でHTTPSで通信可能なことが確認できたらWordPressの管理画面で「設定」→「一般」よりWordPressアドレス(URL)とサイトアドレス(URL)をhttps://
に変更します。
4.3 nginxの設定変更(HTTP→HTTPSリダイレクト)
HTTPからHTTPSにリダイレクトするよう設定変更します。一つだったserver
ブロックがHTTP用とHTTPS用の2つに分かれます。
また、HTTPでアクセスされた場合に次回以降はHTTPSを使うようブラウザに伝えるため、HTTP Strict Transport SecurityのHTTPヘッダを追加します。
server { listen 80; server_name _; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name _; root /var/www/html/example.com; index index.html index.htm index.php; charset utf-8; # SSL ssl on; ssl_certificate /etc/nginx/ssl/server.crt; ssl_certificate_key /etc/nginx/ssl/server.key; # TLS1.0 1.1 1.2のみ有効 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # サーバが提示した暗号スイートを優先する ssl_prefer_server_ciphers on; # 安全でない暗号化スイートはサポートしない ssl_ciphers 'kEECDH+ECDSA+AES128 kEECDH+ECDSA+AES256 kEECDH+AES128 kEECDH+AES256 kEDH+AES128 kEDH+AES256 DES-CBC3-SHA +SHA !aNULL !eNULL !LOW !kECDH !DSS !MD5 !EXP !PSK !SRP !CAMELLIA !SEED'; # SSLセッションキャッシュとサイズを指定 ssl_session_cache builtin:1000 shared:SSL:10m; # SSLセッションキャッシュのタイムアウトまでの時間 ssl_session_timeout 10m; # DH鍵交換パラメータファイル ssl_dhparam /etc/nginx/ssl/dhparam.pem; # OCSP応答をサーバー側にキャッシュ ssl_stapling on; #HTTP Strict Transport Security add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload'; #以降は既存の設定のまま
Strict-Transport-Security
のincludeSubDomains
はすべてのサブドメインがHTTPSの場合のみ追加します。またpreload
は後述のHSTS Preload Listに登録する場合に追加します。
4.4 nginxの設定変更(FastCGIパラメータでSSLを有効化)
nginx + FastCGI環境だと、ここまでの設定だけだと以下のような状態になることがあります。
- トップページにアクセスするとリダイレクトループが発生する
- 管理画面にアクセスするとリダイレクトループが発生する
bloginfo('stylesheet_url')
などで取得するURLがhttp://
になるthe_post_thumbnail()
でサムネイルが正しく取得できない
この場合、FastCGIパラメータの設定をしている箇所にfastcgi_param HTTPS on;
を追加すると問題を回避できます。
参考までに当サイトの該当箇所の設定は以下のようになっています。
location ~ \.php$ { try_files $uri =404; expires off; fastcgi_pass phpfpm; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; fastcgi_param REMOTE_ADDR $http_x_real_ip; fastcgi_param HTTPS on; fastcgi_pass_header "X-Accel-Redirect"; fastcgi_pass_header "X-Accel-Buffering"; fastcgi_pass_header "X-Accel-Charset"; fastcgi_pass_header "X-Accel-Expires"; fastcgi_pass_header "X-Accel-Limit-Rate"; }
設定変更が完了したら下記コマンドで設定ファイルの再読み込みを行います。
# nginx -s reload
5. 常時SSL化後にやること
5.1 記事内のサイト内リンク変更
WordPress管理画面より「Search Regex」で、時サイト内のリンクをhttp://
からhttps://
に置換します。
以下は当サイトでの置換例です。
5.2 SNS Count CacheでHTTPSへのスキーム移行モードを設定
プラグイン「SNS Count Cache」の設定で「HTTPからHTTPSへのスキーム移行モード」を「有効」に、「HTTPからHTTPSへのスキーム移行日」に日付を設定し、設定を更新します。
この設定を行うことでhttp://
でシェアされた数とhttps://
でシェアされた数を合算することが可能です。
5.3 Google Search ConsoleへURL登録
Google Search Console(旧ウェブマスターツール)にhttps://
のURLを登録し、サイトマップを送信します。
5.4 Google AnalyticsのURL変更
Google Analyticsのアナリティクス設定で、「プロパティ設定」と「ビュー設定」のURLをhttps://
に変更します。
5.5 HSTS preload listへのドメイン登録
nginxの設定でHTTP Strict Transport SecurityのHTTPヘッダを追加した際、preloadというパラメータを追加しました。
その上でGoogleが実施しているHSTS preload listに自分のドメインを登録すると、Chromeなどの主要なブラウザと自分のドメインが常にHTTPSで通信する必要があることを伝えることができます。
そのため下記サイトで自分のドメインの登録申請をしておきます。ただしincludeSubDomains
パラメータも必要となるため、すべてのサブドメインがHTTPSでない場合は登録できないようです。
常時SSL化した後の「Qualys SSL Labs」での評価
SSLが有効なサーバを解析し、適切な設定がされているかを評価する「Qualys SSL Labs SSL Server Test」で設定内容をチェックしてみました。
苦労の甲斐あってか「A+」の評価をゲットすることができました。
参考にさせて頂いた他サイト
nginxの設定関連など、今回かなり多くのサイトの記事に助けられました。参考にさせて頂いたサイトは以下の通りです。
- 自社WordPressサイトを完全HTTPS化しました。 – 稲葉サーバーデザイン
- HTTPS on Nginx: From Zero to A+ (Part 1) – Julian Simioni
- HTTPS on Nginx: From Zero to A+ (Part 2) – Configuration, Ciphersuites, and Performance – Julian Simioni
- nginx + ssl + fastcgi で phpMyAdmin を動作させようとしてハマった | dogmap.jp
おわりに
FastCGIの設定漏れでかなりハマったため、サイトの表示がおかしくなる時間をかなり長く作ってしまいましたが無事に常時SSL化できて一安心です。
Googleのランキングシグナルに使用されるとはいえ、コンテンツの質に比べれば重要度は低いため、ユーザへの安全性提供と自己満足が今回の主な効果だと思います。