Kurz gesagt: Um Nginx für PHP sicher zu konfigurieren, geben Sie nur Skripte an PHP-FPM weiter, die es wirklich gibt, bei Front-Controller-Anwendungen sogar nur die index.php. Dazu kommen gesperrte Dotfiles wie .git und .env, ein Standard-Server für unbekannte Hostnamen, passende Größengrenzen und security.limit_extensions = .php im Pool. Das schützt nicht vor Lücken in PHP selbst, begrenzt aber, was nach einem Fehler ausführbar ist.
Die gefährlichsten Zeilen stehen in der PHP-Location
Seit PHP2Shell prüfen viele Teams ihre PHP-FPM-Versionen und Pools, wie es die Seite Nginx mit PHP-FPM absichern beschreibt, und starten nach dem Update alle Worker neu. Ein zweiter Blick gilt der Nginx-Konfiguration selbst. Dort entscheidet sich, welche Dateien überhaupt als PHP ausgeführt werden.
In vielen Konfigurationen steht ein Block, der jede Anfrage auf .php an PHP-FPM weiterreicht, egal wo die Datei liegt. Landet eine eingeschleuste PHP-Datei in einem Upload-Ordner, führt der Server sie aus. Aus einem Dateifehler wird so eine Hintertür.
Dieser Beitrag konzentriert sich auf die Nginx-Seite: welche Direktiven zählen, wie die Reihenfolge der Location-Blöcke wirkt und wie Sie das Ergebnis testen.
Wie Nginx entscheidet, welcher Block greift
Wer Nginx für PHP sicher konfigurieren will, muss die Auswahl der Location-Blöcke kennen. Laut Nginx-Dokumentation läuft sie so ab:
- Ein exakter Treffer mit
location =beendet die Suche sofort. - Unter den Präfix-Locations wird die längste passende gemerkt. Trägt sie
^~, werden keine regulären Ausdrücke mehr geprüft. - Sonst werden reguläre Ausdrücke (
~,~*) in der Reihenfolge der Konfigurationsdatei geprüft; der erste Treffer gewinnt. - Trifft kein regulärer Ausdruck, gilt die gemerkte Präfix-Location.
Daraus folgen zwei praktische Regeln. Eine Sperre für PHP in Upload-Ordnern muss entweder als ^~-Präfix angelegt werden oder als regulärer Ausdruck vor dem allgemeinen PHP-Block stehen. Und eine normale Präfix-Location wie location /uploads/ schützt nicht, weil der reguläre Ausdruck für .php sie übersticht.
Eine sichere Grundkonfiguration
Das folgende Beispiel zeigt einen Server-Block für eine Anwendung mit Front-Controller, wie sie bei Laravel, Symfony, Shopware 6 oder vielen Eigenentwicklungen üblich ist. Pfade, Socket und Zertifikate passen Sie an.
server {
listen 443 ssl;
server_name www.example.de;
root /var/www/seite1/public;
index index.php;
ssl_certificate /etc/ssl/seite1/fullchain.pem;
ssl_certificate_key /etc/ssl/seite1/privkey.pem;
server_tokens off;
client_max_body_size 32m;
# Let's Encrypt und andere bekannte Pfade erlauben
location ^~ /.well-known/ {
try_files $uri =404;
}
# Versteckte Dateien und Ordner sperren (.git, .env, .htaccess)
location ~ /\. {
deny all;
}
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
# Nur der Front-Controller wird an PHP-FPM übergeben
location = /index.php {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_hide_header X-Powered-By;
fastcgi_pass unix:/run/php/seite1.sock;
}
# Jede andere PHP-Datei wird nicht ausgeführt
location ~ \.php$ {
return 404;
}
}
$realpath_root löst symbolische Links auf. Das ist bei Deployments mit wechselndem Symlink auf das aktuelle Release wichtig, damit PHP-FPM und OPcache den richtigen Pfad sehen. Beachten Sie außerdem: Laut Nginx-Dokumentation werden fastcgi_param-Direktiven nur dann von höheren Ebenen geerbt, wenn auf der aktuellen Ebene keine eigenen stehen. Deshalb gehört include fastcgi_params; in denselben Block.
Klassische CMS wie WordPress, TYPO3 oder Contao haben mehrere Einstiegspunkte. Dort ersetzen Sie den Front-Controller-Block durch eine allgemeine PHP-Location, die nur existierende Dateien übergibt (try_files $uri =404;), und sperren die Ausführung in allen beschreibbaren Ordnern. Wie das gelingt, steht unter PHP-Ausführung in Upload-Ordnern verbieten.
Die zweite Absicherung in PHP-FPM
Nginx entscheidet, was weitergereicht wird, PHP-FPM entscheidet, was es ausführt. Laut PHP-Handbuch führt PHP-FPM standardmäßig Dateien mit .php und .phar aus und empfiehlt selbst, das auf .php zu beschränken. Das fängt Konfigurationsfehler im Webserver ab.
; im Pool, z. B. /etc/php/8.3/fpm/pool.d/seite1.conf
security.limit_extensions = .php
listen = /run/php/seite1.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
Der Socket sollte nur für Nginx erreichbar sein. FPM-Ports im Netzwerk, etwa 9000, gehören nicht nach außen geöffnet. Wie der Server insgesamt nur die nötigen Ports zeigt, beschreibt Firewall für Webserver: Nur nötige Ports öffnen.
Unbekannte Hostnamen und weitere Stellschrauben
Ohne eigenen Standard-Server beantwortet Nginx Anfragen an unbekannte Hostnamen mit dem ersten passenden Server-Block. Automatisierte Scans, die nur die IP-Adresse ansprechen, landen dann direkt in Ihrer Anwendung. Ein eigener Standard-Server beendet solche Anfragen ohne Antwort.
server {
listen 80 default_server;
listen 443 ssl default_server;
server_name _;
ssl_reject_handshake on;
return 444;
}
Weitere Punkte, die sich bewährt haben:
| Stellschraube | Empfehlung | Zweck |
|---|---|---|
server_tokens |
off |
keine Versionsnummer in Header und Fehlerseiten |
client_max_body_size |
passend zu post_max_size |
große Anfragen früh ablehnen |
autoindex |
aus (Standard) | keine Verzeichnislisten |
fastcgi_hide_header |
X-Powered-By |
keine PHP-Version nach außen |
| Status-Seiten | pm.status_path nur intern |
keine Betriebsdaten öffentlich |
| Backup-Dateien | .sql, .zip, .bak im Webroot sperren oder entfernen |
kein Download von Datenbanken |
Mehr zu Versionsangaben steht im Beitrag expose_php und Server-Header.
Eine weitere Stellschraube betrifft die erlaubten HTTP-Methoden. Die meisten Websites brauchen nur GET, HEAD und POST. Mit limit_except lassen sich andere Methoden in einer Location ablehnen; laut Nginx-Dokumentation erlaubt die Freigabe von GET automatisch auch HEAD. Prüfen Sie vorher, ob Schnittstellen Ihrer Anwendung etwa PUT oder DELETE nutzen, denn REST-APIs tun das häufig.
Testen, bevor Sie neu laden
Jede Änderung prüfen Sie zuerst mit nginx -t und laden Nginx erst dann neu. Anschließend testen Sie das Verhalten von außen mit normalen Anfragen an Ihre eigene Domain:
sudo nginx -t && sudo systemctl reload nginx
# Erwartet: 403 oder 404
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.git/HEAD
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.env
# Erwartet: 404, weil nur der Front-Controller ausgeführt wird
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/info.php
# Welche Blöcke übergeben an PHP-FPM?
sudo nginx -T 2>/dev/null | grep -nE "location|fastcgi_pass"
Sichern Sie vor jeder größeren Änderung die vollständige Ausgabe von nginx -T mit Datum. Sie enthält die gesamte wirksame Konfiguration einschließlich aller eingebundenen Dateien. Geht nach einer Änderung etwas schief, zeigt der Vergleich sofort, was sich unterscheidet. Bei der nächsten kritischen Lücke haben Sie damit außerdem eine verlässliche Grundlage für die Bestandsaufnahme, ohne erst Dateien zusammensuchen zu müssen.
Ändern Sie die Konfiguration zuerst auf einer Testumgebung oder einer Kopie des Server-Blocks. Ein vergessener Einstiegspunkt, etwa ein Zahlungs-Callback, fällt sonst erst auf, wenn Bestellungen ausbleiben.
Wie hilft PHP SOS konkret?
- Konfiguration lesen: Wir werten die gesamte Nginx-Konfiguration mit
nginx -Taus und ordnen jede PHP-Übergabe ihrer Website und ihrem Pool zu. - Einstiegspunkte festlegen: Gemeinsam mit Ihren Entwicklern bestimmen wir, welche Skripte ausgeführt werden müssen, und sperren den Rest.
- Umsetzen und testen: Wir passen Server-Blöcke und Pools an, prüfen mit
nginx -tund testen Formulare, Zahlungswege und Uploads. - Dauerhaft absichern: Die Konfiguration wird Teil unserer Server-Härtung und der Dokumentation Ihres Servers.
Häufige Fragen
Muss Nginx nach einem PHP-Update neu gestartet werden?
Für den PHP-Patch nicht, denn Nginx enthält kein PHP. Neu starten müssen alle PHP-FPM-Dienste. Ändern Sie dabei auch die Nginx-Konfiguration, prüfen Sie sie vorher mit nginx -t und laden Sie Nginx dann neu.
Warum nur index.php an PHP weitergeben?
Viele moderne Anwendungen haben einen einzigen Einstiegspunkt, den Front-Controller. Wird nur diese Datei an PHP-FPM übergeben, kann eine eingeschleuste PHP-Datei an anderer Stelle nicht über den Browser ausgeführt werden. Bei Systemen mit vielen Einstiegspunkten ist dieses Muster nicht möglich.
Was bringt security.limit_extensions in PHP-FPM?
Die Einstellung legt fest, welche Dateiendungen PHP-FPM als Skript ausführt. Laut PHP-Handbuch ist der Standard .php .phar; empfohlen wird, auf .php zu beschränken. Das fängt Fehler in der Webserver-Konfiguration ab, ersetzt sie aber nicht.
Sind Nginx-Regeln ein Schutz gegen PHP2Shell?
Nein. PHP2Shell steckt im PHP-Interpreter und wird nur durch das Update auf eine behobene Version und den Neustart aller Worker geschlossen. Eine sichere Nginx-Konfiguration verkleinert die Angriffsfläche und begrenzt den Schaden nach einem Einbruch.