Lighttpd + Catalyst FastCGIの設定: 複数アプリ&外部FastCGI

| | |
色々試した結果,ようやく良い感じのlighttpdのFastCGI設定が書けたので公開しておきます。環境はCatalyst-5.64 + lighttpd-1.4.10で,他のバージョンではテストしていません。
  • 複数アプリ対応
  • local-server, external-server両方の例
  • $c->baseや$c->uri_forも正しく動く
  • app/root/static以下のファイルはlighttpdが処理する
server.modules += ( "mod_alias", "mod_redirect", "mod_fastcgi") server.document-root = "/var/www/localhost/htdocs" url.redirect = ("") alias.url = ("") # app1 url.redirect += ( "^/app1(\?.*)?$" => "/app1/$1" alias.url += ( "/app1/static/" => "/path/to/App1/root/static/" ) $HTTP["url"] =~ "^/app1/(?!static/)" {     fastcgi.server = (         "/app1" => ( "localhost-ext" => (             "check-local" => "disable",             # -- external --             "host" => "127.0.0.1",             "port" => 10021,             # -- local --             # "bin-path" => "/path/to/App1/script/app1_fastcgi.pl",             # "socket" => "/tmp/app.sock",         ))     ) } #app2 url.redirect += ( "^/app2(\?.*)?$" => "/app2/$1" ) alias.url += ( "/app2/static/" => "/another/path/to/App2/root/static/" ) $HTTP["url"] =~ "^/app2/(?!static/)" {     fastcgi.server = (         "/app2" => ( "localhost-int" => (             "check-local" => "disable",             # -- external --             # "host" => "127.0.0.1",             # "port" => 10022,             # -- local --             "bin-path" => "/other/path/to/App2/script/app2_fastcgi.pl",             "socket" => "/tmp/app.sock",         ))     ) }   FastCGIの動作を変える重要なオプションは"bin-path", "check-local"と,fastcgi.server配列のキー("/app1"など,ドキュメントでは<extension>)の三つです。 まずは"bin-path"です。このオプションがあるとlighttpdは子プロセスとしてFastCGIプロセスを起動します(local-server)。そのとき,"socket"オプションで指定したファイルを開いてFastCGIプロセスの標準入力とし,このソケット経由で通信します。今回は省略していますが,{min,max}-procsやbin-environなどのオプションはこのモードのときだけ有効です。"bin-path"が無いときはlighttpdはFastCGIプロセスの起動に関与せず(external-server),host:portまたはsocket経由でFastCGIプロセスと通信します。 続いて"check-local"です。最初,このオプションの意味が良く分からなかったのですが,「これはPHP向けなんだな」と気づいてようやく意味が分かりました。"check-local" => "enable"のとき(こっちがデフォルトです),lighttpdは"document-root/path"を探してファイルがあるかどうかをチェックします(例えば/index.php → /var/www/localhost/htdocs/index.php)。ファイルが存在しているときに限りFastCGIに処理を渡します。存在しないときは404となります(Railsではこの404-handlerを使って処理を渡しています)。"check-local" => "disable"のときはこのチェックが省略され,document-root以下にファイルがあろうがなかろうがFastCGIに処理を回してくれます。 最後に"<extension>"です。".ext"と拡張子で指定するか,"/app1"のように/から始まるprefixで指定するかの,二通りの方法があります。ドキュメントには書いていないですが,ここの指定により,FastCGIに渡すSCRIPT_NAME, PATH_INFOが決定されます。 prefixで指定するときには"/app1"とするか,"/app1/"とするかで違いがあります。ドキュメントではExamplesの中でこっそりと書いているので分かりにくいですが,最後に"/"を付けるか付けないかで,SCRIPT_NAMEとPATH_INFOの値が変わります。"/app1/"としたときにはその後に続くファイル名(と推定される部分?)をSCRIPT_NAMEとします。"/app1"としたときには"/app1"がSCRIPT_NAMEになります。また,$HTTP["url"]で条件分けしているからといってこの部分を省略したりすると,SCRIPT_NAMEとPATH_INFOが予期しない値になってしまいます。 以上の3点が設定できれば後は細かな調整だけです。"/app1"→"/app1/"としたりするなら,301 Moved Permanentlyを返してブラウザ側にURLを変えさせた方が良いので,url.redirectを使うようにします。(本当はパスではなく絶対URLで返した方が良いようなのですが,$HTTP["host"] + "/app1/$1"などとやってもダメだったので妥協) "/app1/static/"以下をCatalyst + C::P::Static::Simple経由ではなく,lighttpdに直接処理させるには,document-rootと関係なく処理できるurl.aliasを使っています。同時にFastCGIハンドラに処理が渡らないよう,条件文でfastcgi.serverの設定を切り分けています。 url.redirect, alias.urlの設定を「最初は = ("..." => "...")で,後は += ("..." => "...")で」といった非対称な設定にするより,全部+=で書けるようにするために,ダミーを放り込んでいます。alias.url = ()とは書けなかったので = ("")と空エントリを入れています。(何でこれで良いのかは未調査) SCRIPT_NAMEやPATH_INFOが正しく渡っていることを確認してみましょう。App1のdefaultで色々表示させてみます。 sub default : Private {     my ( $self, $c, @args ) = @_;     my $str = "App1::default\n"        . "uri: " . $c->request->uri . "\n"        . "base: " . $c->request->base . "\n"        . "arg: " . join(':',@args) . "\n"        . "req->arg: " . join(':',@{$c->request->arguments}) . "\n"        . "req->parameters: " . join(', ',map{"$_:".$c->request->parameters->{$_}} keys %{$c->request->parameters}) . "\n"        . "engine->env->{REQUEST_URI}: " . $c->engine->env->{REQUEST_URI} . "\n"        . "engine->env->{SCRIPT_NAME}: " . $c->engine->env->{SCRIPT_NAME} . "\n"        . "engine->env->{PATH_INFO}: " . $c->engine->env->{PATH_INFO} . "\n"        . "engine->env->{QUERY_STRING}: " . $c->engine->env->{QUERY_STRING} . "\n"        . "uri_for: " . $c->uri_for('test') . "\n";     $c->response->body( $str ); }   $ script/envtest_fastcgi.pl -n 1 -l :10021   として,:10021で待たせます。テストなのでデーモン化はしていません。 $ GET -e 'http://localhost:8080/app1/foo/hoge?a=1&b=2' Connection: close Date: Sun, 26 Feb 2006 14:33:36 GMT Server: lighttpd/1.4.10 Content-Length: 355 Client-Date: Sun, 26 Feb 2006 14:33:36 GMT Client-Peer: 127.0.0.1:8080 Client-Response-Num: 1 X-Catalyst: 5.64 App1::default uri: http://localhost:8080/app1/foo/hoge?a=1&b=2 base: http://localhost:8080/app1/ arg: foo:hoge req->arg: foo:hoge req->parameters: a:1, b:2 engine->env->{REQUEST_URI}: /app1/foo/hoge?a=1&b=2 engine->env->{SCRIPT_NAME}: /app1 engine->env->{PATH_INFO}: /foo/hoge engine->env->{QUERY_STRING}: a=1&b=2 uri_for: http://localhost:8080/app1/test   app1/root/static以下がlighttpd経由で送信されていることも確認しておきましょう。X-Catalystヘッダが無いですし,FastCGIプロセスを落としているときでも送信されています。  $ wget -S http://localhost:8080/app1/static/images/catalyst_logo.png --23:38:10--  http://localhost:8080/app1/static/images/catalyst_logo.png            => `catalyst_logo.png' Resolving localhost... 127.0.0.1 Connecting to localhost|127.0.0.1|:8080... connected. HTTP request sent, awaiting response...   HTTP/1.0 200 OK   Connection: keep-alive   Content-Type: image/png   ETag: "-514715257"   Accept-Ranges: bytes   Last-Modified: Sun, 26 Feb 2006 08:53:16 GMT   Content-Length: 13710   Date: Sun, 26 Feb 2006 14:38:10 GMT   Server: lighttpd/1.4.10 Length: 13,710 (13K) [image/png] 100%[====================================>] 13,710        --.--K/s 23:38:10 (64.41 MB/s) - `catalyst_logo.png' saved [13710/13710]   追記:2006/02/27 09:35 (バーチャル)ホスト全体のハンドラとしてFastCGIにする場合のSCRIPT_NAME, PATH_INFOについても同じことが起こる様子。fastcgi.server => ( "/" => ... )とすると「"/"で終わるprefix」として認識され続くURLをスクリプトファイル名とみなす。fastcgi.server => ( "" => ... )とすると「空のprefix = 空文字列のスクリプトファイル」として認識される。

Trackback URL for this post:

http://old.typemiss.net/trackback/73