HTTPSを強制するために .htaccess に細工をするのは有名。例えば以下のような書き方が王道。
1 2 3 4 5 |
<IfModule mod_rewrite.c> RewriteEngine on RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R,L] </IfModule> |
これをそのままElasticBeanstalkにデプロイするとリダイレクトループが発生する。正確に書くとリバースプロキシ(ロードバランサ)が有効になっている場合にリダイレクトループが発生する。
原因
原因についてはココが詳しい。ざっくりまとめると、
- ロードバランサが443へのアクセスを80へのアクセスに変換する
- .htaccess内の RewriteCond ${HTTPS} が永遠に on にならず、リダイレクトの度にRewriteRule が走ってしまう
元々のアクセスが https か http のどちらかが分かれば良いのだが、上記の挙動のせいで、https にリダイレクトしたとしても http からアクセスされたことになり、これが永遠に繰り返されてしまう。
解決策
(記事主さんが)無茶苦茶泥臭く挙動を追跡したところ、ロードバランサに到着した元のアクセスが http のときに限り、X-Forwarded-Proto というヘッダが付与され値が入るらしい。なので、X-Forwarded-Protoヘッダの内容を http か https かの判断基準にすれば良い、というのが基本的なアイデア。本人も言っているが、it’s just an empiric result… である。
その .htaccess が以下
1 2 3 4 |
RewriteEngine On # Force HTTPS RewriteCond %{HTTP:X-Forwarded-Proto} !=https RewriteRule ^/?(.*) https://%{HTTP_HOST}/$1 [R,L] |
これを ElasticBeanstalkにデプロイすると見事に動作する。
開発環境との共存
開発もAWSで行っていればこれで良いのだがそうでない場合も多いと思う。
上記のAWS用.htaccessを非AWSな開発環境に持ってくると今度は RewriteCond %{HTTP:X-Forwarded-Proto} !https が常に真になり、リダイレクトループが発生する。
あっちが立てばこっちが立たない!
いろいろ試行錯誤した結果、以下なら両立できた。(2017/7/8訂正)
1 2 3 4 5 |
RewriteEngine On # Force HTTPS RewriteCond %{HTTPS} !=on RewriteCond %{HTTP:X-Forwarded-Proto} !=https RewriteRule ^/?(.*) https://%{HTTP_HOST}/$1 [R,L] |
根拠となる X-Forwarded-Proto がとっても経験的!なので、いつの日か使えなくなる日が来るかもしれない。