Running our Django site with mod_wsgi and virtualenv (part 2)

These are the steps remaining from our previous article. In order to complete our desired setup we must configure Apache with mod_wsgi pointing to the new virtual environment.

But before we can even do that, we need to setup mod_wsgi, which in our case will require building it and installing it from source.

Setting up mod_wsgi with our virtual Environment

Detailed explanations for using virtual environments in mod_wsgi can be found here.

Just by reading over a bit, and based on some prior experience (2+ years ago, though), I was expecting this to be the main pain area of the whole process. From the docs I read that mod_wsgi has to be compiled against the same version of Python your code will be running under. Which means I will have to build from source, since Ubuntu 9.04’s version of mod_wsgi is linked with its included version of Python 2.6.

Build mod_wsgi

First, we must build and install mod_wsgi to use the correct version of Python. The installation guide for mod_wsgi is very clear, you just need to follow it. Below are the distilled steps my installation needed.

We start by installing the Apache2 development libraries (which we will need in order to install mod_wsgi), and downloading mod_wsgi from its subversion repository.

sudo apt-get install apache2-dev
svn co mod_wsgi-2.x
cd !$

Then we have to make sure that mod_wsgi will be compiled against our required version of Python (the one we installed with pythonbrew earlier on). If we just run:

$ ./configure
checking for apxs2... /usr/bin/apxs2
checking Apache version... 2.2.14
checking for python... /usr/bin/python
configure: creating ./config.status
config.status: creating Makefile

…from the output of configure we see that something is wrong. The chosen python version is the default one in our Ubuntu in /usr/bin/python, which is not the one we want (that one is 2.6, we want the 2.7 we installed with pythonbrew). We can select the correct version in two different ways, choose whichever one you prefer:

$ ./configure --with-python=/home/isigma/.pythonbrew/pythons/Python-2.7.2/bin/python
checking for apxs2... /usr/bin/apxs2
checking Apache version... 2.2.14
configure: creating ./config.status
config.status: creating Makefile

…or this will also work:

$ pythonbrew use 2.7.2
Using `Python-2.7.2`
$ ./configure 
checking for apxs2... /usr/bin/apxs2
checking Apache version... 2.2.14
checking for python... /home/isigma/.pythonbrew/pythons/Python-2.7.2/bin/python
configure: creating ./config.status
config.status: creating Makefile

After correct configuration we have a proper Makefile, the standard steps follow:

sudo make install

Create the Virtual Environment(s)

Again, you just need to follow the steps clearly described in the mod_wsgi guide. This is a summary of the specific steps I followed.

First I created a baseline virtualenv. I decided to name it baseline27, since it is for python 2.7:

pythonbrew use 2.7.2
mkvirtualenv --no-site-packages baseline27

This virtual environment will be kept clean, we won’t install any additional packages there. Ever.

In our previous article we had already created a virtual environment for our site called fabula. If you haven’t created it yet, do so now following the more detailed instructions there. Or, as a quickie:

pythonbrew use 2.7.2
mkvirtualenv --no-site-packages fabula
cd /your/project/folder
pip install -r requirements.txt

Create a WSGI Script for your Django Application

The mod_wsgi documentation tells you to add a couple lines at the start of your WSGI script such as these:

import site

My Django project is located under /var/django/fabula. This is how my complete WSGI script (/var/django/fabula/config/fabula.wsgi) looks like :

import os
import sys
import site

# set up python path and virtualenv
os.environ['PYTHON_EGG_CACHE'] = '/var/django/cache'

# django WSGI specifics
from django.core.handlers.wsgi import WSGIHandler
os.environ['DJANGO_SETTINGS_MODULE'] = 'sites.fabula.settings'
application = WSGIHandler()

Set up Apache

Add a directive to one of the apache configuration files, so that mod_wsgi can locate the proper python baseline version. This has to be outside any virtual host section. You can put this in /etc/apache2/sites-available/default, /etc/apache2/mods-available/wsgi.conf or another one of your preference:

WSGIPythonHome /home/django/baseline27

This is my setup for mod_wsgi and my Django site (quite standard, from the examples in the Django documentation). All my sites/projects are located under folders in /var/django:

<Directory "/var/django">
  WSGIApplicationGroup %{GLOBAL}
  Order deny,allow
  Allow from all

WSGIDaemonProcess django-fabula threads=5 maximum-requests=20

WSGIScriptAlias /fabula /var/django/fabula/config/fabula.wsgi
<Location "/fabula">
  WSGIProcessGroup django-fabula
  WSGIApplicationGroup %{GLOBAL}
  WSGIPassAuthorization On

Alias /fabula/appmedia /var/django/fabula/sites/fabula/media
Alias /fabula/adminmedia /var/django/adminmedia
<Location "/fabula/appmedia">
    SetHandler none

(Oh BTW the WSGIPassAuthorization directive is unrelated to the example. I need it because my site relies on HTTP Basic Authentication for some operations, and I do not want the authorisation headers removed, which is mod_wsgi’s standard behavior).

We just need to reload Apache, and our Django site will be up and running!

sudo /etc/init.d/apache2 reload

Conclusions, and Where to go Next

The site is now running Python 2.7.2 and Django 1.2.5 as initially planned. After this work, creating an upgrade of our site with a different version of Django or other dependencies, that can run side-by-side with the older version, is going to be much simpler.

The problem that will remain, I guess, is how to deal with different simultaneous Python versions. I’m not sure mod_wsgi will be capable of that, and it may be time to move to a more modern setup (like nginx as a frontend for uWSGI, which is stated to be sysadmin-friendly and seems to do very well in benchmarks).

2 thoughts on “Running our Django site with mod_wsgi and virtualenv (part 2)

  1. Hi,

    while in ‘make’ of mod_wsgi, i’ve come up with the following error:

    /usr/bin/ld: /home/diogo/.pythonbrew/pythons/Python-2.7.2/lib/libpython2.7.a(abstract.o): relocation R_X86_64_32 against `.rodata.str1.8′ can not be used when making a shared object; recompile with -fPIC
    /home/diogo/.pythonbrew/pythons/Python-2.7.2/lib/libpython2.7.a: could not read symbols: Bad value
    collect2: ld returned 1 exit status
    apxs:Error: Command failed with rc=65536
    make: *** [] Error 1

    I can’t seem to solve the problem. Any suggestions?

    • Sorry man, no idea. Check if there’s a mod_wsgi mailing list, they may be able to help.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s