Debian Etch: apache2-mpm-worker mit PHP5 via FCGI und suexec
Datum: 17. November 2007 - Zuletzt aktualisiert: 03. März 2010 - Kategorie Ubuntu/Debian
Ziel:
Als Alternative zu PHP5 mit mod_php bietet sich die FastCGI-Schnittstelle an, da dort die Ausführung von PHP im Kontext des Users möglich ist, nicht nur als www-data. So kann man alle Projekte gut trennen, pro VirtualHost kann man einen Benutzer festlegen. Im Gegensatz zu suphp ist diese Lösung performanter, aber nicht ganz so einfach zu konfigurieren. Noch ein Vorteil: Verschiedene PHP-Versionen sind auch kein Problem.
Ein Vergleich der verschiedenen Arten PHP einzubinden: rootforum.de: mod_php vs PHP-CGI
Zu diesem Howto:
Diese Anleitung hier schreibe ich, weil es viele meist zu komplizierte Tutorials gibt - sie sind einfach zu alt, oder wollen bestimmte Dinge durch selbstkompilieren umgehen... gerade letzteres wollte ich nicht, um die Sicherheitsupdates von Debian nutzen zu können.
Anmerkung: Ich verwende hier mod_fcgid statt mod_fastcgi - einen ausführlichen Vergleich zwischen den Alternativen habe ich nicht vorgenommen.
Benutzer und Gruppen:
Im Folgenden wird immer als Beispiel myuser und mygroup verwendet. myuser muss natürlich Mitglied der Gruppe mygroup sein - weiterhin setze ich aber voraus, dass auch www-data Mitglied dieser Gruppe ist: Der Apache muss die statischen Seiten/Grafiken/... ausliefern können, dafür benötigt er die Leserechte.
Hinzufügen von www-data zur Gruppe:
adduser www-data mygroup
Aus Sicherheitsgründen sollte man deshalb für jeden User eine eigene Gruppe anlegen! Nur so ist gesichert, dass ein Benutzer nicht auf die Daten eines anderen zugreifen kann.
Die ID des Benutzers und die ID der Gruppe dürfen außerdem nicht kleiner als 1000 sein, dies ist wegen suexec notwendig.
Anleitung:
Alle Befehle müssen als root ausgeführt werden. Zuerst müssen die benötigten Pakete installiert werden:
aptitude install php5-cgi apache2-mpm-worker libapache2-mod-fcgid
(Am besten sollten vorher Apache und PHP komplett deinstalliert werden, inklusive Konfigurationsdateien.)
(Anmerkung: In Debian Lenny muss auch apache2-suexec oder apache2-suexec-custom (für z.B. abweichendes DocumentRoot) installiert werden.)
Es sollte sichergestellt werden, dass fcgid und suexec aktiviert sind:
a2enmod suexec a2enmod fcgid
Unsere Verzeichnisstruktur muss zwingend unterhalb von /var/www liegen (die Debian-Binary fordert dies). Ich erstelle dort ein Verzeichnis vhosts:
mkdir /var/www/vhosts
Sicherstellen, dass die Rechte richtig sind (müsste schon so sein):
chmod 755 /var/www /var/www/vhosts
In diesem Verzeichnis wird für jedes Projekt (ein oder mehrere VirtualHosts) ein Verzeichnis angelegt, das root gehört, die Gruppe soll die des Benutzers sein:
mkdir /var/www/vhosts/projekt chgrp mygroup /var/www/vhosts/projekt chmod 750 /var/www/vhosts/projekt
In diesem Projektverzeichnis soll es 4 Ordner geben: conf, log, php-fcgi und web. Unter "conf" kommt die vollständige php.ini des Projekts, unter "log" sollen die Logs angelegt werden, in "php-fcgi" kommt das PHP-Startskript. "web" enthält die eigentlichen Daten, es wird das DocumentRoot des VirtualHost. Wichtig ist, dass Eigentümer und Gruppe sowie Rechte richtig gesetzt werden:
mkdir /var/www/vhosts/projekt/conf mkdir /var/www/vhosts/projekt/log mkdir /var/www/vhosts/projekt/php-fcgi mkdir /var/www/vhosts/projekt/php-tmp mkdir /var/www/vhosts/projekt/web chown myuser /var/www/vhosts/projekt/php-fcgi /var/www/vhosts/projekt/php-tmp /var/www/vhosts/projekt/web chgrp mygroup /var/www/vhosts/projekt/* chmod 750 /var/www/vhosts/projekt/*
Nun wird in "conf" die php.ini angelegt:
cp /etc/php5/cli/php.ini /var/www/vhosts/projekt/conf/php.ini
Die Einstellungen in der php.ini anpassen:
open_basedir = /var/www/vhosts/projekt/web/:/var/www/vhosts/projekt/php-tmp/ upload_tmp_dir = /var/www/vhosts/projekt/php-tmp/ session.save_path = /var/www/vhosts/projekt/php-tmp
Aus Sicherheitsgründen sind noch empfehlenswert:
disable_functions = show_source, system, shell_exec, passthru, exec, phpinfo, popen, proc_open display_errors = Off log_errors = On allow_url_fopen = Off
Es fehlt noch das Startskript für PHP:
vi /var/www/vhosts/projekt/php-fcgi/php-fcgi-starter
Der Inhalt soll sein:
#!/bin/sh PHPRC="/var/www/vhosts/projekt/conf/" export PHPRC exec /usr/bin/php5-cgi
(Später kann man bei Bedarf mit der Variable PHP_FCGI_CHILDREN in diesem Skript noch eine Maximalanzahl von Prozessen festlegen. Das php5-cgi-Binary von Debian hat glücklicherweise FastCGI-Unterstützung, nicht von dem fehlenden f verwirren lassen.)
Nun muss das Skript noch den User als Eigentümer sowie die richtige Gruppe haben, sonst funktioniert es nicht:
chown myuser:mygroup /var/www/vhosts/projekt/php-fcgi/php-fcgi-starter chmod 750 /var/www/vhosts/projekt/php-fcgi/php-fcgi-starter
Da der User nun alle Rechte an der Datei hat (und an deren Verzeichnis, beides wieder unbedingt notwendig), müssen wir Änderungen trotzdem verhindern - das geht mit dem immutable-Bit (muss vom Dateisystem unterstützt sein, auch root kann die Datei dann nicht mehr bearbeiten):
chattr +i /var/www/vhosts/projekt/php-fcgi/php-fcgi-starter
Zu beachten ist hier: Beim Kopieren wird das immutable-Bit nie mitkopiert, es muss immer neu gesetzt werden!
Damit wäre dies soweit abgeschlossen, es fehlt nur noch der VirtualHost in Apache:
<VirtualHost *>
ServerName www.domain-des-projekts.xy
SuexecUserGroup myuser mygroup
AddHandler fcgid-script .php
DocumentRoot "/var/www/vhosts/projekt/web/"
<Directory "/var/www/vhosts/projekt/web/">
FCGIWrapper /var/www/vhosts/projekt/php-fcgi/php-fcgi-starter .php
Options ExecCGI
</Directory>
ErrorLog /var/www/vhosts/projekt/log/error.log
LogLevel warn
CustomLog /var/www/vhosts/projekt/log/access.log combined
ServerSignature On
</VirtualHost>
Wie man sieht, kann man pro VirtualHost den User mit Gruppe verändern, und pro Verzeichnis sogar das PHP-Startskript.
In "web" sollte man jetzt zum Test als User eine PHP-Datei anlegen. Eigentlich überflüssig zu erwähnen, aber natürlich muss der Apache neu gestartet werden. Der erste Aufruf eines PHP-Skriptes wird spürbar dauern, da erst dann der PHP-Prozess gestartet wird. Danach geht es schneller.
In den Logdateien sieht es dann z.B. so aus:
$ cat /var/log/apache2/suexec.log [2007-11-17 09:45:34]: uid: (1000/myuser) gid: (1000/1000) cmd: php-fcgi-starter
$ tail -n2 /var/log/apache2/error.log
[Sat Nov 17 09:45:34 2007] [notice] mod_fcgid: call /var/www/vhosts/projekt/web/index.php with wrapper
/var/www/vhosts/projekt/php-fcgi/php-fcgi-starter
[Sat Nov 17 09:45:34 2007] [notice] mod_fcgid: server /var/www/vhosts/projekt/web/index.php(9495) started