ポンコツエンジニアのごじゃっぺ開発日記。

いろいろポンコツだけど、気にするな。プログラム&ロボット大好きなポンコツが日々の記録を残していきます。 自動で収入を得られるサービスやシステムを作ることが目標!!

LBにSSLサーバ証明書を置いている場合のHTTPのリクエストをHTTPSにリダイレクトするときに気をつけること。

このブログのサーバの話ですが、せっかく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番ポートに流してくれています。

f:id:ponkotsu0605:20190418004228p:plain

(参考:GCP上でWordPressを動かしてみた。

気をつけないといけないのは、このような構成にすると、ここでいう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のデベロッパーツールで確認すると以下のようになりました。

f:id:ponkotsu0605:20190418004337p:plain

レスポンスヘッダのLocationがちゃんとhttpsのURIになっており、またStatus Code301 Moved Permanentlyになって、しかも2回目以降のリクエストはfrom disk cacheになっているのがわかると思います。

このようにして、無事、キレイにリダイレクトさせることができました。