37
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

ELB(https) + nginx でヘルスチェックがこける問題

SSL が必要な簡単なページを稼働させる際に、ELB の無料の SSL 証明書を利用した時にハマったお話

構成

簡単な図です。

b00ff7c3-fd0a-d4d4-3eec-960725c15b96.png

  1. ec2 の前段に ELB
  2. HTTPS(SSL) は ELB が対応
  3. ec2 へのアクセスは http
  4. http -> https へのリダイレクトは nginx 側で対応
  5. ec2 は一台のみ

問題が起きた設定

http://qiita.com/snoguchi/items/f5ccb67592f87942480d
はじめに、こちらの記事を参考に以下のように設定しました。

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  example.com;  # 利用するドメインを設定

        # アクセスが http なら https としてリダイレクト
        if ($http_x_forwarded_proto != https) {
            return 301 https://$host$request_uri;
        }

        location / {
                root /var/www/index/;
                index index.html;
        }
    }

これで一時はうまくいったのですが、しばらくするとページにアクセスできなくなり、503 Service Unavailable: Back-end server is at capacity というステータスが返されて表示できなくなりました。
どうやら ELB のヘルスチェックがこけて、ec2 が外されたようでした。

原因

ヘルスチェック自体は http で行っていたので、$http_x_forwarded_proto は http。
https へのリダイレクトの条件に合致して、ステータスコード 301 を返したのでヘルスチェックで fail 判定となって外された。
というのが原因だと推測されました。

対処

対処はいくつか考えられます。

  • ヘルスチェック用のルーティングを追加 (/healthcheck 等)
  • 別のポートで Server コンテキストを追加
  • default_server と server_name で別の server コンテキストを作成して分ける

他にもやり方は色々とあるかと思います。

ここでは一番最後の default_server と server_name で別の server コンテキスト作成して分ける方法で対応しました。
既存のドメイン指定の server コンテキストの default_server を削除して、ヘルスチェック用の 1px gif を返すだけのコンテキストを追加します。

    # health check 用 (とにかく 200 を返せれば OK)
    server {
        listen 80 default_server;
        listen [::]:80 default_server;
        root   /usr/share/nginx/html;

        location / {
                # empty_gif というモジュールで 1x1 の透過 gif を返します
                empty_gif;
                access_log off;
                break;
        }
    }

    server {
        # default_server を削除
        listen       80;
        listen       [::]:80;
        server_name  example.com;  # 利用するドメインを設定

        # アクセスが http なら https としてリダイレクト
        if ($http_x_forwarded_proto != https) {
            return 301 https://$host$request_uri;
        }

        location / {
                root /var/www/index/;
                index index.html;
        }
    }

これで問題なく稼働するようになりました。

ただ、上記の設定は IP 直でアクセスすると 1px の gif が表示されます。
対応した案件が、クローズドなサイトで IP でアクセスする必要が皆無の為このような設定になりましたが、IP でもドメインでも同様にアクセスさせたい場合は、ヘルスチェックを考慮した設定を考える必要があると思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
37
Help us understand the problem. What are the problem?