Django, Apache and FCGI

In Django, lighttpd and FCGI, second take I described a method how to run Django with FCGI behind a lighttpd installation. I did run the Django FCGIs as standalone servers so that you can run them under different users than the webserver. This document will give you the needed information to do the same with Apache 1.3.

Update: I maintain my descriptions now in my trac system. See the Apache+FCGI description for Django.

Update: I changed from using unix sockets to using tcp sockets in the description. The reason is that unix sockets need write access from both processes - webserver and FCGI server - and that's a bit hard to setup right, sometimes. tcp sockets are only a tad bit slower but much easier to set up.

First the main question some might ask: why Apache 1.3? The answer is simple: many people still have Apache 1.3 running as their main server and can't easily upgrade to Apache 2.0 - for example if they run large codebases in modperl or modpython they will run into troubles with migrating because Apache 2.0 will require modperl2 or modpython2 and both are not fully compatible with older versions. And even though lighttpd is a fantastic webserver, if you already run Apache 1.3 there might just not be the need for another webserver.

So what do you need - besides the python and django stuff - for Apache 1.3 with FastCGI? Just the modrewrite module and modfastcgi module installed, that's all. Both should come with your systems distribution. You will still need all the python stuff I listed in the lighttpd article.

mod_fastcgi is a bit quirky in it's installation, I had to play a bit around with it. There are a few pitfalls I can think of:

  1. the specification of the socket can't be an absolute path but must be a relative path with respect to the FastCgiIpcDir
  2. the specification of the FCGI itself (even though it's purely virtual) must be in a fully qualified form with respect to the document root you want to use. If you use a relative path, it will be relative to the document root of the default virtual host - and that's most surely not the document root you will use if you want to set up a virtual host with the FCGI.
  3. the FCGI itself can't be defined within a virtual host - it must be defined in the main server config. That's where the relative addressing problem comes into play.
  4. the socket file must be both readable and writeable by the FCGI user and the Apache user. Usually you do this by changing the socket file to group writeable and changing the group of that socket file to a group where both the user and the apache are members of.

Now here is the config snippet you have to add to your httpd.conf. I use the same directories as with the lighttpd sample, you most surely will have to adapt that to your situation.

   FastCgiExternalServer /home/gb/work/myproject/publichtml/admin.fcgi -host 127.0.0.1:8000
FastCgiExternalServer /home/gb/work/myproject/publichtml/main.fcgi -host 127.0.0.1:8001

<VirtualHost *> ServerAdmin gb@bofh.ms Servername www.example.com ErrorLog /home/gb/work/myproject/logs/django-error.log CustomLog /home/gb/work/myproject/logs/django-access.log combined DocumentRoot /home/gb/work/myproject/public_html RewriteEngine On RewriteRule ^(/admin/.)$ /admin.fcgi$1 [L] RewriteRule ^(/main/.)$ /main.fcgi$1 [L] </VirtualHost>

You have to allow the webserver write access to the logs directory, so you might want to use a different location for them - possibly in /var/log/apache/ or whereever your apache puts it's logs. The FastCgiExternalServer directives must be outside of the virtual host definitions, but must point to files within the virtual hosts document root. But those files needn't (and probably shouldn't) exist in the filesystem, they are purely virtual. The given setup reflects the setup I did for the lighttpd scenario.

Now restart your apache, start your django-fcgi.py and you should be able to access your django application. Keep in mind to copy the admin_media files over to the document root, otherwise your admin will look very ugly.

django-fcgi.py --settings=myproject.settings.main --host=127.0.0.1 --port=8000 --daemon
django-fcgi.py --settings=myproject.settings.admin --host=127.0.0.1 --port=8001 --daemon

Have fun.

tags: Apache, Django, Sysadmin

JFM Aug. 5, 2005, 10:17 p.m.

Hi. It's not actually necessary to run the Django fcgi apps as separate servers in order for them to run as a separate user from the webserver. You can run them as "dynamic servers", and use the SuExec wrapper. The fcgi servers will be started as needed.

hugo Aug. 5, 2005, 10:56 p.m.

Sure, but then suexec needs to start with root rights. Not nice. I don't like suid software - if it can be avoided, it's much better to avoid it. And in the case of FCGI it's absolutely possible to avoid it. And suexec is a bit of a pain in multi-domain setups and shared setups.

Loevborg Sept. 4, 2005, 11:21 p.m.

At least with the versions of apache2 and mod_fastcgi included in debian sarge, using FastCgiExternalServer and FastCgiServer/FastCgiWrapper simultaneously seems impossible - as soon as FastCgiWrapper is enabled, the virtual external server .fcgi files disappear. I found this out because we use both django and php in a FCGI setup. Maybe it's easier to set up an additional lean web server that hosts django (maybe using twisted.web) and to map it back into the main server url space using mod_proxy.

hugo Sept. 4, 2005, 11:44 p.m.

You can allways just put your FCGIs behind lighttd and map that one into your apache webspace via mod_proxy. I do stuff like that a lot - it's often fast enough for production use as apache with mod_proxy is _very_ fast. And I keep the nice flexibility with regard to logging for apache, and keep a consistent face to the outside - one virtual server merging content from several different machines and services.

florida web design March 22, 2009, 2:48 a.m.

Great article, but one quick thing: the link at the top to the apache/django description is broken. I'm curious to look at that page.

hugo June 20, 2009, 12:08 p.m.

Well, this page is quite outdated by now, so better check the original Django docs to look at how to do FCGI (it's part of the standard distribution now).