lighttpd 1.4.x で X-Reproxy をできるようにする mod_fastcgi_reproxy

追記@2009-10-20: もっとちゃんとした reproxy モジュールを書きました。こちらの新しい記事を参照ください。

lighttpd 大好きっ子な村瀬です。

突然ですが、perlbal というロードバランサーをご存じでしょうか。この perlbal には reproxy という機能があります。 これは、このロードバランサー下のWebサーバーが

X-Reproxy-Url: http://example.com/

などというヘッダを返すと、perlbal がその URL の内容を取得し、コンテンツボディをその URL の内容に置き換えてくれるという物です。

MogileFS や Amazon S3 との相性のいい機能ですね。

これを lighttpd でもやりたくなったのでがんばってみました。

mod_fastcgi_reproxy

既存の mod_fastcgi に reproxy 機能を組み込んだモジュールです。パッチにしてもよかったのですが、別モジュールのほうが使い勝手がいい気がしたので別名で作ってみました。

reproxy 機能以外は基本的に mod_fastcgi として動作するため、このモジュールを使用する場合は mod_fastcgi をロードしないようお気をつけください。

使い方は mod_fastcgi と全く同じですが、あたらしく allow-x-reproxy というオプションが追加されており、これを "enable" にすることで reproxy 機能が有効になります。

実際に使える最小の lighttpd.conf

server.modules = (
    "mod_fastcgi_reproxy",
)

server.document-root = "/home/typester/dev/lighttpd/lighttpd-1.4.21"
server.port = 80

fastcgi.server = (
    "" => (
        ( "bin-path" => "/home/typester/dev/lighttpd/lighttpd-1.4.21/test.fcgi",
         "socket" => "/tmp/fcgi.socket",
         "max-procs" => 1,
         "check-local" => "disable",
         "allow-x-reproxy" => "enable",
        ),
    ),
)

このような感じになります。

test.fcgi

#!/usr/bin/env perl

use strict;
use warnings;

use CGI::Fast;

while (my $q = CGI::Fast->new) {
    print "X-LIGHTTPD-reproxy-host: example.com\n";
    print "X-LIGHTTPD-reproxy-path: /path/to/file.jpg\n";
    print "\n";
    print "Hello fcgi";
}

こんな感じとなってます。

この fcgi では "Hello fcgi" というコンテンツを返していますが、mod_fastcgi_reproxy によりコンテンツが置き換えられ、実際には http://example.com/path/to/file.jpg のデータが返ります。

lighttpdには以前ご紹介した X-Sendfile という仕組み がありますが、こちらと組み合わせると、

  • S3 のデータをローカルでキャッシュしている場合には X-Sendfile でローカルのファイルを出力
  • キャッシュがない場合には X-Reproxy で S3 のファイルを出力

というようなことが簡単にできるようになります。

実はこの機能は、lighttpd 1.5 では実装済み (X-Rewrite-* という名前) だったりするのですが、1.5はまったくもってリリースされないので待ちきれずにハックしてしまいました。後悔はしていません。

現在の問題としては

  • fcgi で出力されたヘッダと reproxy 先で返されるヘッダのマージ処理がおかしい
  • 自分自身に reproxy されると無限ループ><

などがあります。

皆様のバグレポートをお待ちしております。

ではまた!

カヤックでは apache モジュールや lighttpd モジュール、また perlbal プラグインなどをがんがん書くことが出来る技術者を募集しています!