もう少し Web サーバらしく細かな設定をする名前ベースのバーチャルホストIP アドレスを共有する名前ベースのバーチャルホストを設定するときは nevow.vhost.NameVirtualHost をリソースツリーのルートに使用します。 nevow.vhost.NameVirtualHost もまたリソースタイプのオブジェクトです。 >>> from nevow import vhost >>> list(zope.interface.implementedBy(vhost.NameVirtualHost)) [<InterfaceClass nevow.inevow.IResource>, <InterfaceClass nevow.inevow.IRenderer >, <InterfaceClass nevow.inevow.IGettable>, <InterfaceClass nevow.inevow.IContai ner>, <InterfaceClass nevow.inevow.IRendererFactory>, <InterfaceClass nevow.inev ow.IMacroFactory>, <_MetaConfigurable formless.iformless.IConfigurable>, <Interf aceClass formless.iformless.IConfigurableFactory>] 以下は2つのバーチャルホスト www.example.com と www.example.org を設定する場合の例です。NameVirtualHost オブジェクトの addHost メソッドを使ってホスト名と対応するリソースを登録していきます。
# 名前ベースのバーチャルホスト
# nvhost.tac from nevow import appserver, static, vhost from twisted.web import error, twcgi from twisted.application import service, internet # 各バーチャルホストに共通の設定 PORT = 80 TIMEOUT = 300 UID = 33 GID = 33 LOGPATH = '/var/log/www/access.log' # バーチャルホスト毎の設定 config = ( ( # www.example.com 用の設定 'www.example.com', # ホスト名 '/var/www/www.example.com/html', # HTML 用ディレクトリ '/var/www/www.example.com/cgi-bin', # CGI 用ディレクトリ ), ( # www.example.org 用の設定 'www.example.org', '/var/www/www.example.org/html', '/var/www/www.example.org/cgi-bin', ), ) class FileWithoutListing(static.File): """ファイル一覧を表示しないリソース""" def directoryListing(self): return error.ForbiddenResource() root = vhost.NameVirtualHost(listHosts=False) for hostname, htmlDir, cgiDir in config: resrc = FileWithoutListing(htmlDir) cgiResrc = twcgi.CGIDirectory(cgiDir) resrc.putChild('cgi-bin', cgiResrc) root.addHost(hostname, resrc) site = appserver.NevowSite(root, logPath=LOGPATH, timeout=TIMEOUT) server = internet.TCPServer(PORT, site) application = service.Application('my_httpd', uid=UID, gid=GID) server.setServiceParent(application) なお上記例では、バーチャルホストとして登録されていない名前やアドレス直接指定でアクセスがあった場合 404 NotFound を返すようになっています。 nevow.vhost.NameVirtualHost のオブジェクト作成時に指定できるオプション引数は以下の通りです。
リダイレクトtwisted.web には一時的なリダイレクト(302 Found)用のリソース twisted.web.util.Redirect が用意されていますが、恒久的なリダイレクト(301 Moved Permanently)用のリソースがありません。ホスト名の変更などで恒久的リダイレクトを実行したいときはクラスを作成する必要があります。 以下は example.com へのアクセスをすべて http://www.example.com/ へリダイレクトする例です。
# 恒久的なリダイレクトの実行
# redirect.tac from nevow import appserver, static, vhost from twisted.web import error, twcgi, util from twisted.application import service, internet from twisted.web.http import MOVED_PERMANENTLY PORT = 80 TIMEOUT = 300 UID = 33 GID = 33 LOGPATH = '/var/log/www/access.log' # www.example.com 用の設定 DOCUMENT_ROOT = '/var/www/www.example.com/html' CGI_DIR = '/var/www/www.example.com/cgi-bin' class FileWithoutListing(static.File): """ファイル一覧を表示しないリソース""" def directoryListing(self): return error.ForbiddenResource() class MovedPermanently(util.Redirect): """恒久的リダイレクト(301 Moved Permanently)用リソース""" def render(self, request): request.setResponseCode(MOVED_PERMANENTLY) request.setHeader('location', self.url) return = """ <html> <head><title>301 Moved Permanently</title></head> <body> <h1>301 Moved Permanently</h1> <p>The object has moved to <a href="%s">%s</a>.</p> </body> </html> """ % (self.url, self.url) root = vhost.NameVirtualHost(listHosts=False) # www.example.com resrc = FileWithoutListing(DOCUMENT_ROOT) cgiResrc = twcgi.CGIDirectory(CGI_DIR) resrc.putChild('cgi-bin', cgiResrc) root.addHost('www.example.com', resrc) # example.com へのアクセスは www.example.com へリダイレクト root.addHost('example.com', MovedPermanently('http://www.example.com/')) site = appserver.NevowSite(root, logPath=LOGPATH, timeout=TIMEOUT) server = internet.TCPServer(PORT, site) application = service.Application('my_httpd', uid=UID, gid=GID) server.setServiceParent(application) IPアドレスベースのバーチャルホスト各バーチャルホストにそれぞれ独自の IP アドレスを割り当てる場合は、それぞれ独立したサービスオブジェクトを作成して、アプリケーションオブジェクトに登録します。各ホストがリッスンする IP アドレスは twisted.application.internet.TCPServer の interface オプションで指定します。 下記は2つのアドレス192.168.1.1と192.168.1.2をそれぞれ別のホスト設定で使用する例です。
# IP アドレスベースのバーチャルホスト
# multihost.tac from nevow import appserver, static from twisted.web import error, twcgi from twisted.application import service, internet # 各バーチャルホストに共通の設定 PORT = 80 TIMEOUT = 300 UID = 33 GID = 33 # バーチャルホスト毎の設定 config = ( ( # 192.168.1.1用の設定 '192.168.1.1', # 使用 IP アドレス '/var/www/www.example.com/html', # HTML 用ディレクトリ '/var/www/www.example.com/cgi-bin', # CGI 用ディレクトリ '/var/log/www/www.example.com.log', # アクセスログ ), ( # 192.168.1.2用の設定 '192.168.1.2', '/var/www/www.example.org/html', '/var/www/www.example.org/cgi-bin', '/var/log/www/www.example.org.log', ), ) class FileWithoutListing(static.File): """ファイル一覧を表示しないリソース""" def directoryListing(self): return error.ForbiddenResource() application = service.Application('my_httpd', uid=UID, gid=GID) for address, htmlDir, cgiDir, logPath in config: resrc = FileWithoutListing(htmlDir) cgiResrc = twcgi.CGIDirectory(cgiDir) resrc.putChild('cgi-bin', cgiResrc) site = appserver.NevowSite(resrc, logPath=logPath, timeout=TIMEOUT) server = internet.TCPServer(PORT, site, interface=address) server.setServiceParent(application) SSL を使ういよいよ SSL 対応のサーバを書きます。 pyOpenSSL をあらかじめインストールしておいてください。暗号化通信のややこしいところは pyOpenSSL (と OpenSSL)におまかせなので、特に難しいことはありません。 SSL 通信用のサービスオブジェクトを作成するときは twisted.application.internet.TCPServer ではなく twisted.application.internet.SSLServer を使います。またオブジェクト作成時の引数に SSL コンテクストを生成するファクトリオブジェクトを渡してやる必要があります。SSL コンテクストファクトリのクラスは twisted.internet.ssl.DefaultOpenSSLContextFactory として用意されています。 サーバ証明書と秘密鍵ファイルは Apache の mod_ssl で使用する場合と同じ PEM 形式のものを用意します。以下はポート80番で通常の Web サーバ、443番で SSL サーバを動かす場合の例です。どちらも配信するコンテンツ内容は基本的に同じですが、 http://hostname/secure/ だけは SSL を使わなければアクセスできないようにしています。
# SSL サーバの設定例
# sslserv.tac from nevow import appserver, static from twisted.web import error, twcgi from twisted.application import service, internet from twisted.internet import ssl DOCUMENT_ROOT = '/var/www/html' CGI_DIR = '/var/www/cgi-bin' PORT = 80 LOGPATH = '/var/log/www/access.log' TIMEOUT = 300 UID = 33 GID = 33 SSL_PORT = 443 SSL_LOGPATH = '/var/log/www/ssl.log' SECURE_DOCUMENT = '/var/www/secure' # SSL 専用コンテンツ CERT_FILE = '/var/www/ssl/server.crt' # サーバ証明書 KEY_FILE = '/var/www/ssl/server.key' # 秘密鍵 class FileWithoutListing(static.File): """ファイル一覧を表示しないリソース""" def directoryListing(self): return error.ForbiddenResource() application = service.Application('my_httpd', uid=UID, gid=GID) # 通常の Web サーバ resrc = FileWithoutListing(DOCUMENT_ROOT) cgiResrc = twcgi.CGIDirectory(CGI_DIR) resrc.putChild('cgi-bin', cgiResrc) site = appserver.NevowSite(resrc, logPath=LOGPATH, timeout=TIMEOUT) server = internet.TCPServer(PORT, site) server.setServiceParent(application) # SSL サーバ resrc2 = FileWithoutListing(DOCUMENT_ROOT) cgiResrc2 = twcgi.CGIDirectory(CGI_DIR) secureResrc = FileWithoutListing(SECURE_DOCUMENT) resrc2.putChild('cgi-bin', cgiResrc2) resrc2.putChild('secure', secureResrc) # SSL を通じてのみアクセス可 site2 = appserver.NevowSite(resrc2, logPath=SSL_LOGPATH, timeout=TIMEOUT) # SSL サーバ用のサービス登録 sslCtx = ssl.DefaultOpenSSLContextFactory(KEY_FILE, CERT_FILE) sslServer = internet.SSLServer(SSL_PORT, site2, sslCtx) sslServer.setServiceParent(application) MIME タイプのカスタマイズスタテッィクファイルの配信で用いる MIME タイプの定義は /etc/mime.types から読み込むようになっています。定義内容は拡張子をキーに持つ辞書として nevow.static.File の contentTypes にセットされます。定義をカスタマイズしたい場合は、インスタンス作成後に辞書を更新します。
>>> from nevow import static
>>> resrc = static.File('/var/www/html')
>>> type(resrc.contentTypes)
<type 'dict'>
>>> resrc.contentTypes['.swf']
'application/x-shockwave-flash'
>>> resrc.contentTypes['.bz2']
Traceback (most recent call last):
File "<stdin>", line 1, in ?
KeyError: '.bz2'
>>> resrc.contentTypes['.bz2'] = 'application/x-bzip2'
/etc/mime.types 以外のファイルを使いたいときは 関数 nevow.static.loadMimeTypes() を使って読み込みます。オプション引数 mimetype_locations にはパス名のリスト(またはタプル)を指定します。 >>> mimetypes = ['/var/www/etc/mime.types'] >>> resrc.contentTypes = static.loadMimeTypes(mimetype_locations=mimetypes) (つづく) 最終更新 2007-03-12 20:37:36 |
Python と Twisted、それに Nevow を使った Web サーバの書き方
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
© 2007-2010, Yasushi Iwata