Lighttpdのプラグイン開発に苦戦しています。
- 低レイヤプログラミングになる程, 特にメモリに注意しないといけない
- システムコールの戻り値に気をつかう(エラーハンドリング)
- 様々なコンテキストに対応する必要がある
I/O多重化の時の挙動をもっと理解しないといけないなと思ってます。
システムプログラミングという領域は, OSを理解することなしでは成り立たないですね。
息抜きということでLighttpdのインストールとLighttpd上で動くアプリについて書きます。
OSXにLighttpdをインストールする
OSXにLighttpdをインストールする手順です。
$ ./configure --without-pcre --prefix=/usr/local/lighttpd/lighttpd-1.4.32
$ make
$ make install
configure で –without-pcre はpcreがなかったから指定しました。
正規表現は大事なので入れましょう。prefixでインストール場所を指定します。
/usr/local/etc/lighttpd.confを開いて, ポート, ドキュメントルート, logの場所を以下のように設定します。
server.document-root = "/usr/local/var"
server.errorlog = "/usr/local/var/log/lighttpd.error.log"
server.port = 80
## bind to localhost (default: all interfaces)
server.bind = "127.0.0.1"
lighttpdを起動します。index.htmlでも作って確認してください。
# start
$ sudo /usr/local/sbin/lighttpd -f /usr/local/etc/lighttpd.conf
CGIとFastCGIの違い
CGIは仕様自体が古くWEBサーバと通信するプロセスは, リクエスト毎に起動される必要があります。
そのためサーバが毎回インタプリタを起動しなければなりません。
一方で, FastCGIの場合WEBサーバにインタプリタを組み込む代わりに, バックグラウンドでプロセスを生成しておきソケット通信します。
プロセスは起動後ループしているため, 毎回起動するCGIに比べ速くなります。
CGIで動かす
lighttpd.confを変更して, CGIを使えるようにします。
server.modules += ("mod_cgi")
cgi.assign = (
".bin" => "",
".py" => "/usr/bin/python",
".pl" => "/usr/bin/perl",
".fcgi"=> "/usr/bin/python",
".rb" => "/usr/bin/ruby"
)
必要なpythonパッケージをインストールします。
$ sudo easy_install web.py
hello.pyを作成して, 定番のhello worldを書きます。
#!/usr/bin/python
# -*- coding: utf-8 -*-
import web
print "Content-Type: text/plain"
print
print "hello world."
CGIで使うためのおまじないをかけます。
$ chmod +x hello.py
ブラウザを開いてlocalhostにアクセスします。
lighttpd.confをparseしているのはconfigfile.cとconfigfile-glue.cです。
プラグインのフックエントリがjoblistの場合は、リクエストが確定する前にjoblistが呼ばれるので “.py” -> “/usr/bin/python” のように記述してもルーティングしてくれないようです。従って、プラグイン内でrequest.url->ptrで文字比較して判定する必要があります。
FastCGI
次はFastCGIです。まずは, lighttdの設定からです。
server.modules += ("mod_fastcgi")
fastcgi.debug = 1
fastcgi.server = (
"/hello_wsgi.fcgi" =>
((
"host" => "127.0.0.1",
"port" => "1111",
"bin-path" => "/usr/local/var/hello_wsgi.fcgi",
"max-procs" => 1
))
)
url.rewrite-once = (
"^/favicon.ico$" => "/static/favicon.ico",
"^/static/(.*)$" => "/static/$1",
"^/(.*)$" => "/hello.py/$1",
)
FastCGIはバックグラウンドでプロセスを生成しておくことでCGIと起動と終了のコストをなくせます。
一方で, リクエストが来なくても一定のメモリを消費する・このプロセスを監視する必要があるというデメリットもあります。
unix-domain socketで他のポートのプロセスと通信することが必要ですが, ここではspawn-fcgiを使って unix-domain socketの設定を肩代わりさせます。
$ tar zxvf spawn-fcgi-1.6.3.tar.gz
$ cd spawn-fcgi-1.6.3
$ ./configure
$ make
$ make install
spawn-fcgiは/usr/local/bin/spawn-fcgiにあります。
Web Server Gateway Interface (WSGI, ウィズギー) モジュールをインストールします。
$ sudo easy_install flup
サーバアプリケーションを書いてhello_wsgi.fcgiという名前で保存します。
[1] https://flask.pocoo.org/docs/deploying/fastcgi/
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from cgi import escape
import sys, os
from flup.server.fcgi import WSGIServer
def app(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
yield '<h1>This is FastCGI</h1>'
WSGIServer(app).run()
起動の手順はfcgiプロセス -> lighttpd の起動の順で行います。
$ sudo killall lighttpd
# if used fcgi_proccess , kill PID
$ spawn-fcgi -f /usr/local/var/hello_wsgi.fcgi -a 127.0.0.1 -p 1111 -u www-data -g www-data
$ spawn-fcgi: child spawned successfully: PID: 29955
$ sudo /usr/local/sbin/lighttpd -f /usr/local/etc/lighttpd.conf
ブラウザを開いてみましょう。
[2] mod_proxyのソースコードリーディング
[3] mod_websocketなるものを発見しました。シェア1%のサーバにwebsocketのプラグインを書く人がいることに感動です。