Running TurboGears Behind Apache via WSGI

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 WSGI gateway. In this setup, the CherryPy server will not be running, and Apache communicates directly with your application via the WSGI protocol. This has the advantage that it is very performant. If you want to have a setup that is more like your development setup, consider running TurboGears behind Apache as a reverse proxy to the CherryPy server.

Note that the following documentation assumes you are using TurboGears 1.5.1 and CherryPy 3.2 or newer versions.

Install the mod_wsgi Apache module

In order to use the WSGI protocol, you will need to install the mod_wsgi Apache module. The mod_wsgi Wiki has installation instructions for most platforms.

Precompiled packages are available for many platforms nowadays. For instance, openSUSE comes with the package “apache2-mod_wsgi”.

After installing the mod_wsgi module, you must still enable it. This can be done by adding the following line to your Apache configuration:

LoadModule wsgi_module modules/mod_wsgi.so

Under openSUSE, you can enable the module by running yast sysconfig and addding wsgi to the list of modules that you can find under Network - WWW- Apache2 - APACHE-MODULES.

Create the WSGI script for your application

To access your application via WSGI, you need to create a WSGI script file. We recommed creating a separate directory for your WSGI script files. This directory must be accessible by Apache, but should not be located somewhere below DocumentRoot. A good place would be a sibling directory to an existing cgi-bin directory on your system, or a directory under your TurboGears project directory, but not under the static subdirectory. If you are using a virtual enviroment for your TurboGears project, then a subdirectory of the virtual enviroment directory would also be a good place for the WSGI script file.

In the following we assume your WSGI script file directory is /srv/www/wsgi-scripts. We recommend naming your WSGI script file after your TurboGears application. So if your TurboGears project is called myapp, the WSGI script file would be /srv/www/wsgi-scripts/myapp.wsgi.

To make your WSIG script file usable by Apache, you must add the following configuration lines to your Apache 2 configuration file:

<IfModule mod_wsgi.c>

<Directory /srv/www/wsgi-scripts>
Order allow,deny
Allow from all
</Directory>

WSGIScriptAlias /myapp /srv/www/wsgi-scripts/myapp.wsgi

</IfModule>

Of course, instad of “Allow from all”, you can also apply stricter rules for accessing your WSGI scripts, such as requiring certain IP addresses.

The above configuration assumes that you want your application to appear under the URL prefix /myapp/. In this case, you should also set server.webpath = '/myapp' in your TurboGears configuration file. If you want your application to appear with no URL prefix, then replace /myapp with / in the WSGIScriptAlias directive.

The content of the file /srv/www/wsgi-scripts/myapp.wsgi can be as simple as this:

"""WSGI script for myapp"""

from myapp import command

application = command.start()

Make sure your Apache user has the necessary permission to read this file. For security reasons, you should not make it writable or executable, though.

Choose between “daemon mode” and “embedded mode”

The mod_wsgi module offers two different modes of operation, “daemon mode” and “embedded mode”. In daemon mode, your TurboGears application will run in its own process, separate from the child processes of the Apache web server. In embedded mode, your application will be executed within the context of a normal Apache child process. We recommend using daemon mode, particularly if you use the same Apache webserver for serving other static pages or applications as well, because in daemon mode your application is decoupled from the Apache configuration and can be tuned for performance independently. Note however that under Windows the daemon mode is not available.

If you leave the Apache configuration as above, embedded mode will be used. For using daemon mode, add the following bits to your Apache configuration, right below the WSGIScriptAlias directive:

WSGIProcessGroup myapp

WSGIDaemonProcess myapp processes=1 threads=25 \
                  maximum-requests=10000 \
                  user=myapp group=www \
                  display-name=%{GROUP}

This directive also allows you to run your application under a certain user and group. Choose the user and group to run your application carefully, because it impacts the security of your application. Don’t use a user with high privileges or even the root user here. Make the necessary ressources in your TurboGears project accessible to that user. For most of these you will only need read acces, but some, such as SQLite database files or the directory for storing sessions as files, may need write access as well.

Look into the mod_wsgi documentation for fine-tuning the other arguments of the WSGIDaemonProcess directive and other optional directives.

Adapt your TurboGears Configuration

We assume you want to make a “real” deployment for production. So in your prod.cfg or default.cfg file, set the correct environment:

environment = 'production'

As we do not need and want the CherryPy server to start when running the application via WSGI, we must add the following setting:

engine.start = False

If want to use embedded mode instead of daemon mode (or you must, because you are using a Windows server), then use this configuration setting:

environment = 'embedded'

In this case you don’t need to set engine.start, because TurboGears already assumes you don’t want to start the CherryPy engine in this mode.

Running your application in a virtual environment

If you are running your application in a virtual enviroment, you need to adapt your WSGI script file so that it inserts the paths in the site-packages directory of the virtual enviroment in front of all the other paths in Python’s sys.path. Assuming your virtual environment for Python 2.7 is located at /home/myapp/venv, the WSGI script file should be modified as follows:

"""WSGI script for myapp"""

# Set to the site-packages directory inside your virtualenv
# or set to None if you are not using a virtualenv:
SITEDIR = '/home/myapp/venv/lib/python2.7/site-packages'

if SITEDIR:
    import site, sys
    sys_path = set(sys.path)
    is_sys_path = lambda path: path in sys_path
    site.addsitedir(SITEDIR)
    sys.path.sort(key=is_sys_path)

from myapp import command

application = command.start()

Isolate your application from the global enviroment

Even if you have set up your virtual enviroment with the --no-site-packages option, the global site packages will still be available in your WSGI application unless you use the WSGIPythonHome directive in your Apache configuration. Unfortunately, this directive can only be used in the global Apache server configuration, not inside an individual virtual host or directory context. In order to be able to use as many WSGI applications as you like, isolated from each other and the global Python enviroment, we recommend setting up one empty virtual environment like this:

mkdir -p /usr/local/pythonenv
cd /usr/local/pythonenv
virtualenv --no-site-packages empty

and then using this empty environment as the WSGIPythonHome for all your WSGI applicatons by adding the following to your global Apache configuration:

WSGIPythonHome /usr/local/pythonenv/empty

Servig static pages with Apache

To improve performance even more, you should let Apache serve the static files directly instead of serving them through the WSGI application.

A simple solution is to add a symbolic link to the static directory of your TurboGears project somewhere inside the DocumentRoot of your Apache configuration (you will need to add the FollowSymLinks or SymLinksIfOwnerMatch option setting for that directory, though). Then you can add aliases to your Apache configuration like this:

Alias /myapp/static/ /srv/www/htdocs/myapp/static/
Alias /myapp/robots.txt /srv/www/htdocs/myapp/static/robots.txt
Alias /myapp/favicon.ico /srv/www/htdocs/myapp/static/favicon.ico

Here we assumed again that you want your application to appear under the URL prefix /myapp/. Change the configuration appropriately if you want to use a different prefix or no prefix at all.

Setting the correct charset

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.