18.2. Using mod_rewrite or mod_proxy to Connect to CherryPy
Because we don't have time to cover every possible configuration, we have to content ourselves to showing you how to set TurboGears up behind Apache. If for some reason you have to install behind another server, however, you can find good recipies at turbogears.org, and lots of helpful people on the mailing list.
We chose Apache because it is the most widely used web server in the world, it runs on Linux, Windows, and OSX; and if you are using shared hosting, it's almost certainly what's already installed.
When using mod_rewrite or mod_proxy to forward requests from the Apache front-end server to your TurboGears application, Apache uses the HTTP protocol to talk to CherryPy. Basically, whenever Apache gets a valid request that matches the criteria you set up, Apache forwards the HTTP request that it received from the browser to CherryPy, waits for a response from CherryPy, and then forwards that response right back down to the browser.
This is probably the easiest and most flexible way to run CherryPy behind a web server. The configuration details behind using mod_rewrite or mod_proxy are Apache specific, but this same technique is also likely to be your best choice when using other web servers such as IIS or lighttpd.
18.2.1. Advantages/Drawbacks of Using a Proxy in front of CherryPy
The advantages of this method are as follows:
The drawbacks of this method are as follows:
18.2.2. Configuring Apache with mod_rewrite
Let's assume that your CherryPy process is listening on port 80. All you have to do is tell Apache to forward requests to CherryPy. If you use mod_rewrite, this is done like this:
RewriteEngine on RewriteRule ^(.*) http://127.0.0.1:8000$1 [P]
The equivalent with mod_proxy is this:
ProxyPass / http://localhost:2432/ ProxyPassReverse / http://localhost:2432/
For this to work, you have to make sure that the mod_rewrite or mod_proxy module is loaded (either dynamically, or statically linked when Apache was built). For more details about mod_rewrite or mod_proxy, refer to their documentation:
18.2.3. Configuring Apache to Serve Static Content Directly
Chances are, your web server will be faster than CherryPy for serving static files. So, you should take advantage of this. Fortunately, it is trivial to achieve this with mod_rewrite:
RewriteEngine on RewriteRule ^/static(.*) /home/myuser/static$1 [L] RewriteRule ^(.*) http://127.0.0.1:8000$1 [P]
This way, if you have a static file /home/myuser/static/foo.html, it will be available at http://<domain>/static/foo.html.
18.2.4. Configuring CherryPy to Run Behind a Web Server
CherryPy doesn't really care whether it runs exposed or behind another web server. It works identically in both cases.
However, Apache modifies requests slightly before forwarding them to CherryPy:
The remote IP address is not needed by CherryPy apart from logging purposes, but if you're logging the IP address inside your TurboGears application, make sure you use the X-Forwarded-For header from the request.
However, the Host header is needed when you need to generate "canonical" URLs (that is, URLs that include the full protocol and domain name). You might think that you can just use relative URLs everywhere in your app (such as: /my/url) and then you'll be fine. But this is only half true. Chances are you'll use some redirects (HTTP code 302 or 303) in your application, and the HTTP protocol specifies that you must include the canonical URL when you issue a redirect. And so, you really do need the full host path for your application.
Fortunately, we can use a CherryPy filter to make this easier. CherryPy's base_url_filter has an option to use the X-Forwarded-For value as the base URL, which gets used to generate full (canonical) URLs. All you have to do to get this automagical behavior is to add the following three lines to prod.cfg:
[/] base_url_filter.on = True base_url_filter.use_x_forwarded_host= True
Unfortunately the "X-…" headers are only there if you use Apache 2.0 or later. If you use Apache 1.3, the original Host and IP address are lost. In that case, you can still use base_url_filters, but you have to hard-wire the base URL into base_url_filter like this:
[/] base_url_filter.on = True base_url_filter.base_url = 'http://your.domain.com' base_url_filter. use_x_forwarded_host= False
Of course, you will want to replace your.domain.com with your actual domain! This will set the base_url to a static value, which isn't quite as nice, but, hey, at least it works.
18.2.5. Making Sure That CherryPy Stays Up
When you run CherryPy behind your web server, you're responsible for making sure that your CherryPy server starts up when the machine boots and restarts if it ever crashes. This can be achieved using various techniques:
There are advantages and disadvantages to the three techniques. Unfortunately, lots of shared hosting environments won't let you run cronjobs frequently, and they are very picky about what long running processes they'll allow. So, sometimes you're stuck with the CGI script hack. Lucky for us, it works well and is easy to set up. All you have to do is tell Apache to run a CGI script when an error occurs (along with the other mod_rewrite rules):
RewriteEngine on ErrorDocument 502 /cgi-bin/autostart.cgi RewriteRule ^/cgi-bin/(.*) /home/myuser/autostart.cgi [L] RewriteRule ^/static(.*) /home/myuser/static$1 [L] RewriteRule ^(.*) http://127.0.0.1:8000$1 [P]
The autostart.cgi file can be a simple Python script that starts CherryPy in the background:
#!/usr/local/bin/python print "Content-type: text/html\r\n" print """""<html><head><META HTTP-EQUIV="Refresh" CONTENT="1; URL=/"></ head><body>Restarting site ...<a href="/">click here<a></body></html>""" import os os.setpgid(os.getpid(), 0) os.system('/usr/local/bin/python2.4 cherrypy-site.py &')
We set the group ID of the process to 0. If you don't do that, Apache will kill the CGI process and its children (that is, the CherryPy process) after a while.