Apache Server mit PHP fcgid (ehemals FastCGI) und Debian (Squeeze, Wheezy, Jessie)

Vorwort

Nach einigen Stunden Zeitinvestition und Tutorials lesen, habe ich es nun endlich geschafft fcgid auf Debian (ursprünglich mal Lenny, nun auch Squeeze, Wheezy oder Jessie) zum Laufen zu bringen. Da dies im Internet bisher nicht dokumentiert ist, fasse ich hier meinen Installationsweg zusammen. Das Tutorial funktioniert uneingeschränkt genauso auf Debian Squeeze oder Wheezy.

Warum sollte ich fcgid benutzen?

Nun warum mache ich das so kompliziert und benutze nicht einfach mod_php, schließlich ist dieses Modul für Apache per Debian Paket in wenigen Sekunden schnell installiert und leicht konfigurierbar? Nun, das mod_php Modul hat einige gravierende Nachteile:

  1. PHP wird unter dem Apache-Benutzer (bei Debian www-data) ausgeführt. Dies führt dazu, dass wenn ein Benutzer ein PHP Skript auf dem Webserver ausführt, dieses unter den Benutzerrechten von www-data ausführt. Dies kann Sicherheitsprobleme mit sich bringen z.B. wenn das PHP-Skript Sicherheitslücken aufweist oder der Benutzer Zugriff auf die Skripte von anderen Webserver-Mitbenutzern erlangt (indem er sie per fopen() als www-data öffnet, auch open_basedir ist für fopen() leider nutzlos).
  2. Wenn der Webserver mit Hilfe von PHP Dateien anlegt, werden diese - logischerweise - ebensfalls unter dem Benutzer www-data angelegt. Dieser ist somit auch der Inhaber der Dateien. Möchte nun der Webmaster per FTP die Dateien mit seinem FTP-Benutzer löschen oder anpassen, hat er keine Zugriffsrechte. Hier wäre es wünschenswert die Skripte im Kontext des FTP-Benutzers auszuführen, damit dieser auch die von seinen Skripten angelegten Dateien wieder löschen kann.
  3. Das Modul mod_php kann nicht mit threadbasierten Apache-MPM worker zusammenarbeiten, sondern muss mit dem langsameren Apache-MPM codefork genutzt werden. Dies verursacht Performanceeinbußen und der größte Vorteil des Apache in Version 2, nämlich das Threading, geht verloren.
  4. Ich kann nur eine globale php.ini Datei verwenden und so für alle Srkipte auf dem Server nur eine Sicherheitsrichtlinie anwenden.
  5. Ich kann nur schwer PHP4 und PHP5 parallel einsetzen.

Genau diese Dinge kann das Modul fcgid mit Hilfe vom Apache-Modul suexec lösen. Es führt PHP-Skripte im Kontext eines vorgegebenen Benutzers aus. Übrigens: fcgid ist eine neu entwickelte Weiterentwicklung des Apache Moduls FastCGI.

Gegenindikatoren: Wann sollte ich fcgid nicht nutzen?

  • Für kleinere Installationen auf die man nur selbst zugreift und die keinen Schreibzugriff (z.B. per FTP) von Dritten erfordern, ist die Installation zu aufwendig.
  • Außerdem kostet das mod_fcgid mehr Arbeitsspeicher, da für jeden Benutzer eine eigene PHP-Umgebung gestartet wird. Sollte man also sehr wenig Arbeitsspeicher zur Verfügung haben, ist von fcgid abzuraten.

Installation

Kommen wir nun zur recht umfangreichen Installation. Ich werde mir Mühe geben, sie möglichst umfangreich zu beschreiben und zu dokumentieren. Um die Anleitung durchzuführen, gebe Codeschrift, die ein Dollar-Zeichen voran gestellt hat, in der Bash als root Benutzer ein.

1. Installation der benötigten Pakete

Zunächst installieren wir die benötigten Pakete mit APT oder aptitude:

$ apt-get install apache2-mpm-worker apache2-suexec php5-cgi libapache2-mod-fcgid

2. Aktivieren der Module

Nun aktivieren wir die beiden benötigten Apache Module:

$ a2enmod fcgid
$ a2enmod suexec

Hinweis: Das Modul fastcgi aus dem Paket libapache2-mod-fastcgi darf nicht installiert sein. Dies ist durch die Verbesserungen in fcgid veraltet.

3. Benutzer anlegen

Lege den Benutzer an, unter dem die PHP Dateien später ausgeführt werden sollen:

$ adduser --disabled-login deinuser
$ adduser www-data deinuser

Der zweite Befehl fügt den Benutzer www-data in die Gruppe Deines Benutzers hinzu, damit der Apache Server später auf die Dateien zugreifen kann.

4. Anlegen einer neuen VirtualHost Datei

Jetzt wird's komplizierter. Zunächst erstellen wir eine neue VirtualHost Datei, wie es bei Apache unter Debian üblich ist, um den Server in verschiedene Websitebereiche zu unterteilen.

$ touch /etc/apache2/sites-available/deinhost.conf

Wir öffnen nun die erstellte VirtualHost Datei mit einem Texteditor:

$ vim /etc/apache2/sites-available/deinhost.conf

Kopiere z.B. den Inhalt einer vorhanden VirtualHost Datei und passe diesen an. Deine VirtualHost Datei sollte in etwa so aussehen. Passe die Schlüsselwörter deinhost und deinuser entsprechend an:

<VirtualHost *:80>
  ServerName deinhost.de
  ServerAdmin webmaster@deinhost.de
 
  DocumentRoot /var/www/deinhost/htdocs
  SuexecUserGroup deinuser deinuser
 
  <Directory /var/www/deinhost/htdocs/>
    FCGIWrapper /var/www/deinhost/conf_deinhost .php
    <FilesMatch \.php$>
      SetHandler fcgid-script
    </FilesMatch>
    Options +ExecCGI
  </Directory>
 
  ErrorLog /var/log/apache2/error.log
  LogLevel warn
  CustomLog /var/log/apache2/access.log combined
 
</VirtualHost>

Ich glaube das benötigt ein bisschen Erklärung. Nun den Aufbau einer allgemeinen VirtualHost Datei möchte ich hier nicht beschreiben. Dies setze ich als bekannt voraus. Nur soviel:

  • Mit DocumentRoot setzen wir unseren Webspace in ein Unterverzeichnis von /var/www
  • SuexecUserGroup legt für das Apache Modul suexec fest, mit welchem Benutzer und Gruppe wir die (PHP-)Skripte aufrufen wollen
  • FCGIWrapper weist das Modul fcgid an, für .php Dateien das angegebene Konfigurationsskript conf_deinhost zu starten. Innerhalb dieses Skriptes starten wir dann später PHP.
  • SetHandler legt die Behandlung für PHP-Dateien fest. Bitte beachtet, dass ich hier FilesMatch benutze, um ein Sicherheitsrisiko in Apache zu umgehen benutze.
  • Die Option ExecCGI unter "Options" erlaubt das Ausführen der PHP Dateien im CGI Modus

Speichere nun die VirtualHost Datei.

5. Erstellen der neuen Verzeichnisse für die VirtualHost Website mit Konfigurationsdatei

Wir erstellen nun ein Verzeichnis welches die gesamte Website und Konfigurationsdaten aufnehmen wird, die wir mit Hilfe der VirtualHost-Datei angelegt haben:

$ mkdir /var/www/deinhost

In dieses Verzeichnis legen wir den Webspace ab:

$ mkdir /var/www/deinhost/htdocs

Wir erstellen auch die von fcgid benötigte Konfigurationsdatei:

$ touch /var/www/deinhost/conf_deinhost

6. Bearbeiten der Konfigurationsdatei für fcgid

Nun müssen wir noch die Konfigurationsdatei für fcgid anpassen:

$ vim /var/www/deinhost/conf_deinhost

Wir fügen den folgenden Inhalt ein:

#!/bin/sh
 export PHPRC="/etc/php5/cgi"
 exec /usr/bin/php5-cgi

Dies sieht etwas verwirrend aus! Was macht diese Datei:

  • PHPRC ist eine Variable, die auf ein Verzeichnis mit einer php.ini Datei zeigen muss. Ich habe hier die Standarddatei aus dem Paket php5-cgi genommen. Du kannst aber auch eine eigene php.ini Datei pro VirtualHost anlegen. Kopiere dazu die Datei /etc/php5/cgi/php.ini nach /var/www/deinhost/php.ini. Im Schritt 8 setzen wir dann aus Sicherheitsgründen auch das immutable Bit auf die php.ini Datei.
  • exec /usr/bin/php5-cgi verweist auf die Binary von php5-cgi also auf das ausführbare PHP Programm und startet somit den Intercodetierprozess der aufgerufenen PHP-Datei.

7. Setzen der Zugriffsregeln auf die VirtualHost Website

Es ist extrem wichtig, dass alle Zugriffsrechte ordnungsgemäß auf das VirtualHost Verzeichnis und seine Unterverzeichnisse gesetzt sind. Dies tun wir mit folgenden Befehlen:

$ chown -R deinuser:deinuser /var/www/deinhost
$ chmod 755 /var/www/deinhost
$ chmod 550 /var/www/deinhost/conf_deinhost
$ chmod 750 /var/www/deinhost/htdocs

Mit folgenden Befehl können wir prüfen, ob die Rechte auf die Ordner/Dateien richtig gesetzt wurden:

$ ls -la /var/www/deinhost
drwxr-xr-x 3 deinuser deinuser 4.0K 2009-11-06 21:58 .
drwxr-xr-x 3 root     root     4.0K 2009-11-06 20:18 ..
-r-xr-x--- 1 deinuser deinuser 62   2009-11-06 21:43 conf_deinhost
drwxr-x--- 2 deinuser deinuser 4.0K 2009-11-06 21:45 htdocs

Hinweise:

  • Entgegen vielen verbreiteten Tutorials müssen die Zugriffsrechte/Besitzer auf /var/www nicht angepasst werden. Dies schafft nur überflüssige Sicherheitsrisiken.
  • Verwendet man chmod -R 777 statt 750 schlägt das Ausführen von suexec fehl. Dies macht suexec um die Dateien vor Manipulation zu schützen.

8. Immutable Bit setzen

Zum Schluss setzen wir das Immutable Bit auf die Konfigurationsdatei. Dadurch wird verhindert, dass selbst der Besitzer (der ja nun der nicht vertrauenswürdige Webmaster ist und sämtliche Rechte auf die Datei hat) die Konfigurationsdatei manipulieren kann. Dies ist EXTREM wichtig durchzuführen:

$ chattr -V +i /var/www/deinhost/conf_deinhost

Hat dies korrekt funktioniert, siehst Du folgende Ausgabe:

chattr 1.41.3 (12-Oct-2008)
Flags von /var/www/deinhost/conf_deinhost wie folgt gesetzt: ----i--------------

Solltest Du auch eine php.ini angelegt haben (siehe 6.), führe den Vorgang auch für diese aus.

9. Die Konfigurationsdatei von mod_fcgid anpassen

Wir rufen nun die Konfigurationsdatei von fcgid auf und setzen einige empfohlene Einstellungen von fcgif:

$ vim /etc/apache2/mods-available/fcgid.conf

Die Konfigurationsdatei sollte wie folgt aussehen:

<IfModule mod_fcgid.c>
  # Wenn dieser Befehl fehlt, werden offene PHP CGI Prozesse nicht richtig beendet
  # Siehe auch: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=398759
  DefaultMinClassProcessCount 0
 
  # Nach Ablauf von n (hier 300) Sekunden wird ein unbeschäftigter PHP CGI Prozess beendet
  IdleTimeout 300
 
  # Alle n Sekunden prüft fcgid auf unbeschäftigte Prozesse
  IdleScanInterval 30
 
  # Legt ein maximal Limit für fcgid Prozesse fest, wird dieses erreicht, wird kein weiterer PHP CGI Prozess gestartet.
  # ACHTUNG: Dies kann bedeuten, dass einzelne VirtualHosts nicht mehr erreichbar werden, wenn der Wert überschritten ist.
  MaxProcessCount 15
 
  # Dies muss laut fcgid Dokumentation gesetzt werden, um Fehler in Zusammenarbeit mit PHP zu umgehen
  MaxRequestsPerProcess 500
  PHP_Fix_Pathinfo_Enable 1
</IfModule>

Es gibt noch jede Menge weitere Parameter einzustellen. Schaue dazu auf der fcgid-Website (siehe unten).

10. Apache Server neustarten

Nun müssen wir den Virtual Host aktivieren und den Apache Server noch neustarten:

$ a2ensite deinhost.conf
$ /etc/init.d/apache2 restart

11. Testen

Nun legen wir eine index.php an und rufen die phpinfo() Funktion auf:

$ touch /var/www/deinhost/htdocs/index.php
$ vim /var/www/deinhost/htdocs/index.php

mit dem Inhalt:

<?php
phpinfo();

Rufe nun die URL zum VirtualHost auf und Du solltest eine wunderschöne phpinfo() Seite zu sehen bekommen!

12. Probleme?

Schaue bitte in den Logdateien von Apache

/var/log/apache2/error.log und /var/log/apache2/suexec.log nach möglichen Fehlermeldungen. Häufig handelt es sich um Zugriffsprobleme. Kontrolliere bitte die gesamte Anleitung nochmal!

13. FAQ

Wie kann ich das Immutable Bit wieder aufheben, um die geschützten Dateien zu löschen?

Dies geht so:

$ chattr -i  /var/www/deinhost/conf_deinhost

Danach ist die jeweilige Datei wieder editierbar und auch wieder löschbar.

Ich kann das Immutable Bit nicht setzen :-( !

Das Immutable Bit gibt es nicht auf allen Linux Dateisystemen. Hier hilft nur eine sehr aufwändige eigene Kompilierung von suexec Abhilfe. Dazu habe ich leider kein eigenes Tutorial bereit gestellt. Schaue im Internet nach entsprechender Hilfe.

Ich bekomme beim Aufruf der Website die Fehlermeldung "No input file specified."

Bitte setze die open_basedir Anweisung in der php.ini auf den richtigen Zielordner.

Ich bekomme beim Aufruf der Website den Fehler "500 Internal Server Error"

Wahrscheinlich handelt es sich um ein Rechteproblem. In der /var/log/apache2/suexec.log bekommst Du weitere Hinweise. Zum Beispiel:

  • [Datum Uhrzeit]: cannot open current working directory
    Hier kann der Benutzer deinuser nicht auf das Verzeichnis mit dem Konfigurationswrapper conf_deinhost zugreifen.

Bei sämtlichen Rechteproblemen sollte das helfen: Entferne das Immutable Bit (siehe FAQ oben), setze die Rechte wie in 7. beschrieben und setze danach das Immutable Bit wieder.

14. Quellen & Weiterführendes

15. Changelog

  • 30.08.2015 - Seit Debian Jessie müssen die Konfigurationsdateien für VirtualHost Container auf .conf enden (reported by Daniel J.)
  • 16.08.2014 - Punkte 6 und 7 getauscht. Dadurch Abhängigkeiten aufgelöst (reported by Frank O.)
  • 04.07.2013 - Änderung Zugriffsrechte konsistent an den 9.4.2013 angepasst (reported by Florian L.)
  • 09.04.2013 - www-data Zugriffsproblem gelöst, Rechte angepasst (reported by Klaus G.)
  • 17.08.2011 - Tutorial funktioniert auch unter Squeeze, Hinweis auf nicht sinnige Arbeitsgebiete
  • 05.08.2009 - Erweiterung der FAQ, um einen Hinweis bei fehlerhaft gesetzten Rechten
  • 22.07.2009 - Verbesserung der Sicherheit durch korrigierte chown www-data:deinuser und chmod 770/660 Einstellungen (reported by Sven M.)

Tags: