So I've moved my stuff over to Rackspace and have pulled Apache out of the mix. I'm now running Django behind Nginx and uWSGI in a virtualenv with Supervisor. It was more work than I expected and most of the instructions out there I didn't find to be very helpful because they expect you to be setting things up exactly how the author of those instructions does it, so here's my own little bit of info on how to do this. I run Debian, so the specifics I provide here will be for Debian (and Ubuntu and I'd guess Mint). I'm going to make the assumption that there's already a working Django app which may or may not be running in a virtualenv in some manner already.

First install virtualenv if you don't already have it and create your virtual environment. Virtualenv lets you package specific versions of libs for one specific app your are using and not affect anything else. I suggest getting this set up first because I recommend using it later to install uWSGI into. You may want to tack the --no-site-packages flag as well so that packages which were installed by your distro don't get shoved into the virtual environment to cause conflicts.

# Create the virtual env
me@blargh:~$ virtualenv ~/virtualenv/myblog/

Then install Nginx and uWSGI. I used the nginx-full package from Debian backports. For uWSGI I again took a different route than every other how-to I've seen on this subject. Rather than downloading and building the source, I just used pip to install uWSGI into my virtual environment.

me@Blargh:~$ ~/virtualenv/myblog/bin/activate
(myblog) me@Blargh:~$ pip install uwsgi

Now install supervisord and then it's time to start on the configurations. Let's start with the wsgi file that uWSGI needs to run the Django app. This makes the most sense to put in the root of your project where settings.py (and manage.py prior to Django 1.4) lives or in a subdirectory of that. I've got mine in a ./wsgi/ subdirectory right now. I don't see any real benefit to this, but I guess maybe some people might have multiple files for different setups or perhaps it's useful for a multi-site single Django installation setup. Anyway, name the wsgi file whatever you want... dispatch.py is common. It should look like this inside.

#! /usr/bin/env python
import sys
import os
import django.core.handlers.wsgi
# Since this is one directory lower than settings.py, append the  parent
# which is the main site dir with settings.py to the python path
# This line may not even be necessary
sys.path.append(os.path.dirname(os.path.dirname(file)))
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
application = django.core.handlers.wsgi.WSGIHandler()

Now for supervisord to be able to start up uWSGI which is in a virtualenv you have to be a little tricky. Supervisor is not running in your virtualenv. They best way I found to do this is to create a bash script as shown here and put it somewhere that makes sense. I put mine in my ~/virtualenv/ dir that holds my virtual environments. This script enters the specified virtualenv and then runs whatever command you pass to it. It will be used by supervisord to start up uWSGI.

Now that that's out of the way, it's time to add the supervisord conf. In Debian add a file to /etc/supervisor/conf.d/ called myblog.conf (or whatever you want to call it). The contents of that file should be something like this:

[program:bslive]
command = /home/youruser/virtualenv/supervisord_launcher.sh /home/youruser/virtualenv/myblog/ uwsgi --pp /home/youruser/django/mblog/wsgi/ -H /home/youruser/virtualenv/myblog --module dispatch --socket localhost:10001 --master
directory=/home/youruser/django/myblog
environment=DJANGO_SETTINGS_MODULE='settings'
user=youruser
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor.log
redirect_stderr=true
stopsignal=QUIT

The command = bit is what supervisor will actually run to start up your uWSGI instance. /home/youruser/virtualenv/supervisord_launcher.sh is the script I linked to above which makes the virtualenv magic happen for supervisor. The next part of that is just the path to the virtual env. Then comes the actual uwsgi command line.

The --pp and -H flags are critical. -H sets the $PYTHONHOME environment variable. This should be the root of your virtual environment. Python looks in $PYTHONHOME/lib/ for modules. The --pp flag sets the $PYTHONPATH, which gets looked at after $PYTHONHOME. This should be the directory where your dispatch.py wsgi file lives. The --module flag is the name of your module, so if you called it dispatch.py, then just put dispatch.

Now with that out of the way, restart supervisord and it should start up your uWSGI daemon for nginx to proxy. You can use supervisorctrl to get a shell where you can see the status of everything supervisor is managing.

The last bit is the nginx virtualhost config which is really simple.

server {
        listen 50.56.191.111:80;
        server_name bash-shell.net www.bash-shell.net;

        access_log /var/log/nginx/myblog_access.log;
        error_log /var/log/nginx/myblog_error.log;

        # Set the location to whatever your ADMIN_MEDIA_PREFIX is
        # and the alias to STATIC_ROOT/admin/
        # unless you're on Django 1.4
        location /static/admin/ {
                alias /home/youruser/django/myblog_static/admin/;
                expires 48h;
        }

        # Set the location to whatever your STATIC_URL is
        # and the alias to STATIC_ROOT/
        location /static/ {
                alias /home/justin/django/bslive_static/;
                expires 48h;
        }

        set $home /home/youruser/django/myblog;
        location / {
          # the socket an port your wsgi daemon listens on
          uwsgi_pass 127.0.0.1:10001;
          include uwsgi_params;
          root $home;
        }
}