PHP-Installationen im Vergleich
Artikel erschienen in Swiss IT Magazine 2004/09
Scriptsprachen lassen sich auf vielerlei Arten mit dem HTTP-Server verbinden. Wie immer erhöht sich dabei mit der Komplexität der Installation auch die Zahl der zusätzlichen Aspekte, die man bedenken muss. In Bezug auf Webserver und Scriptsprachen gibt es drei wichtige Punkte, die miteinander vereinbart werden müssen: Geschwindigkeit, Sicherheit und Funktionalität. Während vor allem in Bezug auf Perl und das Apache-Modul mod_perl unzählige Artikel und Dokumente zur sicheren und performanten Installation verfügbar sind, wird PHP diesbezüglich ziemlich stiefmütterlich behandelt, auch wenn es zu einer der beliebtesten Scriptsprache im Web mit mehreren Millionen Installationen aufgestiegen ist. InfoWeek hat die Motorhaube geöffnet und die verschiedenen Anbindungsmethoden von PHP miteinander verglichen.
Für den mit knapp 70 Prozent Marktanteil verbreitetsten HTTP-Server Apache existieren grundsätzlich zwei verschiedene Anbindungsmethoden für PHP: Über das CGI (Common Gateway Interface) oder als Apache-Modul. Sowohl für die PHP-Entwickler als für die meisten Benutzer gilt das Apache-Modul (mod_php) dabei als "the way to go", die CGI-Variante wird als Notgroschen für minderbemittelte Webserver betrachtet. Auf den ersten Blick mag man diese Betrachtung sogar einigermassen teilen. Durch die Integration in Apache ist mod_php massiv schneller als die CGI-Variante, die komplette Funktionalität steht zur Verfügung und die Konfiguration ist dank APXS-Support trivial. Kein Wunder findet man auf den meisten Servern das PHP-Modul. Leider hat aber die Integration in den HTTP-Server Folgen in Bezug auf Sicherheit und Lastverhalten.
Durch die direkte Integration in Apache läuft PHP innerhalb des Apache-Prozesses. Dies hat zur Folge, dass es auch unter demselben Benutzer und derselben Gruppe agiert, beispielsweise nobody:nogroup. Somit hat man mit der Scriptsprache auf dieselben Bereiche Zugriff wie der HTTP-Server. Was auf den ersten Blick als unkritisch und gewollt erscheint, beispielsweise bei der Invokation von externen Programmen, kann bei grösseren Setups und mehreren Virtual Hosts unangenehm werden. So lässt sich problemlos von einem Virtual Host heraus auf einen anderen zugreifen. Das kann vom einfachen Lesen bis hin zur Modifikation oder Löschung der Daten gehen. Zwar lässt sich dies mit den PHP-Konfigurationsoptionen safe_mode und open_basedir einigermassen einschränken, leider verstossen diese beiden Optionen gegen grundlegende Regeln des Systemdesigns, indem man versucht, Sicherheit auf Applikationsebene zu erreichen, was auch entsprechende Folgen hat. So sind beide Sicherheitsfunktionen einerseits teilweise zu restriktiv und andererseits immer wieder defekt.
Ein weiteres Problem von mod_php ist das Lastverhalten. Der Master-Prozess des Apache Webservers (in der Version 1.x und 2.x in der Prefork-Ausführung) erzeugt zur Beantwortung der Requests mehrere Child-Prozesse, die für eine gewisse Anzahl von Requests am Leben bleiben. Dies hat unter anderem den Vorteil, dass bei einem Absturz eines Prozesses die anderen Prozesse nicht mit in den Orkus gerissen werden, allerdings auch den Nachteil, dass in jeden Prozess sämtliche Module eingelesen werden müssen, also auch PHP inklusive aller einkompilierten Extensions. Dadurch dauert das Starten eines Prozesses ungleich länger und der RAM-Verbrauch steigt bei einer höheren Anzahl von Apache-Prozessen exponentiell, selbst dann, wenn nur statische Dokumente oder Bilder ausgeliefert werden müssen. Um dieses Problem mindestens teilweise zu umschiffen, werden oft statische Dokumente und Bilder auf einem zweiten Server abgelegt, dessen HTTP-Server ohne irgendwelche Module daherkommt.
PHP als CGI löst immerhin das Sicherheitsproblem. Die Ausführung der PHP-Binaries lässt sich mit dem Suexec-Wrapper ahnlich wie bei mod_perl kontrollieren. Damit werden die PHP-Scripts nicht mehr unter der UID und GID des Webservers sondern des jeweiligen Benutzers ausgeführt. Auch lässt sich der Zugriff auf den Verzeichnisbaum kontrollieren. Die Konfiguration ist leider nicht ganz einfach, so wird ein PHP-Wrapper (mod_cgiwrap o.ä.) benötigt, damit man das PHP-Binary nicht unterhalb des Apache-Document-Roots ablegen (Sicherheitsrisiko) oder per Shebang-Zeile (#! /usr/local/php/ bin/php) aufrufen muss.
Eine Alternative ist mod_suphp, ein Modul, das sich ähnlich wie mod_php über APXS in den HTTP-Server einhängt und dann selber das PHP-Binary aufruft. Dies macht zwar die Konfiguration leichter und benötigt kein Suexec, leider ist eine Limitierung auf bestimmte Verzeichnisbäume nicht möglich. Dies ist nicht wirklich erwünscht, da so die Anwender ebenfalls durchs Dateisystem surfen können.
Bezüglich Geschwindigkeit sieht es bei der CGI-Variante schlechter als beim Modul aus. Da für jeden Request und nicht für jeden Prozess eine neue Instanz des PHP-Interpreters geladen werden muss, steigt die Workload noch weiter an und die Anzahl Requests pro Sekunde, welcher der Webserver beantworten kann, sinkt entsprechend.
Wie der Name schon sagt, möchte FastCGI die Ausführung von Software über das CGI beschleunigen. Dabei wird anstatt der Scriptsprache mod_fastcgi in den Webserver geladen, das dann nachher die Verbindungsbrücke zur Scriptsprache darstellt und das Prozessmanagement übernimmt. Die Funktionsweise erinnert dabei ein wenig an das Prinzip der Applikationserver. FastCGI startet bei der Initialisierung des Webservers eine vorbestimmte Anzahl von PHP-Prozessen, die dann im RAM gehalten werden und an die der Code durchgereicht wird, wenn ein PHP-Script ausgeführt werden muss. Ist das Script ausgeführt, verbleibt der PHP-Prozess im RAM und wartet auf den nächsten Request, bis das Ende seiner Lebenszeit erreicht ist und ein neuer PHP-Prozess gestartet wird. Auf diese Weise wird die Workload viel kleiner gehalten, da nicht für jeden Request ein neuer PHP-Prozess gestartet werden muss und der HTTP-Server vom Ballast befreit wurde. So können statische Dokumente und Bilder massiv schneller ausgeliefert werden und das Lastverhalten verbessert sich.
Auch lässt sich mit Hilfe von FastCGI die Ausführung der PHP-Scripts auf andere Maschinen verteilen, womit der Webserver nur noch für das Ausliefern der Daten zuständig ist und die Ausführung der Scripts auf speziell dafür eingerichteten Maschinen stattfindet.
Bezüglich der Sicherheit muss man sich bei FastCGI auch kaum Sorgen machen: Mit Hilfe der FastCgiWrapper-Direktive lässt sich die Script-Ausführung mit Suexec kontrollieren.
Modul, CGI und FastCGI im Überblick
Auch wenn der Apache-Webserver in der Version 2 schon vor langer Zeit veröffentlicht wurde, setzen noch die meisten Administratoren auf den alten 1.3.x-Zweig. Dies vor allem deshalb, weil der Anreiz zum Wechsel fehlt. Da die meisten PHP-Extensions nicht Thread-safe sind, kommt der Einsatz von mod_php mit Apache 2 und einem threadenden MPM, das ressourcenschonender und schneller als das alte Prefork-Modell arbeitet, Russischem Roulette sehr nahe.
Möchte man auf mod_php setzen, sollte man entweder bei der alten Version bleiben oder darauf achten, Apache 2 mit dem Prefork-MPM einzusetzen. Bei der Verwendung von PHP über das CGI ist der Einsatz mit einem threadenden Apache, beispielsweise mit dem Worker-MPM, ungefährlich. Vom Einsatz der als Suexec-Ersatz gedachten MPMs wie Perchild oder Metux-MPM muss bislang noch abgeraten werden. Perchild ist auf einigen Plattformen, darunter Linux, sehr instabil und wird nicht mehr weiter gepflegt. Metux-MPM befindet sich momentan noch in der Testphase und ist ebenfalls instabil.