How to use Django with FastCGI, SCGI, or AJPLink to this heading

Although WSGI is the preferred deployment platform for Django, many people use shared hosting, on which protocols such as FastCGI, SCGI or AJP are the only viable options.

Essentially, FastCGI is an efficient way of letting an external application serve pages to a Web server. The Web server delegates the incoming Web requests (via a socket) to FastCGI, which executes the code and passes the response back to the Web server, which, in turn, passes it back to the client’s Web browser.

Like WSGI, FastCGI allows code to stay in memory, allowing requests to be served with no startup time. While e.g. mod_wsgi can either be configured embedded in the Apache Web server process or as a separate daemon process, a FastCGI process never runs inside the Web server process, always in a separate, persistent process.

Prerequisite: flupLink to this heading

Before you can start using FastCGI with Django, you’ll need to install flup, a Python library for dealing with FastCGI. Version 0.5 or newer should work fine.

Starting your FastCGI serverLink to this heading

FastCGI operates on a client-server model, and in most cases you’ll be starting the FastCGI process on your own. Your Web server (be it Apache, lighttpd, or otherwise) only contacts your Django-FastCGI process when the server needs a dynamic page to be loaded. Because the daemon is already running with the code in memory, it’s able to serve the response very quickly.

A Web server can connect to a FastCGI server in one of two ways: It can use either a Unix domain socket (a “named pipe” on Win32 systems), or it can use a TCP socket. What you choose is a manner of preference; a TCP socket is usually easier due to permissions issues.

To start your server, first change into the directory of your project (wherever your manage.py is), and then run the runfcgi command:

Shell
./manage.py runfcgi [options]

If you specify help as the only option after runfcgi, it’ll display a list of all the available options.

You’ll need to specify either a socket, a protocol or both host and port. Then, when you set up your Web server, you’ll just need to point it at the host/port or socket you specified when starting the FastCGI server. See the examples, below.

ProtocolsLink to this heading

Django supports all the protocols that flup does, namely fastcgi, SCGI and AJP1.3 (the Apache JServ Protocol, version 1.3). Select your preferred protocol by using the protocol option with ./manage.py runfcgi – where <protocol_name> may be one of: fcgi (the default), scgi or ajp. For example:

Shell
./manage.py runfcgi protocol=scgi

ExamplesLink to this heading

Running a threaded server on a TCP port:

Shell
./manage.py runfcgi method=threaded host=127.0.0.1 port=3033

Running a preforked server on a Unix domain socket:

Shell
./manage.py runfcgi method=prefork socket=/home/user/mysite.sock pidfile=django.pid

Run without daemonizing (backgrounding) the process (good for debugging):

Shell
./manage.py runfcgi daemonize=false socket=/tmp/mysite.sock maxrequests=1

Stopping the FastCGI daemonLink to this heading

If you have the process running in the foreground, it’s easy enough to stop it: Simply hitting Ctrl-C will stop and quit the FastCGI server. However, when you’re dealing with background processes, you’ll need to resort to the Unix kill command.

If you specify the pidfile option to runfcgi, you can kill the running FastCGI daemon like this:

Shell
kill `cat $PIDFILE`

…where $PIDFILE is the pidfile you specified.

To easily restart your FastCGI daemon on Unix, try this small shell script:

Shell
#!/bin/bash

# Replace these three settings.
PROJDIR="/home/user/myproject"
PIDFILE="$PROJDIR/mysite.pid"
SOCKET="$PROJDIR/mysite.sock"

cd $PROJDIR
if [ -f $PIDFILE ]; then
    kill `cat -- $PIDFILE`
    rm -f -- $PIDFILE
fi

exec /usr/bin/env - \
  PYTHONPATH="../python:.." \
  ./manage.py runfcgi socket=$SOCKET pidfile=$PIDFILE

Apache setupLink to this heading

To use Django with Apache and FastCGI, you’ll need Apache installed and configured, with mod_fastcgi installed and enabled. Consult the Apache documentation for instructions.

Once you’ve got that set up, point Apache at your Django FastCGI instance by editing the httpd.conf (Apache configuration) file. You’ll need to do two things:

  • Use the FastCGIExternalServer directive to specify the location of your FastCGI server.

  • Use mod_rewrite to point URLs at FastCGI as appropriate.

Specifying the location of the FastCGI serverLink to this heading

The FastCGIExternalServer directive tells Apache how to find your FastCGI server. As the FastCGIExternalServer docs explain, you can specify either a socket or a host. Here are examples of both:

Apache
# Connect to FastCGI via a socket / named pipe.
FastCGIExternalServer /home/user/public_html/mysite.fcgi -socket /home/user/mysite.sock

# Connect to FastCGI via a TCP host/port.
FastCGIExternalServer /home/user/public_html/mysite.fcgi -host 127.0.0.1:3033

In either case, the file /home/user/public_html/mysite.fcgi doesn’t actually have to exist. It’s just a URL used by the Web server internally – a hook for signifying which requests at a URL should be handled by FastCGI. (More on this in the next section.)

Using mod_rewrite to point URLs at FastCGILink to this heading

The second step is telling Apache to use FastCGI for URLs that match a certain pattern. To do this, use the mod_rewrite module and rewrite URLs to mysite.fcgi (or whatever you specified in the FastCGIExternalServer directive, as explained in the previous section).

In this example, we tell Apache to use FastCGI to handle any request that doesn’t represent a file on the filesystem and doesn’t start with /media/. This is probably the most common case, if you’re using Django’s admin site:

Apache
<VirtualHost 12.34.56.78>
  ServerName example.com
  DocumentRoot /home/user/public_html
  Alias /media /home/user/python/django/contrib/admin/media
  RewriteEngine On
  RewriteRule ^/(media.*)$ /$1 [QSA,L,PT]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L]
</VirtualHost>

Django will automatically use the pre-rewrite version of the URL when constructing URLs with the {% url %} template tag (and similar methods).

Using mod_fcgid as alternative to mod_fastcgiLink to this heading

Another way to serve applications through FastCGI is by using Apache’s mod_fcgid module. Compared to mod_fastcgi mod_fcgid handles FastCGI applications differently in that it manages the spawning of worker processes by itself and doesn’t offer something like FastCGIExternalServer. This means that the configuration looks slightly different.

In effect, you have to go the way of adding a script handler similar to what is described later on regarding running Django in a shared-hosting environment. For further details please refer to the mod_fcgid reference

lighttpd setupLink to this heading

lighttpd is a lightweight Web server commonly used for serving static files. It supports FastCGI natively and, thus, is a good choice for serving both static and dynamic pages, if your site doesn’t have any Apache-specific needs.

Make sure mod_fastcgi is in your modules list, somewhere after mod_rewrite and mod_access, but not after mod_accesslog. You’ll probably want mod_alias as well, for serving admin media.

Add the following to your lighttpd config file:

Lua
server.document-root = "/home/user/public_html"
fastcgi.server = (
    "/mysite.fcgi" => (
        "main" => (
            # Use host / port instead of socket for TCP fastcgi
            # "host" => "127.0.0.1",
            # "port" => 3033,
            "socket" => "/home/user/mysite.sock",
            "check-local" => "disable",
        )
    ),
)
alias.url = (
    "/media" => "/home/user/django/contrib/admin/media/",
)

url.rewrite-once = (
    "^(/media.*)$" => "$1",
    "^/favicon\.ico$" => "/media/favicon.ico",
    "^(/.*)$" => "/mysite.fcgi$1",
)

Running multiple Django sites on one lighttpdLink to this heading

lighttpd lets you use “conditional configuration” to allow configuration to be customized per host. To specify multiple FastCGI sites, just add a conditional block around your FastCGI config for each site:

Shell
# If the hostname is 'www.example1.com'...
$HTTP["host"] == "www.example1.com" {
    server.document-root = "/foo/site1"
    fastcgi.server = (
       ...
    )
    ...
}

# If the hostname is 'www.example2.com'...
$HTTP["host"] == "www.example2.com" {
    server.document-root = "/foo/site2"
    fastcgi.server = (
       ...
    )
    ...
}

You can also run multiple Django installations on the same site simply by specifying multiple entries in the fastcgi.server directive. Add one FastCGI host for each.

Cherokee setupLink to this heading

Cherokee is a very fast, flexible and easy to configure Web Server. It supports the widespread technologies nowadays: FastCGI, SCGI, PHP, CGI, SSI, TLS and SSL encrypted connections, Virtual hosts, Authentication, on the fly encoding, Load Balancing, Apache compatible log files, Data Base Balancer, Reverse HTTP Proxy and much more.

The Cherokee project provides a documentation to setting up Django with Cherokee.

Running Django on a shared-hosting provider with ApacheLink to this heading

Many shared-hosting providers don’t allow you to run your own server daemons or edit the httpd.conf file. In these cases, it’s still possible to run Django using Web server-spawned processes.

In your Web root directory, add this to a file named .htaccess:

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

Then, create a small script that tells Apache how to spawn your FastCGI program. Create a file mysite.fcgi and place it in your Web directory, and be sure to make it executable:

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

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

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

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

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

This works if your server uses mod_fastcgi. If, on the other hand, you are using mod_fcgid the setup is mostly the same except for a slight change in the .htaccess file. Instead of adding a fastcgi-script handler, you have to add a fcgid-handler:

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

Restarting the spawned serverLink to this heading

If you change any Python code on your site, you’ll need to tell FastCGI the code has changed. But there’s no need to restart Apache in this case. Rather, just reupload mysite.fcgi, or edit the file, so that the timestamp on the file will change. When Apache sees the file has been updated, it will restart your Django application for you.

If you have access to a command shell on a Unix system, you can accomplish this easily by using the touch command:

Shell
touch mysite.fcgi

Serving admin media filesLink to this heading

Regardless of the server and configuration you eventually decide to use, you will also need to give some thought to how to serve the admin media files. The advice given in the mod_wsgi documentation is also applicable in the setups detailed above.

Forcing the URL prefix to a particular valueLink to this heading

Because many of these fastcgi-based solutions require rewriting the URL at some point inside the Web server, the path information that Django sees may not resemble the original URL that was passed in. This is a problem if the Django application is being served from under a particular prefix and you want your URLs from the {% url %} tag to look like the prefix, rather than the rewritten version, which might contain, for example, mysite.fcgi.

Django makes a good attempt to work out what the real script name prefix should be. In particular, if the Web server sets the SCRIPT_URL (specific to Apache’s mod_rewrite), or REDIRECT_URL (set by a few servers, including Apache + mod_rewrite in some situations), Django will work out the original prefix automatically.

In the cases where Django cannot work out the prefix correctly and where you want the original value to be used in URLs, you can set the FORCE_SCRIPT_NAME setting in your main settings file. This sets the script name uniformly for every URL served via that settings file. Thus you’ll need to use different settings files if you want different sets of URLs to have different script names in this case, but that is a rare situation.

As an example of how to use it, if your Django configuration is serving all of the URLs under '/' and you wanted to use this setting, you would set FORCE_SCRIPT_NAME = '' in your settings file.