Erfahrungsbericht - CherryPy und mod_fastcgi (Debian)

Vorwort

Da ich öfter schon gefragt wurde, wie man CherryPy hinter einem Apachen zum Laufen kriegt und meine Standardantwort "mod_fastcgi" ist dachte ich mir, dass es an der Zeit ist diesen Fall genauer zu demonstrieren. :-)

Als Server setze ich "Debian Etch Gnu/Linux" ein. Das Beispiel ist also genau auf diesen Server zugeschnitten.

Auf dem Server ist als Standardencoding "iso-8859-15" eingestellt. Das kann man mit dem Befehl locale nachprüfen. Deshalb verwende ich auch "iso-8859-15" als Encoding für die Python-Module. Wenn das bei dir anders ist, dann musst du die Encoding-Cookies dementsprechend umstellen.

Einfache Beispielanwendung

Um das Ganze so einfach wie möglich zu halten, habe ich mich für eine kleine Beispielanwendung entschieden, die bei Erfolg "Hallo Apache!" ausgibt. Diese Anwendung würde auch ohne mod_fastcgi funktionieren. Das ist wichtig, dass man die Anwendung testen kann. Und Nein, diese Anwendung läuft nicht in der IDE Idle. :-)

Das Basisprogramm

Das Basisprogramm sieht so aus und wird im Ordner /home/gerold/cpexample unter dem Namen cpexample.py abgelegt:

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
# cpexample.py
"""
Einfache Beispielanwendung

Requirements
    - Python: http://www.python.org/
    - CherryPy: http://cherrypy.org/
"""

import os
import cherrypy

APPDIR = os.path.dirname(os.path.abspath(__file__))
INI_FILENAME = os.path.join(APPDIR, "cpexample.ini")


class Root(object):

    def index(self):
        return "Hallo Apache!"
    index.exposed = True


def main():
    app = cherrypy.tree.mount(Root(), config = INI_FILENAME)
    cherrypy.quickstart(app)


if __name__ == "__main__":
    main()

Dieses Beispiel ist, so wie es hier steht, als Anwendung lauffähig. Bitte nicht vergessen, die Anwendung mit chmod ug+x cpexample.py ausführbar zu machen.

Die INI-Datei

Die INI-Datei cpexample.ini, die für dieses Beispiel zuständig ist, sieht so aus:

#
# cpexample.ini
#

[/]
tools.trailing_slash.on = True

mod_fastcgi-Handler

Und hier das Programm, das vom Apachen per mod_fastcgi aufgerufen wird. Dieses wird unter dem Namen cpexample.fcgi abgelegt und sieht so aus:

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
# cpexample.fcgi

import cherrypy
import cpexample
from flup.server.fcgi import WSGIServer
import atexit


# Die WSGI-Applikation zusammensetzen
app = cherrypy.tree.mount(cpexample.Root(), config = cpexample.INI_FILENAME)

# Config anpassen (evt. werden INI-Einstellungen überschrieben)
cherrypy.config.update(
    {
        #'environment': 'production',    # damit wirds schneller
        'log.screen': False,             # nicht in den Screen loggen
        'show_tracebacks': False,        # keine Tracebacks im Browser anzeigen
        #'engine.autoreload_on': False,  # damit wird Autoreload verhindert
    }
)

# Wenn mod_fastcgi beendet, dann sollte auch dieses Programm beendet werden
atexit.register(cherrypy.engine.stop)

# Wenn noch nicht gestartet, dann Anwendung starten
if cherrypy.engine.state == 0:
    cherrypy.engine.start(blocking=False)

# Los gehts
WSGIServer(app).run()

Dieses Programm ist so noch nicht lauffähig. Es fehlt noch das Vermittlerprogramm Flup und die Apacheeinstellungen.

Bitte nicht vergessen, auch dieses Programm mit chmod ug+x cpexample.fcgi ausführbar zu machen.

Berechtigungen

Die Rechte für die Dateien müssen natürlich so gesetzt sein, dass der Apache die Dateien lesen kann. Aber darum musst du dich selber kümmern.

Ich habe es mir einfach gemacht. Alle Dateien unterhalb des Ordners /home/gerold/cpexample gehören dem Benutzer "gerold" und der Gruppe "gerold". Und der Apache ist Mitglied der Gruppe "gerold". Das kann man in der Datei /etc/group einstellen. Das sieht bei mir so aus: gerold:x:1000:www-data. www-data ist der Benutzer unter dem der Apache ausgeführt wird.

Macht man das nicht, dann müsste man die Dateien auch für Other lesbar und ausführbar machen.

Ein aktuelles Cherrypy 3.x installieren

CherryPy herunterladen http://www.cherrypy.org/wiki/CherryPyDownload und in einen temporären Ordner entpacken.

Im soeben entpackten Ordner:

aptitude install python-dev
python setup.py install

Das bei Debian Etch mitgelieferte CherryPy ist mir einfach zu alt. Vielleicht ist bei dir ein neueres CherryPy mit dabei.

Dieser Befehl gibt Aufschluss darüber:

aptitude show python-cherrypy

Wenn nicht mindestens CherryPy 3.0 mit dabei ist, dann würde ich NICHT das mitgelieferte CherryPy verwenden, sondern so wie oben gezeigt das neueste CherryPy herunterladen und händisch installieren.

Falls bereits ein älteres CherryPy von Debian Etch installiert wurde, dann würde ich vorher noch dieses ältere CherryPy deinstallieren:

aptitude remove python-cherrypy  # vollständig entfernen: mit purge statt remove

Flup - die Verbindung zwischen WSGI und FastCGI - installieren

Flup herunterladen http://www.saddi.com/software/flup/dist/flup-1.0.tar.gz und in einen temporären Ordner entpacken.

Im soeben entpackten Ordner:

python setup.py install

Das python-flup das bei Debian Etch mit dabei ist, ist mir auch zu alt. Deshalb hier ebenfalls eine händische Installation.

mod_fastcgi - den Vermittler zwischen den Welten - installieren

Hier reicht mir die Version, die bei Debian Etch mit dabei ist. Also genügt ein einfacher Aufruf von aptitude um mod_fastcgi hier zu installieren.

aptitude install libapache2-mod-fastcgi

Jetzt muss fastcgi noch im Apachen aktiviert werden.

mod_fastcgi aktivieren

Es gibt, glaube ich, einen einfachen Befehl, mit dem man so etwas machen kann. Aber der fällt mir jetzt nicht ein. Deshalb mache ich das händisch:

ln -s /etc/apache2/mods-available/fastcgi.conf /etc/apache2/mods-enabled/
ln -s /etc/apache2/mods-available/fastcgi.load /etc/apache2/mods-enabled/

Die Apache-Konfiguration

Ich glaube nicht, dass ich irgendetwas direkt in der apache2.conf ändern musste. Zumindest kann ich mich nicht an eine Änderung erinnern.

Testen eines einfachen virtuellen Hosts

Zuerst mal ein Test ohne CherryPy. Nicht dass wir später einen Fehler in der CherryPy-Konfiguration suchen, obwohl der Apache nicht einmal eine einfache Datei ausliefert.

Dazu erstelle ich den Ordner /home/gerold/mytest. Und in diesen Ordner lege ich eine einfache Textdatei index.html:

Hallo Welt

Und hier die neue Datei für den virtuellen Host /etc/apache2/sites-available/mytest.conf:

#
# mytest.halvar.at:80
#
<VirtualHost 88.198.133.12:80>

    DocumentRoot /home/gerold/mytest

    ServerName mytest.halvar.at
    ServerAdmin <<emailadresse>>

    <Directory "/home/gerold/mytest">
        allow from all
    </Directory>

    HostNameLookups On
    ErrorLog "|/usr/sbin/rotatelogs /home/gerold/log/mytest_error_log.%Y-%m-%d  86400"
    LogLevel warn
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    CustomLog "|/usr/sbin/rotatelogs /home/gerold/log/mytest_access_log.%Y-%m-%d  86400" common

</VirtualHost>

Diese Einstellung muss noch aktiviert werden. Achte darauf, absolute Pfade zu verwenden:

ln -s /etc/apache2/sites-available/mytest.conf /etc/apache2/sites-enabled/

WICHTIG! Für diesen Test muss es die Subdomain mytest.halvar.at natürlich geben. Um so etwas zu testen, kannst du die Domäne vorübergehend auch in deine hosts-Datei schreiben. (Linux: /etc/hosts; Windows: C:\WINDOWS\system32\drivers\etc\hosts)

Weiters sollte der Ordner in den die Log-Dateien geschrieben werden (bei mir /home/gerold/log) ebenfalls bereits existieren und der Apache sollte in diesen Ordner schreiben dürfen.

Nach einem Neustart des Apachen sollte die URL http://mytest.halvar.at erreichbar sein und auch ein "Hallo Welt" ausgeben. Wenn das so läuft, dann können wir uns an die CherryPy-Anwendung machen.

CherryPy über Flup und mod_fastcgi

Und hier die Datei für den virtuellen Host /etc/apache2/sites-available/cpexample.conf:

#
# cpexample.halvar.at:80
#
<VirtualHost 88.198.133.12:80>

    ServerName cpexample.halvar.at
    ServerAdmin <<emailadresse>>

    # FastCGI config
    ScriptAliasMatch (.*$) /home/gerold/cpexample/cpexample.fcgi$1

    HostNameLookups On
    ErrorLog "|/usr/sbin/rotatelogs /home/gerold/log/cpexample_error_log.%Y-%m-%d  86400"
    LogLevel warn
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    CustomLog "|/usr/sbin/rotatelogs /home/gerold/log/cpexample_access_log.%Y-%m-%d  86400" common

</VirtualHost>

Diese Einstellung muss noch aktiviert werden. Achte darauf, absolute Pfade zu verwenden:

ln -s /etc/apache2/sites-available/cpexample.conf /etc/apache2/sites-enabled/

Nicht vergessen: Die Python-Dateien müssen ausführbar sein! Und nach einer Änderung an einem Python-Modul muss der Apache mindestens mit /etc/init.d/apache2 reload neu initialisiert werden. Sollte das nichts nützen, dann muss /etc/init.d/apache2 restart ausgeführt werden.

Die neue CherryPy-Website sollte jetzt über http://cpexample.halvar.at/ erreichbar sein.