# Nginx mit PHP-FPM absichern

> Nginx PHP-FPM Sicherheit nach PHP2Shell: Pools und Versionen prüfen, alle Worker neu starten, Übergangswerte per php_admin_value setzen und Nginx härten.

Quelle: https://phpsos.de/server/nginx-php-fpm/  
Stand: 25.10.2026  
Anbieter: PHP SOS, PHP-Notfallhilfe und Server-Sicherheit. Soforthilfe per WhatsApp: https://wa.me/491736494914?text=Hallo%20PHP%20SOS%2C%20wir%20brauchen%20Hilfe%20mit%20unserem%20PHP-Server.%20Firma%3A%20%E2%80%A6%20Website%3A%20%E2%80%A6

**Kurz gesagt:** Bei Nginx mit PHP-FPM steckt die Lücke aus PHP2Shell in PHP-FPM, nicht in Nginx. Patchen Sie alle PHP-FPM-Versionen, starten Sie jeden FPM-Dienst vollständig neu und belegen Sie das mit Prozess-Startzeiten. Für die Nginx PHP-FPM Sicherheit auf Dauer zählen getrennte Pools, nicht überschreibbare Werte und eine Nginx-Konfiguration, die keine hochgeladenen Dateien ausführt.

## Wie Nginx und PHP-FPM zusammenarbeiten

Nginx liefert statische Dateien selbst aus und reicht Anfragen an PHP-Skripte über FastCGI an PHP-FPM weiter. PHP-FPM besteht aus einem Master-Prozess und mehreren Worker-Prozessen, gruppiert in Pools. Ein Worker bearbeitet nacheinander viele Anfragen.

Genau das ist für PHP2Shell relevant. Bei CVE-2026-109619 kann interner Zustand einer Anfrage nach dem Freigeben des Speichers bestehen bleiben und von einer späteren Anfrage im selben Worker genutzt werden. Bei CVE-2026-109618 kann ein Out-of-Memory-Zustand PHP mitten in der Initialisierung einer Anfrage unterbrechen. Beide Lücken sind mit CVSS v4.0 9.2 bewertet und behoben in PHP 8.5.12, 8.4.27, 8.3.36 und 8.2.35.

## Bestand prüfen: Versionen, Pools, Prozesse

Viele Server haben mehrere PHP-FPM-Versionen parallel. Die folgenden Befehle lesen nur; Paket- und Dienstnamen sind Beispiele für Debian/Ubuntu und die RHEL-Familie.

```bash
# Welche FPM-Dienste laufen?
systemctl list-units --type=service | grep -i fpm

# Welche Version steckt dahinter? (Beispiel Debian/Ubuntu)
php-fpm8.3 -v
# RHEL-Familie
php-fpm -v

# An welche Sockets oder Ports reicht Nginx weiter?
nginx -T 2>/dev/null | grep -E 'fastcgi_pass'

# Pools und ihre Benutzer
grep -RhE '^\[|^user|^listen' /etc/php/*/fpm/pool.d/ 2>/dev/null
```

Gleichen Sie jeden `fastcgi_pass`-Eintrag mit einem laufenden Pool ab. So sehen Sie, welche PHP-Version welche Website bedient. Bei Distributionspaketen belegt das Änderungsprotokoll mit den CVE-Nummern den Patch, nicht allein die Versionsnummer.

Ein häufiger Befund bei solchen Bestandsaufnahmen sind Server, auf denen über die Jahre mehrere PHP-Versionen installiert wurden, von denen nur eine tatsächlich in Gebrauch ist. Die übrigen FPM-Dienste laufen trotzdem weiter, oft mit Standard-Pools, die auf einem lokalen Socket oder Port lauschen. Sie sind von außen meist nicht direkt erreichbar, bleiben aber ein unnötiges Risiko und verlängern jede Notfallaktualisierung. Deaktivieren und entfernen Sie Versionen, die keine Website nutzt, nachdem Sie die Zuordnung über die `fastcgi_pass`-Einträge geprüft haben.

Ebenso lohnt ein Blick auf den Benutzer der Pools. Laufen alle Pools als `www-data` oder `nginx`, ist die Trennung zwischen den Websites nur auf dem Papier vorhanden. Wer eine Website übernimmt, kann dann die Dateien aller anderen lesen, etwa Konfigurationsdateien mit Datenbankpasswörtern. Eigene Systembenutzer je Pool und passende Dateirechte schaffen hier eine echte Grenze. Das ist keine Abhilfe für PHP2Shell, begrenzt aber den möglichen Schaden eines erfolgreichen Angriffs deutlich.

## Patch einspielen und alle Worker erneuern

Nach dem Paketupdate starten Sie jeden PHP-FPM-Dienst neu. Ein Reload ersetzt zwar die Worker, ein vollständiger Neustart erneuert aber auch den Master-Prozess und ist nach Sicherheitsupdates der sichere Weg.

```bash
# Beispiel Debian/Ubuntu, je installierter Version
systemctl restart php8.3-fpm
# RHEL-Familie
systemctl restart php-fpm

# Kontrolle: Startzeit von Master und Workern
ps -eo pid,lstart,cmd | grep -E 'php-fpm' | grep -v grep
```

Jeder Prozess muss nach dem Update gestartet sein. Ausführlich beschrieben ist das unter [PHP-FPM und alle Worker neu starten](https://phpsos.de/php2shell/php-fpm-neustart/).

> **Wichtig:**
> Ein Patch entfernt keine Schadsoftware, die vorher eingeschleust wurde. Bewahren Sie die Nginx-Zugriffs- und Fehlerprotokolle ab dem 20.10.2026 auf und prüfen Sie die Websites auf Spuren.

## Übergangswerte im Pool setzen

Solange eine Version nicht gepatcht ist, empfiehlt php.net Übergangsmaßnahmen. Sie bieten keinen vollständigen Schutz. In PHP-FPM setzen Sie die Werte mit `php_admin_value` beziehungsweise `php_admin_flag` im Pool, dann können Anwendungen sie per `ini_set()` nicht überschreiben.

```ini
; Beispiel: /etc/php/8.3/fpm/pool.d/website.conf
php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[post_max_size] = 32M
php_admin_value[upload_max_filesize] = 24M
```

Ohne Upload-Funktion nennt php.net `post_max_size = 8M`. Auf PHP 8.5 kommt `fatal_error_backtraces=0` hinzu. Für den Hinweis zu `memory_limit=-1` brauchen Sie eine Speichergrenze auf cgroup-Ebene, etwa über `MemoryMax` in einer systemd-Ergänzung für den FPM-Dienst. Passen Sie in Nginx `client_max_body_size` an die neue `post_max_size` an, damit Nutzer verständliche Fehlermeldungen erhalten. Danach FPM neu starten.

## Nginx PHP-FPM Sicherheit dauerhaft verbessern

Über den akuten Fall hinaus helfen einige Grundregeln, die den Schaden bei künftigen Lücken begrenzen:

- **Ein Pool je Website** mit eigenem Systembenutzer, eigenem Socket und eigener `open_basedir`-Grenze. Mehr unter [open_basedir und Isolation pro Website](https://phpsos.de/ratgeber/open-basedir/).
- **Socket-Rechte** so setzen, dass nur Nginx zugreifen kann, keine FPM-Ports nach außen öffnen.
- **Nur existierende Skripte ausführen:** In der PHP-Location `try_files $uri =404;` setzen, damit Nginx keine Pfade an PHP weitergibt, die es nicht gibt.
- **Uploads nicht ausführen:** In Upload-Verzeichnissen PHP-Ausführung verbieten. Hinweise dazu stehen unter [Datei-Uploads sicher umsetzen](https://phpsos.de/ratgeber/datei-upload-sicher/).
- **Status-Seiten schützen:** `pm.status_path` und `ping.path` nur intern erreichbar machen.

```nginx
# Beispiel: keine PHP-Ausführung im Upload-Verzeichnis
location ~* ^/uploads/.*\.php$ {
    deny all;
}
```

Prüfen Sie jede Änderung mit `nginx -t`, bevor Sie Nginx neu laden. Halten Sie außerdem fest, welche Pools, Versionen und Sonderregeln auf dem Server bestehen. Diese kurze Dokumentation spart bei der nächsten kritischen Lücke wertvolle Zeit, weil niemand erst suchen muss, welche Website an welchem Pool hängt.

## Wie hilft PHP SOS konkret?

- Wir ordnen jede Website ihrem Pool und ihrer PHP-Version zu und prüfen den tatsächlichen Paketstand.
- Wir patchen, starten alle FPM-Dienste neu und dokumentieren Prozess-Startzeiten als Nachweis.
- Bis zum Patch setzen wir die Übergangswerte je Pool und begrenzen den Speicher per cgroup.
- Im Rahmen der [Server-Härtung](https://phpsos.de/leistungen/server-haertung/) trennen wir Pools, Rechte und Upload-Verzeichnisse sauber.
- Bei Verdacht auf einen Einbruch übernehmen wir die [Incident Response](https://phpsos.de/leistungen/incident-response/).


## Häufige Fragen

**Reicht systemctl reload für PHP-FPM nach einem Update?**  
Ein Reload erneuert die Worker, der Master-Prozess kann aber den alten Code behalten. Nach einem Sicherheitsupdate ist ein vollständiger Neustart des Dienstes der sichere Weg. Kontrollieren Sie danach die Startzeit von Master und Workern.

**Muss Nginx nach einem PHP-Update neu gestartet werden?**  
Nginx selbst enthält kein PHP und muss für den PHP-Patch nicht neu starten. Neu starten müssen alle PHP-FPM-Dienste. Ändern Sie dabei die Nginx-Konfiguration, prüfen Sie sie vor dem Neuladen mit nginx -t.

**Warum eigene Pools je Website?**  
Jeder Pool läuft mit eigenem Benutzer und eigenen Grenzen. Wird eine Website kompromittiert, kommt der Angreifer nicht ohne Weiteres an die Dateien der anderen. Zudem lassen sich Übergangswerte gezielt je Pool setzen.

**Ist pm.max_requests ein Schutz gegen PHP2Shell?**  
Nein, es ersetzt keinen Patch. Der Wert begrenzt, wie viele Anfragen ein Worker bearbeitet, bevor er ersetzt wird. Das kann die Lebensdauer von Zuständen im Prozess verkürzen, ist aber keine von php.net genannte Abhilfe.

## Quellen

- [php.net: Sicherheitsmeldungen](https://www.php.net/)
- [PHP 8 ChangeLog](https://www.php.net/ChangeLog-8.php)
- [OWASP Cheat Sheets](https://cheatsheetseries.owasp.org/)
- [BSI](https://www.bsi.bund.de/)
