@kyanny's blog

My thoughts, my life. Views/opinions are my own.

nginx は 複数の URL が含まれた X-REPROXY-URL ヘッダを扱えない

Perlbal には、リバースプロキシとして利用しているときバックエンドが X-REPROXY-URL というヘッダに「ファイルの実体の URL」を入れてレスポンスを返すと Perlbal が改めてその URL にリクエストして (reproxy) 実体をとってきてからクライアントに返す、という機能があり、画像や動画などファイルサイズが大きい静的コンテンツを配信するのに便利なのでよく使われている。特に MogileFS と組み合わせて使う例がよくみられる。

この X-REPROXY-URL ヘッダによる reproxy 機能は Perlbal 以外のウェブサーバでもサポートされていて、 nginx でも扱うことができる (ApacheLighttpd でも対応したモジュールがある) できるんだけどリバースプロキシを Perlbal から nginx に変更したら X-REPROXY-URL ヘッダの扱いの違いでちょっと問題がおこり対応したのでメモ。

まず nginx で X-REPROXY-URL ヘッダによる reproxy 機能を利用するには http://d.hatena.ne.jp/perezvon/20080418/1208531594 にあるように nginx.conf で reproxy 専用の内部的な URL を宣言してやって (location /reproxy { ... } のところ) バックエンドからは X-Accel-Redirect ヘッダでその内部的な URL も指定する必要がある。 http://d.hatena.ne.jp/sfujiwara/20110406/1302077166 にも具体的な例が載っている。

Perlbal の場合は X-REPROXY-URL ヘッダにホワイトスペース区切りで複数の URL を含められる http://cpansearch.perl.org/src/DORMANDO/Perlbal-1.79/doc/reproxying.txt しかし nginx の場合は単一の URL でないとだめなようで、バックエンド側で文字列操作をして URL をひとつに加工してからレスポンスを返したらうまくいった。デバッグで追いきれてないので想像だけど、おそらく "http://foo.com:80/resource.html http://baz.com:8080/res.htm" というような単一の URL だとみなして reproxy してしまっているのだと思う。

ちなみに Perlbal に対して複数の URL を含む X-REPROXY-URL ヘッダを返すとどうなるかというと、順番に取得しにいって最初に 200 を返したコンテンツを配信するようになっている。 MogileFS はひとつのファイルを複数のストレージノードに分散して保存できるので同じコンテンツのコピーが複数存在することになり、 URL も複数存在しうるので、全部まとめて Perlbal に渡せるようにできているのだろう。