The CherryPy wiki has extensive instructions on how to run the CherryPy server (and TurboGears by extension) behind Apache in different setups. By running your TurboGears application behind Apache you can take advantage of Apache’s HTTPS abilities or have it serve your static files.
There are several ways of running CherryPy behind Apache. In the following, we describe how to do this by using Apache as a reverse proxy. In this setup, the CherryPy server does all the heavy lifting, and Apache only forwards requests to your application to CherryPy. This has the advantage that it is very similar to your development setup. On the other hand, the CherryPy server is written in Python and therefore cannot yield the same performance as Apache itself. If performance is important for you, consider running TurboGears behind Apache using WSGI without resorting to the CherryPy server.
In brief, add the following section to your prod.cfg (assuming here you want to make a “real” deployment for production):
base_url_filter.on = False base_url_filter.use_x_forwarded_host = True server.socket_host = "localhost" server.socket_port = 8080
If you set base_url_filter.on = False, you need to make sure that you use the ProxyPassReverse directive in the Apache configuration below. This is necessary so that URLs generated by your application are correctly transformed to use the server name visible to the outside. You can also let CherryPy do this by setting base_url_filter.on = True but this will only work for HTTP servers not for HTTPS.
Here is how to configure Apache 2 as a reverse proxy for your TurboGears application.
In Apache’s httpd.conf uncomment the mod_proxy modules:
LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_connect_module modules/mod_proxy_connect.so LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
Also note, depending on your distribution, you first might need to install the apache-mod_proxy packages.
In the virtual hosts section of the httpd.conf file or in the include file for your virtual host (e.g. httpd-vhosts.conf, but make sure this is loaded), you would want to have something like this for your site (adapt the server name, admin, log locations etc.):
NameVirtualHost * <VirtualHost *> ServerName mytgapp.blabla.com ServerAdmin email@example.com UseCanonicalName Off ServerSignature Off #DocumentRoot /srv/www/vhosts/mytgapp Errorlog /var/log/apache2/mytgapp-error_log Customlog /var/log/apache2/mytgapp-access_log common AddDefaultCharset utf-8 ProxyPreserveHost On ProxyRequests Off ProxyPass /error/ ! ProxyPass /icons/ ! ProxyPass /favicon.ico ! ProxyPass /robots.txt ! #ProxyPass /static/ ! ProxyPass / http://localhost:8080/ ProxyPassReverse / http://localhost:8080/ </VirtualHost>
Uncomment the DocumentRoot and ProxyPass /static/ lines if you want to serve the directory with static content of your TurboGears application directly by Apache. You will then also need to copy or link this directory to the configured DocumentRoot directory.
Check that your Apache configuration has no problems:
If everything is ok, run:
Finally, go to your TurboGears project directory and in a console run:
python start-myproject.py prod.cfg
Now you should be able to see your webpage in full TurboGears glory at the address configured as ServerName above.
To be able to relocate your application without problems, make sure you create your URLs properly (see Using URLs).
The default Genshi templates used by TurboGears specify utf-8 as a charset. The Apache default charset, returned in the Content-Type header, is ISO-8859-1. This inconsistency will cause errors during validation and incorrect rendering of some characters on the client. Therefore we used the AddDefaultCharset utf-8 directive above to override the Apache default in the TurboGears virtual host section.
You can also explicitly set the charset property on a by-method basis by sending the Content-type HTTP header from CherryPy. To do this, you woud add the following line to your controller methods in controllers.py, somewhere before you return the data dictionary:
cherrypy.response.headerMap["Content-Type"] += ";charset=utf-8"
Apache notices the pre-existing header and passes it through.