Skip to content

PHP-FPM mit Debian Jessie

Statische Webseiten sind nett (und durchaus wieder im Kommen), aber zumindest für manche Zwecke sind dynamisch generierte Seiten und die auf diese Weise ermöglichte Interaktivität doch dann besser oder gar notwendig. Facebook, bspw., würde sich als statische Seite dann doch eher schwierig gestalten.

Die Welt dynamischer Webseiten

Scriptsprachen

Dynamisch generierte Seiten bedingen, dass beim Aufruf einer Webseite nicht nur eine auf dem Server abgelegte Datei angezeigt wird, sondern dass ein Programm dort läuft, das die Ausgabe mehr oder weniger live generiert. Das hat ganz andere Implikationen für die Sicherheit des Servers, denn nunmehr läuft dort von außen erreichbarer Code, der schlimmstenfalls noch durch die Nutzer selbst aufgespielt werden kann. Nicht jeder, der seine ersten Gehversuche mit Scripts macht, hat dabei auch Fragen der IT-Sicherheit ausreichend im Blick - um das Problem einmal stark verharmlosend zu beschreiben. Gerade PHP hat nicht den Ruf, zumindest in den ersten Jahren seiner Entwicklung großes Gewicht auf das Fördern oder gar Erzwingen sicherer Praktiken gelegt zu haben, und viele lern(t)en es vor allem als eine Art Templating-Sprache kennen, die man irgendwie in seine HTML-Seiten einbettet, um ihnen damit eine erweiterte Funktionalität zu verleihen, ohne dabei groß an Konsequenzen zu denken (schuldig, euer Ehren!).

Rechteprobleme

Besondere Schwierigkeiten kommen hinzu, wenn mehr als ein Benutzer auf dem Server Scripts nutzen will. Denn wenn der Webserver bzw. der von diesem gestartete Interpreter das Script ausführen will, muss er es lesen können. Dann muss er aber - logischerweise - auch die Scripts aller anderen nutzer lesen können, was bedeutet, dass Nutzer A ein Sript schreiben kann, mit dem er sich die Scripts von Benutzer B anzeigen lassen kann, samt aller dort gespeicherten Informationen (Datenbankpassworte usw.), ebenso wie Dateien, die Benutzer B anlegt. Und wenn das Script irgendwelche Dateien anlegt (man denke an hochgeladene Bilder), dann werden diese Dateien unter der Nutzerkennung des Webservers angelegt, so dass der Benutzer dann keinen vollen Zugriff darauf hat. Das ist alles etwas unschön, weshalb man schon bald die Möglichkeit geschaffen hat, Scripts (sei es Perl, sei es Python, sei es PHP) unter der Benutzerkennung des jeweiligen Nutzers laufen zu lassen, dem das Script “gehört”.

suexec und suphp

Das schafft zwar andere Probleme, insbesondere im Bereich der Performance, denn nun kann ein Webserverprozess nicht mehr beliebig viele Scripts in parallelen Threads abarbeiten, weil diese ja vielleicht verschiedenen Nutzern gehören, so dass für jedes Script ein neuer Interpreter-Prozess gestartet werden muss, aber es ist doch in der Regel vorzugswürdig.

Für Scripts, die über die CGI-Schnittstelle (ja, ich weiß, das “I” steht schon für “Interface”) gestartet werden, stellt suexec die entsprechende Funktionalität bereit. Für PHP tat das traditionell suphp. suphp gibt es aber in Debian Jessie nicht mehr. Was also tun?

Als Lösung bietet sich PHP-FPM an.

PHP-FPM

FPM steht dabei für FastCGI Process Manager und ist eine sehr angenehme Lösung, um PHP als FastCGI einzubinden. FastCGI ist ein Mittelding zwischen der Einbindung per mod_php, also als Modul im Webserver, und als CGI, so dass für jeden Aufruf eines PHP-Scripts ein eigener Prozess gestartet werden muss: es werden einige FastCGI-Prozesse gestartet, die in einem Pool vorgehalten werden, und wenn ein PHP-Script aufgerufen wird, wird der Aufruf vom Webserver an den schon laufenden Prozess weitergereicht. Das erspart den sonst für jeden Aufruf notwendigen Start des Interpreters - und es bietet die Möglichkeit, pro Pool festzulegen, unter welcher Benutzerkennung die Prozesse dieses Pools laufen sollen.

Hinweis: Der folgende Vorschlag ist nicht der einzige Weg, PHP-FPM zu installieren. Eine bessere Lösung unter Verwendung von mod_proxy_fcgi, auf die ich in den Kommentaren hingewiesen wurde, habe ich mittlerweile auch beschrieben. Dieser andere Weg setzt Apache 2.4.x voraus, benötigt aber kein Paket aus dem nicht-freien Debian-Repository. Insgesamt erscheint mir dieser andere Weg vorzugswürdig.

PHP-FPM installieren

Unter Debian Jessie ist die Installation der Pakete hinreichend einfach:

apt-get install libapache2-mod-fastcgi php5-fpm php5

libapache2-mod-fastcgi kommt hier aus dem non-free-Repository, das dementsprechend eingebunden sein muss.

Debian hinterlegt dabei die php.ini für die FastCGI-Prozesse unter /etc/php5/fpm/php.ini und die Konfiguration für FPM unter /etc/php5/fpm/php-fpm.conf, ergänzt u.a. um die Konfiguration installierter Module in /etc/php5/fpm/conf.d/, wie man das so kennt.

Im Verzeichnis /etc/php5/fpm/pool.d/ sind dann die einzelnen Pools definiert, die ebenfalls in die /etc/php5/fpm/php-fpm.conf inkludiert werden, standardmäßig nur der Pool des Benutzers www-data, unter dem der Webserver läuft.

FastCGI für PHP-FPM konfigurieren

Wenn man möchte, kann man die bestehende Konfigurationsdatei sichern:

cp /etc/apache2/mods-available/fastcgi.conf /etc/apache2/mods-available/fastcgi.conf.backup

und danach sie danach mittels vim /etc/apache2/mods-available/fastcgi.conf neu befüllen wie folgt:

<IfModule mod_fastcgi.c>
    AddType application/x-httpd-fastphp5 .php
    Action application/x-httpd-fastphp5 /php5-fcgi
    Alias /php5-fcgi /usr/lib/cgi-bin/php5-fcgi
    FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -socket /var/run/php5-fpm.sock -pass-header Authorization
    <Directory /usr/lib/cgi-bin>
        Require all granted
    </Directory>
</IfModule>

Auf diese Weise bekommen auf .php endende Dateien den Typ x-httpd-fastphp5 zugewiesen, der über den Handler /php5-fcgi aufgerufen wird, der wiederum auf /usr/lib/cgi-bin/php5-fcgi zeigt, was aber ebenfalls nicht existiert, so dass Apache stattdessen alles dem externen FastCGI-Server zuwirft, der über den Socket /var/run/php5-fpm.sock kommuniziert.

Nach Aktivieren der notwendigen Module mittels a2enmod fastcgi actions alias und einem Restart des Webservers (service apache2 restart) sollte PHP zur Verfügung stehen.

Pools für einzelne Benutzer einrichten

Um nun verschiedene Pools für verschiedene Benutzer einzurichten, bedarf es neben einer passenden Konfiguration des jeweiligen Pools in /etc/php5/fpm/pool.d/ und eines geänderten Aufrufs in jedem virtual host, der diesem Benutzer zugeordnet ist.

Am einfachsten kopiert man sich die bestehende Konfiguration für den Pool www und wandelt sie ab:

cd /etc/php5/fpm/pool.d
cp www.conf user1.conf
vim user1.conf

Folgende Teile der Konfiguration müssen ersetzt werden: der Name des Pools, user, group und listen:

; Start a new pool named 'user1'.
; the variable $pool can we used in any directive and will be replaced by the
; pool name ('user1' here)
[user1]

[...]

user = user1
group = users

[...]

listen = /var/run/php5-fpm-user1.sock

Selbstverständlich können auch andere, für diesen Pool spezifische Änderungen vorgenommen werden

Und danach bekommt der bspw. in /etc/apache2/sites-available/user1-domain.example konfigurierte virtual host noch folgende Ergänzung (zwischen <VirtualHost ...> und </VirtualHost>):

<IfModule mod_fastcgi.c>
    AddType application/x-httpd-fastphp5 .php
    Action application/x-httpd-fastphp5 /php5-fcgi
    Alias /php5-fcgi /usr/lib/cgi-bin/php5-fcgi-user1
    FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi-user1 -socket /var/run/php5-fpm-user1.sock -pass-header Authorization
</IfModule>

In diesem virtual host kommuniziert der Apache also nicht mit dem FastCGI-Server über /var/run/php5-fpm.sock, sondern über /var/run/php5-fpm-user1.sock, und den haben wir ja anders konfiguriert. Ein service apache2 restart bzw. service php5-fpm restart später sollte die geänderte Konfiguration zur Verfügung stehen.

Soll PHP in mehreren virtual hosts unter derselben Benutzerkennung laufen, empfiehlt es sich, die o.g. Konfiguration in eine eigene Datei (bspw. /etc/apache2/sites-available/user1.fcgi) auszulagern und diese Datei dann in die virtual host-Konfiguration einzubinden:

Include /etc/apache2/sites-available/user1.fcg

Das spart nicht nur Tipparbeit, sondern erleichtert auch spätere Änderungen sehr.

Wichtig: Der Eintrag FastCgiExternalServer darf dabei nur einmal erfolgen, also nicht pro vhost wiederholt werden.

Die Installation testen

Am einfachsten gestaltet sich der Test, wenn man im Webroot des Servers (Debian Jessie: /var/www/html/) und der einzelnen virtual hosts jeweils eine Datei test.php speichert, die nur phpinfo() aufruft:

<?php phpinfo(); ?>

In der Ausgabe von phpinfo() wird angezeigt, unter welchem Benutzer das Script ausgeführt wird.

Weiterer Lesestoff

Trackbacks

Netz - Rettung - Recht am : PHP-FPM - jetzt mit mod_proxy_fcgi

Vorschau anzeigen
Vergangene Woche hatte ich darüber berichtet, wie man - unter Debian Jessie - PHP-FPM mit mod_fastcgi installieren kann. In den Kommentaren hatte Sven mir dann nachfolgend erläutert, wie sich die Einbindung einfacher und besser über mod_proxy_fcgi lösen l

Syed riyaz Uddin am : Syed riyaz Uddin via Twitter

Vorschau anzeigen
PHP-FPM mit Debian Jessie https://t.co/1LzqIcVzfp #technology

Kommentare

Ansicht der Kommentare: Linear | Verschachtelt

Sven Hartge am :

Sven Hartge

Das mit fastcgi ist die uralte und nicht mehr wirklich präferierte Variante. Vor allem, weil Apache2.4 in Debian Jessie via mod_proxy direkt fcgi sprechen kann.

Besser ist also folgendes:

(aus meiner /etc/apache2/conf-enabled/php5-fpm.conf)

CODE:
    <Proxy "unix:/var/run/php5-fpm.sock|fcgi://php-fpm">         # we must declare a parameter in here (doesn’t matter which) or it’ll not register the proxy ahead of time         ProxySet disablereuse=off     </Proxy>     <FilesMatch ".+.ph(p[345]?|t|tml)$">         SetHandler proxy:fcgi://php-fpm     </FilesMatch>

(via http://float64.uk/blog/2014/08/20/php-fpm-sockets-apache-mod-proxy-fcgi-ubuntu/ und http://httpd.apache.org/docs/current/mod/mod_proxy.html#handler)

Damit kann man sich das ganze Gehampel mit libapache2-mod-fastcgi aus non-free und der Alias-Geschichte für den Dummy-Pfad, etc. sparen.

Sven Hartge am :

Sven Hartge

Nürx, was hat denn da die <> Zeichen im Markdown verwurxelt?

Thomas Hochstein am :

Thomas Hochstein

Ach, es ist ein Kreuz, da kommen sich die Plugins in die Haar - Markdown, BBCode und der Filter, der HTML verhindern soll. Alles historisch gewachsen, und wenn man jetzt irgendetwas deaktiviert, sehen alte Kommentare komisch aus.

Ich gucke mal, ob ich an der Reihenfolge was tun kann. Deinen Kommentar habe ich leicht abgewandelt, damit es auf jeden Fall erst einmal ordentlich aussieht. Sorry.

Thomas Hochstein am :

Thomas Hochstein

Ich glaube, uralt ist das, was ich vorher getrieben habe. :-)

Aber ich merke mir das gerne mal zum Testen vor. — Rest der Config bleibt sonst gleich, und mod_proxy muss dann noch aktiviert werden, richtig?

Sven Hartge am :

Sven Hartge

mod_proxy_fcgi muss eingeschaltet werden, richtig.

Dann obige Zeilen, entweder global oder pro vHost, mit abgewandeltem Socket-Pfad natürlich, wenn man die vHosts via Benutzer voneinander trennen will.

Wichtig ist, ist dass meine obige Lösung die in http://wiki.apache.org/httpd/PHP-FPM am Ende angesprochenen Probleme nicht hat, weil FilesMatch nur auf wirklich existierende Dateien matcht, während die in der Wiki-Seite besprochene ProxyPassMatch-Lösung ein Sicherheitsalbtraum ist.

Thomas Hochstein am :

Thomas Hochstein

Sehr schön. Funktioniert hier prima.

Danke!

Kommentar schreiben

HTML-Tags werden in ihre Entities umgewandelt.
Markdown-Formatierung erlaubt
Standard-Text Smilies wie :-) und ;-) werden zu Bildern konvertiert.
BBCode-Formatierung erlaubt
Gravatar, Identicon/Ycon Autoren-Bilder werden unterstützt.
Formular-Optionen
tweetbackcheck