WordPress auf nginx mit PHP-FPM konfigurieren: Server-Block, Grenzwerte und Sperren
Getestete Konfiguration für WordPress auf nginx mit PHP-FPM unter Debian 13: Installation, Server-Block mit Permalinks und Zugriffssperren, Grenzwerte im PHP-FPM-Pool, Prüfschleife mit curl und typische Fehler wie 502 und 413.
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Mehr dazu

Viele Hoster und Administratoren betreiben WordPress mit Apache, weil WordPress seine Regeln für schöne Permalinks selbst in die .htaccess schreibt. Auf einem eigenen Server ist nginx mit PHP-FPM eine verbreitete Alternative: nginx liefert statische Dateien direkt aus und reicht nur PHP-Anfragen an einen separaten PHP-Prozess weiter. Der Preis dafür ist, dass nginx keine .htaccess kennt. Jede Regel für Permalinks, Upload-Größen und Zugriffssperren müssen Sie selbst in die Server-Konfiguration schreiben. Diese Anleitung zeigt eine vollständige, getestete Konfiguration für Debian 13 mit nginx 1.26 und PHP 8.4, erklärt jede Zeile und zeigt die typischen Fehler mit echten Meldungen aus dem Labor.
Voraussetzungen
- Server: ein Linux-Server oder VPS mit Debian 13, im Labor Debian 13 „trixie“. Auf Ubuntu heißen Pakete und Pfade ähnlich, die PHP-Version kann abweichen. Für eine kleine Unternehmenswebsite genügen 2 CPU-Kerne und 2 bis 4 GB RAM.
- WordPress: eine vorhandene Installation mit Datenbank, getestet mit WordPress 7.1.2 in deutscher Sprache.
- PHP: PHP 8.4 aus den Debian-Paketquellen, im Labor 8.4.26. Die Mindestempfehlung der WordPress-Versionsschnittstelle ist PHP 7.4.
- Zugriff: SSH mit Root- oder sudo-Rechten sowie Administrator-Zugang zu WordPress.
- Backup: eine aktuelle Sicherung von Dateien, Datenbank und bisheriger Webserver-Konfiguration, bevor Sie von Apache auf nginx wechseln.
- TLS: Die Anleitung zeigt den HTTP-Teil. Das Zertifikat richten Sie danach ein, siehe Nginx mit TLS einrichten.
Schritt 1: nginx und PHP-FPM installieren
PHP-FPM (FastCGI Process Manager) hält einen Pool von PHP-Prozessen bereit, an die nginx Anfragen weiterreicht. Installieren Sie beide Komponenten und die PHP-Erweiterungen, die WordPress für Datenbank, HTTP-Anfragen, Bildbearbeitung und Sprachdateien braucht:
sudo apt update
sudo apt install --no-install-recommends nginx php8.4-fpm php8.4-mysql \
php8.4-curl php8.4-xml php8.4-mbstring php8.4-zip php8.4-intl php8.4-gd php8.4-imagick
--no-install-recommends verhindert, dass Debian zusätzlich Apache als Abhängigkeit mitbringt. Im Labor installierte Debian nginx 1.26.3 und PHP-FPM 8.4.26. Prüfen Sie die Versionen und den Standard-Pool:
nginx -v
php-fpm8.4 -v
grep -E '^(user|group|listen|pm)' /etc/php/8.4/fpm/pool.d/www.conf
Der Pool www läuft als Benutzer www-data und lauscht auf dem Unix-Socket /run/php/php8.4-fpm.sock. Diesen Pfad brauchen Sie im Server-Block. Die WordPress-Dateien müssen für www-data lesbar sein, schreibbar nur dort, wo WordPress schreiben soll. Details dazu stehen in Dateirechte in WordPress richtig setzen.
Verifizieren: php-fpm8.4 -t meldet „configuration file /etc/php/8.4/fpm/php-fpm.conf test is successful“, und der Socket /run/php/php8.4-fpm.sock existiert nach dem Start des Dienstes.
Schritt 2: Server-Block für WordPress anlegen
Legen Sie die Datei /etc/nginx/sites-available/wordpress an. Die folgende Konfiguration lief im Labor unverändert, ersetzen Sie nur server_name und root:
server {
listen 80;
server_name www.ihre-domain.de;
root /var/www/html;
index index.php;
client_max_body_size 64m;
# Sperren zuerst: nginx nimmt die erste passende Regex-Location
location = /wp-config.php { deny all; }
location = /xmlrpc.php { deny all; }
location ~ /\.(?!well-known) { deny all; }
location ~* /(?:uploads|files)/.*\.php$ { deny all; }
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
}
location ~* \.(?:css|js|jpe?g|png|gif|webp|avif|svg|ico|woff2?)$ {
expires 30d;
access_log off;
try_files $uri =404;
}
}
Die wichtigsten Zeilen im Einzelnen:
try_files $uri $uri/ /index.php?$args;ersetzt die Permalink-Regeln der.htaccess. Existiert keine Datei und kein Verzeichnis mit diesem Namen, übernimmt WordPress die Anfrage. Die Beispielkonfiguration im Advanced Administration Handbook verwendet dieselbe Zeile.snippets/fastcgi-php.confist ein Debian-Baustein. Er prüft mittry_files $fastcgi_script_name =404;, ob die PHP-Datei existiert, und bindetfastcgi.confmit dem ParameterSCRIPT_FILENAMEein.client_max_body_sizebegrenzt die Größe einer Anfrage. Der Standard von nginx liegt laut Dokumentation bei 1 MB, zu wenig für Medien-Uploads.location ~ /\.(?!well-known)sperrt versteckte Dateien wie.htaccessoder.git, lässt aber.well-knownfür Zertifikatsprüfungen offen.xmlrpc.phpsperren Sie nur, wenn Sie keine Apps oder Dienste nutzen, die XML-RPC brauchen. Hintergründe stehen in XML-RPC in WordPress deaktivieren oder einschränken.
Die Reihenfolge ist kein Detail. nginx prüft Regex-Locations in der Reihenfolge, in der sie in der Datei stehen, und nimmt die erste passende. Im Labor standen die Sperren zunächst hinter dem PHP-Block. Eine Testdatei wp-content/uploads/test.php wurde dann mit Status 200 ausgeführt, weil location ~ \.php$ zuerst passte. Erst nach dem Verschieben der Sperren nach oben antwortete nginx mit 403.
Aktivieren Sie die Konfiguration und prüfen Sie die Syntax:
sudo ln -s /etc/nginx/sites-available/wordpress /etc/nginx/sites-enabled/wordpress
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
Verifizieren: nginx -t meldet „syntax is ok“ und „test is successful“. curl -s -o /dev/null -w '%{http_code}\n' http://www.ihre-domain.de/ liefert 200.
Schritt 3: Umgebung und Grenzwerte im PHP-FPM-Pool
PHP-FPM startet seine Prozesse mit leerer Umgebung. Laut PHP-Handbuch steht clear_env standardmäßig auf „Yes“, damit keine beliebigen Umgebungsvariablen in die PHP-Prozesse gelangen. Das ist sicher, hat aber eine Folge: Liest Ihre wp-config.php Zugangsdaten per getenv(), etwa weil sie aus einem Container-Image oder einem Deployment-Werkzeug stammt, findet sie nichts. Im Labor zeigte WordPress daraufhin die Seite „Database Error“, und nginx lieferte den Status 500. Die Lösung ist entweder, die Werte direkt in die wp-config.php zu schreiben, oder sie gezielt im Pool freizugeben:
; /etc/php/8.4/fpm/pool.d/www.conf (am Ende ergänzen)
env[WORDPRESS_DB_HOST] = $WORDPRESS_DB_HOST
In derselben Datei legen Sie die PHP-Grenzwerte für diesen Pool fest. Im Labor galten ohne Anpassung upload_max_filesize 2M, post_max_size 8M und memory_limit 128M:
php_admin_value[upload_max_filesize] = 64M
php_admin_value[post_max_size] = 64M
php_admin_value[memory_limit] = 256M
php_admin_value kann von PHP-Code nicht überschrieben werden. Die Werte müssen zu client_max_body_size in nginx passen, sonst blockiert die jeweils kleinere Grenze. Laden Sie den Dienst neu:
sudo php-fpm8.4 -t && sudo systemctl reload php8.4-fpm
Die Anzahl der PHP-Prozesse steuert pm.max_children, im Debian-Standard 5. Jeder Prozess kann bis zum memory_limit belegen. Rechnen Sie grob: freier Arbeitsspeicher geteilt durch den typischen Speicherbedarf eines Prozesses. Messen Sie diesen Bedarf auf Ihrem Server, statt Werte aus Foren zu übernehmen.
Verifizieren: Eine vorübergehend angelegte Datei mit <?php echo ini_get('upload_max_filesize'); gibt über den Browser den neuen Wert aus, im Labor „64M 64M 256M fpm-fcgi“ für alle drei Werte und die Schnittstelle. Löschen Sie die Datei danach sofort.
Schritt 4: Permalinks, Sperren und Caching prüfen
Prüfen Sie die Konfiguration nicht nur mit der Startseite, sondern systematisch. Die folgende Schleife ruft typische Adressen auf und zeigt den Statuscode:
for p in / /hello-world/ /wp-login.php /wp-json/ /xmlrpc.php /wp-config.php /.htaccess /nicht-vorhanden/; do
echo "$(curl -s -o /dev/null -w '%{http_code}' https://www.ihre-domain.de$p) $p"
done
Im Labor mit Permalink-Struktur /%postname%/ lautete das Ergebnis:
| Adresse | Status | Bedeutung |
|---|---|---|
/, /hello-world/, /wp-login.php, /wp-json/ | 200 | Permalinks und REST-API funktionieren |
/xmlrpc.php, /wp-config.php, /.htaccess | 403 | Sperren greifen |
/wp-content/uploads/test.php | 403 | kein PHP im Uploads-Ordner |
/nicht-vorhanden/ | 404 | WordPress liefert seine Fehlerseite |
Für statische Dateien setzte die Konfiguration im Labor Cache-Control: max-age=2592000, also 30 Tage. Das entlastet den Server bei wiederkehrenden Besuchern. Mehr zu Caching-Headern und Komprimierung steht in Browser-Caching und Komprimierung für WordPress.
Unter Einstellungen > Permalinks können Sie die Struktur wie gewohnt ändern. Die try_files-Zeile leitet jede nicht vorhandene Adresse an WordPress weiter und deckt damit alle Strukturen ab.
Verifizieren: Alle Adressen liefern die Statuscodes aus der Tabelle, und /?p=1 leitet mit 301 auf die schöne Adresse des Beitrags weiter.
Schritt 5: Protokolle lesen und dauerhaft betreiben
nginx schreibt Fehler nach /var/log/nginx/error.log, PHP-FPM nach /var/log/php8.4-fpm.log. Beide Dateien sind die erste Anlaufstelle bei Problemen. Gesperrte Zugriffe erscheinen dort mit „access forbidden by rule“, was zeigt, dass Ihre Sperren arbeiten.
Richten Sie außerdem ein, dass beide Dienste nach einem Neustart des Servers starten:
sudo systemctl enable --now nginx php8.4-fpm
Ein eigener Server bedeutet eigene Verantwortung. Sicherheitsupdates für nginx und PHP kommen über apt, WordPress, Plugins und Themes brauchen ihre eigenen Updates, und nach jeder Änderung an der Konfiguration sollten Sie die Prüfung aus Schritt 4 wiederholen. Wer die WordPress-seitigen Aufgaben nicht selbst im Kalender halten möchte, kann sie abgeben: Die WordPress-Wartung von wordpressupdate.de übernimmt Updates von WordPress, Plugins und Themes mit Kompatibilitätsprüfung, wöchentliche Backups auf externen Speicher und die Firewall.
Verifizieren: systemctl is-enabled nginx php8.4-fpm meldet zweimal „enabled“, und nach einem Neustart des Servers liefert die Website wieder 200.
Typische Fehler
- 502 Bad Gateway: nginx erreicht PHP-FPM nicht. Im Labor stand bei falschem Socket-Pfad im Fehlerprotokoll:
connect() to unix:/run/php/php-fpm.sock failed (2: No such file or directory) while connecting to upstream. Pfad auslistenim Pool übernehmen und prüfen, ob PHP-FPM läuft. - 413 Request Entity Too Large beim Upload:
client_max_body_sizeist zu klein. Im Labor protokollierte nginx dazu „client intended to send too large body“. - Upload scheitert trotz passender nginx-Grenze:
upload_max_filesizeoderpost_max_sizeim PHP-FPM-Pool ist kleiner. WordPress zeigt dann die Meldung, die Datei überschreite das Upload-Limit. - „Database Error“ und Status 500 nach dem Wechsel: Die
wp-config.phpliest Umgebungsvariablen, die PHP-FPM wegenclear_envnicht weitergibt. - Beiträge liefern 404, die Startseite funktioniert: Die Zeile
try_files … /index.php?$args;fehlt oder steht im falschenlocation-Block. - PHP-Dateien im Uploads-Ordner werden ausgeführt: Die Sperre steht hinter
location ~ \.php$. Sperren nach oben verschieben.
Häufige Fragen
Ist nginx schneller als Apache?
Das hängt von Konfiguration und Last ab. nginx liefert statische Dateien effizient aus, die Laufzeit von WordPress selbst bestimmt aber PHP. Für die meisten kleinen Websites wirken Seiten-Cache und OPcache stärker als die Wahl des Webservers.
Funktionieren Sicherheits- und Cache-Plugins, die in die .htaccess schreiben?
Deren Regeln wirken auf nginx nicht. Viele Plugins zeigen deshalb eigene nginx-Beispiele an, die Sie in den Server-Block übernehmen und mit nginx -t prüfen.
Brauche ich einen eigenen PHP-FPM-Pool pro Website?
Bei mehreren Websites auf einem Server ja. Ein eigener Pool mit eigenem Benutzer trennt die Websites, sodass eine kompromittierte Installation nicht die Dateien der anderen lesen kann.
Testumfang
Wir haben die Konfiguration auf einem Debian-13-System mit WordPress 7.1.2 aufgebaut und jede Adresse aus der Prüfschleife tatsächlich aufgerufen. Dabei fiel die falsche Reihenfolge der Sperren auf, durch die eine PHP-Datei im Uploads-Ordner zunächst ausgeführt wurde, und ebenso der Datenbankfehler durch die geleerte Umgebung von PHP-FPM. Beides steht deshalb ausdrücklich im Text. HTTPS, den Start über systemd und Ubuntu haben wir nicht geprüft, dort sollten Sie die Schritte vor dem Umstieg auf einem Testsystem nachvollziehen.
Fazit
WordPress läuft auf nginx mit PHP-FPM stabil, wenn Sie drei Dinge beachten: try_files für Permalinks, Sperren vor dem PHP-Block und abgestimmte Grenzwerte in nginx und PHP-FPM. Mit der Prüfschleife aus Schritt 4 erkennen Sie nach jeder Änderung, ob alles noch greift. Wenn Sie die Pflege von WordPress, Plugins und Backups auf diesem Server lieber abgeben, übernimmt das die WordPress-Wartung von Marcel Schönfelder.
Weiterführende Anleitungen und Quellen
- Nginx als Reverse Proxy mit TLS manuell einrichten
- Dateirechte in WordPress richtig setzen
- Browser-Caching und Komprimierung für WordPress auf Apache und Nginx
- XML-RPC in WordPress deaktivieren oder einschränken
- Advanced Administration Handbook: Nginx
- nginx-Dokumentation: Core-Modul (location, try_files, client_max_body_size)
- PHP-Handbuch: FPM-Konfiguration


