AWS-NLBでHTTP通信をHTTPS通信に強制リダイレクトする方法

2021-11-30

AWSでロードバランサーを使用する場合、通常ALBを使用すると思う。ALBは料金も少し安いし、バックエンドのEC2へのルーティングやHTTPSリダイレクトが簡単にできるからだ。

ALBを利用できないケース

しかし、ALBを使用できないケースもある。それは、NSをRoute53に設定できない時だ。Route53以外でDNSを設定する場合、ALBへのルーティングはCNAMEを設定せざるを得ない。しかし、例えば、WEBサーバーをドメインaaa.comとwww.aaa.comで運用したい場合(wwwありをwwwなしにリライトして)、「aaa.com」はCNAMEを設定できないのだ。DNSの仕組み上不可能である。そのため、ノンサブドメをALBへ向けることができないのだ。(自分が知らないだけで、外部NSでALBを運用する方法があればすいません)

こういう場合は、NLB(Network Load Balancer)を利用すれば、上記のことを実現できる。

NLB、NginxでSSL通信

NLBでは、LBに対してIPアドレスを設定できる。そのため。DNSでwwwなしもwwwありもAレコードでNLBに向けることができる。しかもACMによってSSL証明書をセットしてhttps通信も簡単にできる。以下のイメージだ。

HTTP通信  :—(80)—> (NLB) –>(80)–> EC2(Nginx)
HTTPS通信:—(443)–> (NLB) –>(80)–> EC2(Nginx)

そして、LBではなくNginxでHTTP通信をHTTPS通信へリダイレクトしたいはずだ。ググると以下のconf設定が出てくる。

if ($http_x_forwarded_proto != https){
   return 301 https://$host$request_uri;
}

しかし、これはNLBではうまくできない!

NLB+NginxでHTTPをHTTPSへリダイレクト

いろいろ調べたが、以下のようにすれば解決。同じ方法でApacheでも可能だ。

  1. EC2に設定しているセキュリティグループのインバウンドで80と8080を許可する。
  2. 80ポートで待ち受けるEC2のターゲットと8080ポートで待ち受けるEC2のターゲットにしたターゲットグループを2つ作成する。
  3. NLBのリスナーで【443】を【80のターゲット】に、【80】を【8080のターゲット】に設定。
  4. Nginxのconfで8080ポートを以下のように設定する。
server {
     listen 8080;
     server_name _;
     root /usr/share/nginx/html;
     index index.html index.htm index.php;

     if ($http_user_agent !~* ELB-HealthChecker){
         return 301 https://$host$request_uri;
     }
}

これにより、NLBへのHTTP(80)通信をNginxの8080ポートへ流し、443へ強制的にリダイレクトできる。このとき、LBのヘルスチェックの時だけは200をリターンできるようにしておく。