Django FastCGI & Lighttpd Setup

Multiple site setup using FastCGI & lighttpd on Debian.

30th October 2011

/etc/init.d/django

FastCGI init.d script from Django Documentation modified to use named unix sockets for communication, so if 1 django site refuses to start, it won't affect the site mappings in lighttpd.
Initial setup:
  • each django site is a directory in /home/httpd/django
  • /home/httpd/django/run will contain pid files & unix sockets used for lighttpd->django communication
  • in settings.py, add FORCE_SCRIPT_NAME='' needed so auto-generated form links do not point to mysite.fcgi

        #!/bin/bash
        ### BEGIN INIT INFO
        # Provides:          FastCGI servers for Django
        # Required-Start:    networking
        # Required-Stop:     networking
        # Default-Start:     2 3 4 5
        # Default-Stop:      S 0 1 6
        # Short-Description: Start FastCGI servers with Django.
        # Description:       Django, in order to operate with FastCGI, must be started
        #                    in a very specific way with manage.py. This must be done
        #                    for each DJango web server that has to run.

        #### SERVER SPECIFIC CONFIGURATION
        DJANGO_SITES="patter secure" # space-separated list
        SITES_PATH=/home/httpd/django
        RUNFILES_PATH=$SITES_PATH/run
        HOST=127.0.0.1
        RUN_AS=www-data
        FCGI_METHOD=threaded
        #### DO NOT CHANGE ANYTHING AFTER THIS LINE!
        set -e

        PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
        DESC="FastCGI servers"
        NAME=$0
        SCRIPTNAME=/etc/init.d/$NAME

        #
        #       Function that starts the daemon/service.
        #
        d_start()
        {
            # Starting all Django FastCGI processes
            for SITE in $DJANGO_SITES
            do
                echo -n ", $SITE"
                if [ -f $RUNFILES_PATH/$SITE.pid ]; then
                    echo -n " already running"
                else
                    start-stop-daemon --start --quiet \
                               --pidfile $RUNFILES_PATH/$SITE.pid \
                               --chuid $RUN_AS --exec /usr/bin/env -- python \
                                $SITES_PATH/$SITE/manage.py runfcgi \
        		       	socket=$RUNFILES_PATH/$SITE.sock \
        			pidfile=$RUNFILES_PATH/$SITE.pid
                    chmod 400 $RUNFILES_PATH/$SITE.pid
                fi
            done
        }

        #
        #       Function that stops the daemon/service.
        #
        d_stop() {
            # Killing all Django FastCGI processes running
            for SITE in $DJANGO_SITES
            do
                echo -n ", $SITE"
                start-stop-daemon --stop --quiet --pidfile $RUNFILES_PATH/$SITE.pid \
                                  || echo -n " not running"
                if [ -f $RUNFILES_PATH/$SITE.pid ]; then
                   rm $RUNFILES_PATH/$SITE.pid
                fi
            done
        }

        ACTION="$1"
        case "$ACTION" in
            start)
                echo -n "Starting $DESC: $NAME"
                d_start
                echo "."
                ;;

            stop)
               echo -n "Stopping $DESC: $NAME"
                d_stop
                echo "."
                ;;

            restart|force-reload)
                echo -n "Restarting $DESC: $NAME"
                d_stop
                sleep 1
                d_start
                echo "."
                ;;

            *)
                echo "Usage: $NAME {start|stop|restart|force-reload}" >&2
                exit 3
                ;;
        esac

        exit 0
            
        

lighttpd.conf

This should be added to your default lighttpd configuration. This first section applies to all sites, then each django site requires its own configuration section.

            server.modules += (
                "mod_alias",
                "mod_rewrite",
            )

            alias.url += (
                "/static/admin" => "/usr/share/pyshared/django/contrib/admin/media/"
            )

            url.rewrite-once += (
                "^(/static.*)$" => "$1",
                "^(/.*)$" => "/mysite.fcgi$1",
            )
        

Per-site configuration


            $HTTP["host"] =~ "^patter.local" {
                fastcgi.server = (
                    "/mysite.fcgi" => (
                        "main" => (
                            "socket" => "/home/httpd/django/run/patter.sock",
                            "check-local" => "disable",
                        )
                    ),
                )
            }