BLOGサブスレッドの日常
2019.04.24
nginx の proxy_pass の闇
torikai
月曜日担当の鳥飼です。
2日連続です。よろしくお願いします。
nginx 使っていますか? 私はまだまだ使いこなせていないのですが…
先日遭遇した nginx のproxy_pass
の設定の小ネタを紹介します。
よくある設定
location /hoge/ {
proxy_pass https://hoge.example.com/;
}
これは、/hoge/
以下のアクセスを、https://hoge.example.com/ に転送する設定ですね。
例えば、/hoge/hige?food=curry
にアクセスすると、https://hoge.example.com/hige?food=curry に転送します。
ただ、この書き方だと少し困ったことがありました。
それは、proxy_pass
に指定した URL の IP が変わった時です。
nginx の proxy_pass に指定したURLの名前解決のタイミング
nginx のproxy_pass
に指定している URL の名前解決は nginx 起動時に行われ、以降はその IP を使い続けます。
ホストからIPを逆引きした時、得られる IP が固定の場合はこの挙動でも良いのですが…
ALB(ELB) や S3 などの DNS を CNAME に設定している場合、Auto Scaling が働くと IP が変わります。
先程触れたように、nginx では名前解決は起動時の一度のみ。
つまり、Auto Scaling などの理由でIPが変わった場合、nginx は起動時に名前解決した時の IP で転送処理を続けてしまいます。
そうだ TTL のキャッシュ時間を短くしよう
そこで、resolver
ディレクティブの valid
オプションを使って、TTL
のキャッシュ時間を短くしてみました。
ほぼ都度名前解決を行うので IP が変わったら新しい IP に転送するはず!
あんまり行儀が良いとは言えませんが、かと言って古い IP を持たれても困るので^^;
cf. resolver ディレクティブ
location /hoge/ {
resolver 172.31.0.2 valid=5s;
proxy_pass https://hoge.example.com/;
}
(172.31.0.2
は、AWSのVPC内DNSサーバのIPです)
これで解決する…
と思っていたのですが。
闇があった
実はこれでは設定が不充分であり、この設定では nginx はずっと古い IP を持ち続け、名前解決をしてくれませんでした。
(そんな馬鹿な)
泣きたい気持ちで proxy_pass ディレクティブのページをよくよく読んで見れば、こんなことが書かれていました。
Parameter value can contain variables. In this case, if an address is specified as a domain name, the name is searched among the described server groups, and, if not found, is determined using a resolver.
再度名前解決をする為には変数を指定しなければならない、というような断定的な書き方ではないものの、proxy_pass
に変数を指定すると上手く名前解決をしてくれそうです。
location /hoge/ {
resolver 172.31.0.2 valid=5s;
set $endpoint hoge.example.com;
proxy_pass https://$endpoint/;
}
転送先ホストのIPを切り替えながらテストをしてみました。
proxy_pass
に直接URLを指定している場合、転送先ホストのIPが変わると古いIPに転送するproxy_pass
に変数を指定している場合、転送先ホストのIPが変わると新しいIPに転送する
上記2点の確認を行い、想定の挙動を確認しまして、これで解決、とほっと胸をなでおろしました。
のですが…
闇はもう少し深かった
上記設定で/hoge/hige?food=curry
にアクセスしてみると、https://hoge.example.com/ に転送されます。
期待する転送先は https://hoge.example.com/hige?food=curry です。
そう、/hoge/
以下のパラメータがまるっと無視されています。
(そんな馬鹿な)
/
の有無で転送の挙動が変わる、ということは知っていたのですが、まさか文字列指定を変数に変更しただけで挙動が変わるとは露程にも思いませんでした…
とは言え、そうなるものはしょうがない(´・ω・`)
最終的な設定内容
正規表現を使って、/hoge/
以下のパスをproxy_pass
にくっつけつつ、クエリストリングがあれば追加するようにしました。
location ~ /hoge/(.*) {
resolver 172.31.0.2 valid=5s;
set $endpoint hoge.example.com;
proxy_pass https://$endpoint/$1$is_args$args;
}
これにて I got Kotonaki.
想定した通りに転送され、解決しました。
余談
社内に共有したところ
「っていうかこれnginxのバグじゃない?」
「旧バージョンではURLを直接指定したら構文エラーになっていたので、こんな怪しい動きをするならいっその事そのままで居てくれたほうがよかった」
「nginx にかかわらず、リバースプロキシの設定はちょっと値が変わるだけでも動きが変わるので変更した場合は念入りにテストした方が良いね」
…などなど、熱い議論が交わされました。
正直、まさかここまで振り回されるとは思いませんでした^^;
もし、nginx のproxy_pass
の設定で悩まれている方の助けになりましたら、幸いです。
今日のひとネタでした(・ω・)ノ
この記事を書いた人
torikai