I've recently been trying to improve my Django setup to make it more stable and easier to maintain. Part of this has been experimenting with protocols and modules for Django to interface with Apache.

For awhile I've been running Django using FastCGI with Apache's mod_fastcgi. There are several good things about using mod_fastcgi and one annoying disadvantage. What I really like is how easy it is to go this route while using virtualenv. You just activate your virtualenv and then start up the Django FastCGI server with manage.py runfcgi port=<yourport> pidfile=django.pid and away you go (after proper configuration of Apache, of course). FastCGI is also basically a built in app server and you can start them up on as many remote servers as you want with Apache on the front end to handle the connections. As an additional advantage, you can easily switch the Apache front end out for a different HTTPD like Nginx. I have one site running this way but with Nginx up front and it has the same strengths and weaknesses (only considering the strengths/weaknesses of FastCGI not, Nginx and Apache themselves).

The main disadvantage, in my opinion, is that you have to remember to manually start up the Django FastCGI processes. If your server gets rebooted (such as a dedicated server rented from a data center) and you're not around, then your site is down until you can start those processes up. The most common solution to this is using supervisord to keep the FastCGI daemons running. I tried this out and initially it seemed like a nice idea, and it did work for starting the processes. The way I found to make it work was to create a shell script which invokes the virtualenv and then starts the daemon. Supervisord is then configured to run the shell script. Unfortunately this keeps supervisord from killing the daemons when you need to restart them.

Given the issues above I decided to try out mod_wsgi, which is the recommended way of running Django apps, anyway. When using mod_wsgi you create a short loader script and point mod_wsgi at it. After that Apache manages it. You can even run it in a daemon mode which can run as a user other than the user Apache runs as and even in daemon mode, Apache ensures they are running. If Apache is up, your site is accessible.

The cons for mod_wsgi mostly come when using virtualenv. To get Django to run in the virtualenv you have a few choices. In your Apache config you can specify a virtualenv, but this is a server wide setting, so different sites all running Django have to be started from that same virtualenv (more on this issue shortly). You can also have your launcher script initialize the virtualenv. With this second option you are starting with the system python binary and modules rather than the ones in your virtualenv. If you have different versions of the same modules installed in your system $PYTHONPATH and in your virtualenv you run into conflicts because the virtualenv's modules are later in the path than the system modules. To resolve this you can re-order sys.path either manually or with activate_this.py, but that also has risks because the libs you started executing the system with are no longer what are being called for newer calls that use those modules. A smaller annoyance is that if you're mounting your WSGIScriptAlias at / then it conflics with mod_userdir and will override it. I did read about a work around using mod_rewrite to get the wsgi script to run, but I didn't want to mess with it.

The solution I've gone with for now to use mod_wsgi with virtualenv is the create a bare virtualenv with no modules other than the defaults installed created with the --no-site-packages flag. I use the WSGIPythonHome parameter to point at that bare virtualenv. Then my loader script that WSGIScriptAlias points at uses site.addsitedir() to pull in the modules for the site's real virtualenv.

When I have some more time I hope to set up a site to use mod_fcgid on Apache and uWSGI on Nginx so that I can compare the strengths and weaknesses of those to make my final decision on how I'd like to run my sites.