このブログのサーバの話ですが、せっかくSSL証明書を設置してHTTPS化したので、HTTPのリクエストは全てHTTPSにリダイレクトさせたくなりますよね。もちろんレスポンスヘッダーは301で。
ということで、今回はそのリダイレクトの方法について書いていきたいと思います。
HTTPをHTTPSにリダイレクトさせよう
さて、リダイレクトさせる方法をググると、以下のような.htaccessを使ってリダイレクトさせようって出ると思います。
RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
このようになると思います。
たしかに、この方法は、HTTPでアクセスした際に、HTTPSにリダイレクトさせてくれます。
ただ、ここで問題!
今回の自分の場合は、以下のように、ロードバランサにSSL証明書を配置してHTTPSのリクエストをLBで受けてバックエンドサーバに80番ポートに流してくれています。
気をつけないといけないのは、このような構成にすると、ここでいうWordPressのサーバは80番ポートでリクエストを受け取るので、この.htaccessの書き方だと、もしユーザがHTTPSでリクエストしてもWordPress側はHTTPのリクエストだと思ってしまい、またHTTPSのURLにリダイレクトさせようとしてしまいます。結果として、リダイレクトループに陥ってしまいます。
この.htaccessをPHPでも同じように書けます。
<?php if (empty($_SERVER['HTTPS'])) { header( "HTTP/1.1 301 Moved Permanently" ); header("Location: https://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}"); exit; }
これも同じようにリダイレクトループに陥ってしまいます。
正しくリダイレクト処理を書こう
そこで使用するのが、リクエストヘッダーのX-Forwarded-Protoという情報。
これは、このブログの構成でのユーザがHTTPでアクセスしたかHTTPSでアクセスしたかでそれぞれ'http'と'https'の文字列が入るようになっています。なので、このヘッダー情報の文字列を比較することで、ユーザがHTTPでアクセスしたのかHTTPSでアクセスしたのかを知ることができます。
// ヘッダーを出力する var_dump(getallheaders()); // 実際の値を見てみる var_dump($_SERVER);
上のスクリプトを例えばWordPressであればindex.phpに埋め込むことでヘッダーの情報をダンプすることができます。
したがって、正しくリダイレクト処理を書こうとするとこのようになるかと思います。
if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'http') { header( "HTTP/1.1 301 Moved Permanently" ); header("Location: https://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}"); exit; }
これをindex.phpの最初の方に埋め込むことで、httpのリクエストをhttpsのURLにリダイレクトさせることができるようになります。
例えば、このブログであれば、http://blog.pnkts.netにアクセスしたときの通信内容をchromeのデベロッパーツールで確認すると以下のようになりました。
レスポンスヘッダのLocationがちゃんとhttpsのURIになっており、またStatus Codeが301 Moved Permanentlyになって、しかも2回目以降のリクエストはfrom disk cacheになっているのがわかると思います。
このようにして、無事、キレイにリダイレクトさせることができました。