AWS ELB配下でApacheのRewriteRuleが上手く動かなかった話


■環境

AWS ELB
AWS EC2
Apache 2.2.32


AWSのEC2上で動いているApacheサーバーでの話。

SEO対策で/index.html/にリダイレクトしたかったので
.htaccess に以下を設定しました。

RewriteRule ^(.*)index.html$ $1 [R=301,L]  

検証インスタンスでは上手く動いたので、本番インスタンスにも反映させたところ
https://〜/index.html(443ポート) が http://〜/(80ポート)にリダイレクトされるようになってしまいました。

なんでだろう?と思いながら以下のような分岐を作ってみましたが、結果は変わらずでした。

# 一旦プロトコルはhttpとしておく  
RewriteRule .* - [E=X_PRTCL:http]  
# リクエストプロトコルがhttpsの場合、リダイレクト先もhttpsにする  
RewriteCond %{HTTPS} on  
RewriteRule .* - [E=X_PRTCL:https]  
RewriteRule ^(.*)index.html$ %{ENV:X_PRTCL}://%{HTTP_HOST}/$1 [R=301,L]  

なぜ443ポート(https)の通信が80ポート(http)扱いになってしまったかというと
本番環境のEC2はELBを通しているのが原因でした。

つまり、検証環境では

PC  
↓443ポート  
EC2  

だったのに対して、本番環境では

PC  
↓443ポート  
ELB  
↓80ポート  
EC2  

となっていたのでした。

ELBを経由した場合、HTTPプロトコルを判定するにはX-Forwarded-Protoというパラメータを見る必要があるようです。
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/classic/x-forwarded-headers.html

以下のようにhtaccessへ記載すればELB経由でも上手く動きました

# 一旦プロトコルはhttpとしておく  
RewriteRule .* - [E=X_PRTCL:http]  
# リクエストプロトコルがhttpsの場合、リダイレクト先もhttpsにする  
RewriteCond %{HTTPS} on [OR] # ELBを経由しない時用  
RewriteCond %{HTTP:X-Forwarded-Proto} https # ELBを経由する時用  
RewriteRule .* - [E=X_PRTCL:https]  
RewriteRule ^(.*)index.html$ %{ENV:X_PRTCL}://%{HTTP_HOST}/$1 [R=301,L]