Putting Nevow Page under Apache Proxy¶
It is generally not recommended to put the staff that requires many simultaneous connections under apache, unless Event MPM is used. But sometimes that’s just fine, e.g for tests.
This is what you put on apache with mod_proxy enabled:
<VirtualHost *:80> # of course, *:80 can be replaced by something # external site URL ServerName go.site.com # internal (proxied) URL, note vhost/<protocol>/<host>/ scheme (*) ProxyPass / http://localhost:8080/vhost/http/go.site.com/ </VirtualHost>
Usually people also add ‘ProxyRequests Off’ to their apache conf to ensure that apache won’t be used as free proxy.
But it’s clearly not enough to setup apache, because it will send requests to Twisted asking http://localhost:8080/.. , while Nevow application should process request as if it were http://go.site.com.
There is a special module nevow.vhost.VHostMonsterResource() (please note nevow.vhost is used, not twisted.web.vhost), which takes url in the form http://localhost:8080/vhost/http/go.site.com/* and fixes request to make Resource think that it were direct go.site.com/* .
Here is a brief ‘proxy.tac’ example, which can be run by ‘twistd -noy proxy.tac’
from twisted.application import service, strports from nevow import appserver, inevow, rend, loaders, vhost from zope.interface import implements # This is the root resource we are hiding behind proxy # It *was* working as http://localhost:8080, but now it should *become* http://go.site.com class MyResource(rend.Page): def child_(self, ctx): return HelloPage() # A simple root page, *was* http://localhost:8080/, # will *become* http://go.site.com/ # (or http://localhost:8080/vhost/http/go.site.com/ from proxied url) class HelloPage(rend.Page): docFactory = loaders.xmlstr('''\ <html><body>Hello</body></html> ''') # thanks Damascene for this wrapper # it delegates /vhost/* requests to VHostMonsterResource, which fixes request class VhostFakeRoot: ''' I am a wrapper to be used at site root when you want to combine vhost.VHostMonsterResource with nevow.guard. If you are using guard, you will pass me a guard.SessionWrapper resource. Also can hide generic resources ''' implements(inevow.IResource) def __init__(self, wrapped): self.wrapped = wrapped def renderHTTP(self, ctx): return self.wrapped.renderHTTP(ctx) def locateChild(self, ctx, segments): '''Returns a VHostMonster if the first segment is 'vhost'. Otherwise delegates to the wrapped resource.''' if segments == 'vhost': return vhost.VHostMonsterResource(), segments[1:] else: return self.wrapped.locateChild(ctx, segments) # setup/run site site = appserver.NevowSite(VhostFakeRoot(MyResource())) application = service.Application('go') strports.service('8080', site).setServiceParent(application)
How that works ?¶
- Request comes as http://localhost:8080/vhost/http/go.site.com/<**>
- VhostFakeRoot.locateChild is called
- ‘vhost’ is stripped from path and http/go.site.com/* comes to VHostMonsterResource
- http is stripped by VHostMonsterResource, request is fixed
- go.site.com is stripped by VHostMonsterResource, request is fixed
- MyResource comes into play and does its job with <**>
- Headers from Twisted are consumed by apache.. That may be a problem
- Nevow.livePage stuff had problems working through proxy
There’s an alternative (a lot easier method) to achieve the desired result. Just do it in apache config:
<VirtualHost [insert IP or * here]:80> ServerName mysub.mydomain.com ErrorLog /var/log/apache2/mysub.mydomain.com_error_log CustomLog /var/log/apache2/mysub.mydomain.com_access_log combined ProxyVia On ProxyPass / http://127.0.0.1:8080/ ProxyPassReverse / http://127.0.0.1:8080/ </VirtualHost>
Also see Reverse Proxy.