Deployment von Django mit Lighttpd

Dienstag, den 18. November 2008

Auf die Frage, wie man einfach und effektiv Django-Anwendungen in die Welt setzt, gibt es da und dort gut Anregungen und Tipps. Hier soll nun einmal das Deployment am schlanken Webserver Lighttpd gezeigt werden. Als Ausgangspunkt betrachten wir eine kleine Anwendung, die während der Entwicklung meist so aufgerufen wurde:

./manage.py runserver

Dabei wird der eingebaute Webserver gestartet, welcher wirklich nur zur Entwicklung genutzt werden sollte. Da des Öfteren die Pfade im produktiven System nicht mit denen des Entwicklungs-Systems übereinstimmen, bekommt man schon die ersten Probleme, denn Pfade müssen immer absolute Pfade angegeben werden. Es empfiehlt sich also, am Anfang der settings.py folgende Eintragung zu ergänzen.

from os import path
PRJ_DIR = path.abspath(path.dirname(__file__))
PRJ_NAME = path.basename(PRJ_DIR)

Wie unschwer zu erkenne ist, trägt PRJ_DIR nun das Arbeitsverzeichnis und PRJ_NAME den Namen des Django-Projektes.

Statische Inhalte wie Stylesheets, Grafiken oder JavaScript-Code wurden zuvor durch django.views.static.serve() bereitgestellt. Damit dies nur während der Entwicklung so ist, sollte man der urls.py folgende Zeilen beifügen:

from django.conf import settings

if settings.DEBUG:
   urlpatterns += patterns('',
      (r'^static/(?P<path>.*)$', 'django.views.static.serve', {
         'document_root': settings.PRJ_DIR+'/static' }
      ),
   )

Ist in der settings.py das Debugging aktiviert, übernimmt Django auch das Ausliefern der statische Inhalte. Zudem machen wir uns PRJ_DIR zu Nutze, um den Pfad zu definieren.

Doch nun zum eigentlichen Kern, dem Servieren mit Lighttpd. Folgende Module werden für unser Beispiel benötigt: mod_fastcgi, mod_rewrite und optional auch mod_compress zur Kompression statischer Inhalte. Pro Django Instanz oder Domain empfiehlt sich folgende Konfiguration:

$HTTP["host"] =~ "^(www.)?your-domain.com" {
   server.document-root = "/var/www/your-domain.com/root"
   accesslog.filename = "/var/www/your-domain.com/access.log"

   fastcgi.server = ( "/django.fcgi" => ( "main" => (
      "socket" => "/var/www/your-domain/django.sock",
      "check-local" => "disable",
      "docroot" => "/",
   ) ) )

   alias.url = (
      "/media/" => "/usr/.../contrib/admin/media/",
      "/static/" => "/path/.../prj/static/",
      "/other/" => "/path/.../whatever/",
    )

   url.rewrite-once = (
      "^(/django\.fcgi.*)$" => "$1",
      "^(/favicon\.ico)$" => "/static$1",
      "^(/(media|static|other).*)$" => "$1",
      "^(/.*)$" => "/django.fcgi$1",
   )
}

Betrachtet man den url.rewrite-once Abschnitt vorerst nicht, werden nur HTTP-Anfrage an /django.fcgi von Django bearbeitet. Anfragen an /media/, /static/ oder /other/ verweisen direkt auf die Pfade im Dateisystem. Mit url.rewrite-once werden nun die URLs intern umgebogen, bevor sie von Django behandelt werden! Überprüfen könnte man das mit folgender view,

from django.http import HttpResponse

def debug(request):
   return HttpResponse(request.path+'\n')

welche wie abgebildet in urls.py eingebunden ist:

urlpatterns = patterns('',
   (r'^debug/$', 'myprj.myapp.debug'),
)

Ein kurzer Versuch bringt zum Vorschein, was Django zu Gesicht bekommt:

$ wget -q -O - "http://yourdomain.com/debug/"
/django.fcgi/debug/

Ergänzt man in settings.py die kaum bekannte Option FORCE_SCRIPT_NAME="" ergibt sich in der Ausgabe: /debug/. Das ist wichtig, da Anwendungen wie django.contrib.admin mit request.path arbeiten.

Ein Shell-Script zum Starten des FastCGI Prozesses ist hier gelistet.

Abschliessend noch ein Wort zum Thema Bandbreite-sparen. Das bereits erwähnte mod_compress von Lighttpd komprimiert nur statische Inhalte! Ein mod_deflate ist zwar auf dem Weg, doch momentan ist das Einbinden der folgende Middleware-Klasse zu bevorzugen:

MIDDLEWARE_CLASSES = (
   'django.middleware.gzip.GZipMiddleware',
   ...
)

Hiermit werden alle Inhalte ab einer Größe von 200 Byte komprimiert, sofern vom Browser unterstützt.

Der Beitrag wurde am 18.11.2008 unter dem Titel “Deployment von Django mit Lighttpd” veröffentlicht. Schlagwörter: