直径1.5メートル

ひよっこエンジニアのちょっとしたメモ。主に備忘録。

【nginx】ホスト名指定でのリバプロはresolverをセットで

nginxのリバースプロキシ設定で、転送先をIPではなくホスト名で指定していると、ある日突然エラーが発生する現象に遭遇しました。
ググると複数の記事が見つかったので、よくある現象?のようです。

リバースプロキシ設定

元々は↓のように設定していました。
proxy_passのところで、リクエストの転送先をホスト名で指定しています。

location ~ ^/hoge {
  proxy_pass https://example.com;
}

この状態だとnginx起動時に転送先のIPがキャッシュされ、以降はキャッシュしたIPへ転送するようになるようです。
IPが変わってもキャッシュしているIPへ転送し続けるので、AWSのELBを使っていたりすると、IPが変わった際にエラーが起きてしまうことも。
それを回避するため、proxy_passと併せてresolverを設定しておきます。

resolverを設定する

resolverを設定すると↓のような感じに。

location ~ ^/hoge {
  resolver 10.0.0.2;
  set $host_name example.com;
  proxy_pass https://$host_name;
}

resolverで指定するDNSのIPは、AWSの場合はVPCのネットワーク範囲+2とのこと。

AmazonProvidedDNS は Amazon DNS サーバーです。このオプションは、VPC のインターネットゲートウェイを介して通信する必要があるインスタンスに対して DNS を有効にします。文字列 AmazonProvidedDNS は、リザーブド IP アドレスで実行中の DNS サーバーにマップされ、VPC IPv4 ネットワークの範囲に 2 をプラスした値です。例えば、10.0.0.0/16 ネットワークの DNS サーバーの位置は 10.0.0.2 となります。
DHCP オプションセット - Amazon Virtual Private Cloud

デフォルトではTTLが切れたタイミングでDNSに問い合わせ。
resolverにvalidを設定すると、任意のタイミングで問い合わせることができるようです。
ex. valid指定

location ~ ^/hoge {
  resolver 10.0.0.2 valid=5s; # 5秒ごとに問い合わせ
  set $host_name example.com;
  proxy_pass https://$host_name;
}

nginxのバージョンによる?のか、nginx 1.6系、1.8系ではsetでホスト名を変数に入れないとエラーになるようです。
nginx 1.10.1では、setを使わずに指定しても設定できました。

参考

nginx proxy の名前解決問題、ファイナルアンサー? – 1Q77
Nginx のDNS 名前解決とS3 やELB へのリバースプロキシ :: by and for engineers
Nginxでproxy_passにホスト名を書いた時の名前解決のタイミング - (ひ)メモ