NginxのリバースプロキシでのDNS名前解決における落とし穴
問題
Nginxのリバースプロキシでは、プロキシ先として(IPアドレスの他に)ホスト名を指定することができます。 その際、設定ファイルのlocationコンテキストは以下のようになると思います。
location /hoge/ { proxy_pass http://example.com/; }
しかし、これには大きな落とし穴があります。DNSの名前解決がnginxの起動時にしか行われず、TTLは無視され、初回起動時に解決されたIPアドレスがずっと使われてしまうのです。 もちろん、ホスト名に対応するIPアドレスに変更があったときにエラーになってしまいます。
自分の場合では、プロキシ先としてAWSのELBのホスト名を指定しており、(ELBのアドレスは固定ではないので)この問題が原因で502エラーを吐き出してしまっていました。
解決策?
nginxにはresolverというディレクティブがあります(公式ドキュメント)。By default, nginx caches answers using the TTL value of a response
とあるので、TTLが尊重されるみたいです。うまく行きそうな気がします。
試しにresolverにはGoogle Public DNSの8.8.8.8
を利用してみます。
location /hoge/ { resolver 8.8.8.8; proxy_pass http://example.com/; }
しかし、これでもうまくいきません。もはやバグですね。
解決策
このようにして、一旦ホスト名を変数に格納して使うと、うまくいくようです。
location /hoge/ { set $target example.com; resolver 8.8.8.8; proxy_pass http://$target/; }
なんだかなあって感じです。