CMPT 470, Fall 2012

Deploying Django with FastCGI

This information is provided to help you get (possibly several) Django applications running on your group's web server. The setup I have suggested is Apache 2 with mod_fastcgi. Deploying with mod_wsgi seems to be better supported, but this may work if you're having problems with mod_wsgi.

Installation and Setup

First of course, you need the relevant software installed:

sudo apt-get install apache2-mpm-prefork libapache2-mod-fastcgi python-django python-mysqldb
sudo a2enmod rewrite

If you haven't already, you will need to install the MySQL server as well: sudo apt-get install mysql-server

I'm going to assume a Django project already checked-out in the directory /home/userid/djangoproject/ and that you want to access that project at http://server/mysite/.

In /home/userid/djangoproject, create a directory fastcgi where we will put the code needed to handle the FastCGI requests. In that directory, create a .htaccess:

AddHandler fastcgi-script .fcgi
RewriteEngine On
RewriteBase /mysite
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.fcgi/$1 [QSA,L]

Create a Python program dispatch.fcgi (also in the fastcgi directory) that handles all of the requests using these tools:

#!/usr/bin/env python
import sys, os

# Add a custom Python path.
sys.path.insert(0, "/home/userid")
sys.path.insert(0, "/home/userid/djangoproject")

# Switch to the directory of your project. (Optional.)
# os.chdir("/home/userid/djangoproject")

# Set the DJANGO_SETTINGS_MODULE environment variable.
os.environ['DJANGO_SETTINGS_MODULE'] = "djangoproject.settings"

from django.core.servers.fastcgi import runfastcgi
runfastcgi(daemonize="false")

… and make it executable:

chmod 0755 dispatch.fcgi

To alias this directory to the URL, and start the setup process, edit /etc/apache2/sites-enabled/000-default and at the bottom of the <Virtualhost> section (right before the “</Virtualhost>”), add this:

Alias /mysite "/home/userid/djangoproject/fastcgi"
<Directory /home/userid/djangoproject/fastcgi>
  Options ExecCGI FollowSymLinks
  AllowOverride all
  Allow from all
  Order allow,deny
</Directory>

Restart the Apache server so it recognizes the config changes:

sudo /etc/init.d/apache2 restart

Settings

You will likely have to modify your settings.py file so that your app uses a MySQL database that you create, rather than the SQLite database you are using for development. See the MySQL database instructions for info on creating a database for your app, then do a python manage.py syncdb.

You will also probably have to add the template directory (e.g. /home/userid/djangoproject/templates) to the TEMPLATE_DIRS variable.

Working

You should be able to work on the Django application more-or-less without worrying about the setup.

If you make changes to the database, or code, or otherwise want to restart the FastCGI process, the easiest and most surefire way is to restart Apache entirely:

sudo /etc/init.d/apache2 restart

Redirects and Links

Of course, any links within your system will have to take the new URL into account. For example, a link like this

<a href="/object/edit">

will have to become:

<a href="/mysite/object/edit">

Hopefully, you have used the {%url%} template tag and reverse function to generate all of the URLs in your app. If so, the changes should be automatic.

If you haven't used {%url%} and reverse, the easiest fix might be to go back to your code and use them wherever you need a URL. For example, in the Django tutorial, the index.html template contains this link:

<li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li>

… which will become:

<li><a href="{% url polls.views.detail poll_id=poll.id %}">{{ poll.question }}</a></li>

Static Media

For all but the simplest sites, you will have some static files that accompany the dynamically-generated code (stylesheets, images, Javascript code, etc.). While it's possible to serve these from within Django, that will be much slower than just letting the web server itself send the files as necessary.

These instructions assume that you have a static directory in your Django app. (i.e. djangoproject/static)

In your Apache config, add this line before the Alias line you added above:

Alias /mysite/static "/home/userid/djangoproject/static"

Now, all of the files in that directory should be accessible below http://server/mysite/static. You can then set the MEDIA_URL variable in your settings.py file to '/mysite/static' and include things like this in your templates (if you render with context_instance=RequestContext(request)):

<link rel="stylesheet" href="{{MEDIA_URL}}/style.css" />

You can also configure caching or other HTTP features on your static directory in the Apache configuration file.

Admin Site Media

You may still need the Django admin site when your app is in production. (Or maybe not, but it's possible.) If so, you will find that the stylesheets and other media for the admin side likely aren't being served properly. You can get things working by setting the proper URL prefix in your settings.py:

ADMIN_MEDIA_PREFIX = '/mysite/admin-media/'

In your Apache config, add this line before the Alias line you added above:

Alias /mysite/admin-media "/usr/share/pyshared/django/contrib/admin/media"

How to use Django with FastCGI in the Django docs (especially the shared hosting topic), or Deploying Django in The Django Book.


Copyright © , based on content created by Greg Baker.