アクトインディ技師部隊報告書

子供とお出かけ情報「いこーよ」を運営する、アクトインディ株式会社のエンジニアブログです

HTTP/HTTPS判定をnginx側で判定するようにしました

こんにちは、endoです。

いこーよのHTTP/HTTPS判定をアプリケーション側から、nginxで行うようにしました。

rails5へのアップデート作業の途中経過報告に書いていたことを実現しました。

理由としては、下記の通りです。

  • アプリケーション側で行うより、ALB/nginx側で行う方がコンピュータに優しい
  • rails5のupdate作業中にssl_requirementのメンテナンスをなくしたかった

対応としては、下記のことに注意しないといけません。

  • HTTPSリダイレクト
    • 一部HTTPでもアクセス可能
  • ALBのhealth check対応

HTTPSリダイレクト

いこーよはALBでHTTPS判定を行っているので、その前提でお話しします。

ALBは暗号化処理を終わらせた状態で後続のリクエストを流してくれます。

user    →    ALB    →    nginx    →    rails
      暗号化       暗号解除(平文)

ALBは暗号化処理を解除した証にヘッダーにX-Forwarded-Protoをhttpsという値をつけてくれています。

nginxは$http_x_forwarded_protohttpsかどうかを判定すれよくなります。

httpアクセスの場合は、ALBはヘッダーにX-Forwarded-Protoをつけてこないので、それを利用します。

ALBはヘッダーにX-Forwarded-Protoをつけてこないので、それを利用します。

location / {
  ...

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

  ...
}

これでHTTPSのリダイレクトは可能になりました。

一部HTTPでもアクセス可能

こちらは特定のURLの場合の設定をnginx側に書きます。


location /foo {
  try_files $uri @app;
}

try_filesでそのまま通常の設定に送ります。

ALBのhealth check対応

health checkをHTTPS通信で行うと暗号を解除しないといけなくなるのでHTTP通信で行います。

ここで気をつけないといけないことです

  • health checkはHTTP
  • health check以外はHTTPS
location /bar {
  # ヘルスチェックはHTTP通信を許可する
  if ($http_user_agent ~ "ELB-HealthChecker") {
      proxy_pass http://app_server;
      break;
  }

  # HTTP通信の場合は、HTTPSにリダイレクトする
  if ($http_x_forwarded_proto != https) {
      return 301 https://$host$request_uri;
  }
  try_files $uri @app;
}

User AgentでALBかどうかを判定します。

リリース時の対応

nginxの設定を反映すれば完了です。

いこーよはマルチAZなので、アクセスを片方に寄せてnginxを起動することもできるのですが、若干めんどくさいですね。

nginxはプロセスで設定を「反映する前」と「反映後」を共存できるので,それを利用して反映します。

sudo /opt/nginx/sbin/nginx -t←設定ファイルを確認する

sudo kill -USR2 `cat /var/run/nginx.pid`←設定後のプロセスを立ち上げてくれて、反映前のプロセスと共存します。
sudo kill -WINCH `cat /var/run/nginx.pid.oldbin`←反映前のworkerプロセスを終了する
sudo kill -QUIT `cat /var/run/nginx.pid.oldbin`←反映前のプロセスを終了する

これでリリースは終了です。

唯一の懸念点は、health checkのUser Agentが変更されたら、health checkでサーバーが落ちていきます。

こんなことがあるのかは、わからないですが、現象さえわかっていれば対応は取れます。

以上です。

補足

ステージングでhealth check対応かどうかを調べていたときの方法です。


curl 'http://staging.net/foo' -H 'User-Agent: ELB-HealthChecker'

curlコマンドのUser Agentを入れて確かめていきました。

参考

無停止でnginxを手動upgradeする