Bei einer PHP-Website hängt die Antwortzeit des Servers von drei Faktoren ab: Kompiliert PHP die Skripte bei jeder Anfrage? Sind genügend PHP-Prozesse für gleichzeitige Besucher vorhanden? Und vor allem: Muss PHP für jede Seite ausgeführt werden? Dieser Leitfaden behandelt alle drei Punkte in dieser Reihenfolge. Die Beispiele beziehen sich auf WordPress unter Ubuntu 24.04 mit PHP 8.3, gelten jedoch auch für Laravel oder jede andere PHP-Anwendung.
1. Erst messen, dann einstellen
Ohne eine Ausgangsmessung lässt sich nicht feststellen, ob eine Anpassung etwas bewirkt hat. Erfassen Sie die Ladezeit einer repräsentativen Seite dreimal hintereinander:
for i in 1 2 3; do
curl -o /dev/null -s -w "TTFB %{time_starttransfer}s\n" https://monsite.fr/
done
Ab 800 ms stuft Google die Antwortzeit als schlecht ein. Beachten Sie diesen Wert auch bei einer Seite, die nicht zwischengespeichert werden kann, wie beispielsweise der Warenkorb eines Online-Shops: Genau diesen Wert werden PHP-FPM und Redis verbessern. Zur Interpretation dieser Werte siehe WordPress läuft langsam: Die eigentliche Ursache finden.
2. OPcache aktivieren und dimensionieren
OPcache speichert bereits kompilierten PHP-Code im Arbeitsspeicher. Es wird zusammen mit PHP installiert, doch die Standardwerte sind für WordPress und dessen Erweiterungen zu niedrig. Erstellen Sie eine Übersteuerungsdatei:
cat > /etc/php/8.3/fpm/conf.d/99-opcache.ini <<'EOF'
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=60
EOF
systemctl restart php8.3-fpm
Mit revalidate_freq=60, PHP überprüft höchstens einmal pro Minute, ob sich eine Datei geändert hat: Dies ist ein guter Kompromiss für ein WordPress, das über den Admin-Bereich aktualisiert wurde.
opcache.validate_timestamps=0. Das geht zwar schneller, aber PHP erkennt keine Dateiänderungen mehr, solange Sie PHP-FPM nicht neu starten. Dies ist nur für Anwendungen vorgesehen, die über ein Skript bereitgestellt werden, das systemctl reload php8.3-fpm bei jeder Produktionsfreigabe. Bei WordPress würde ein Plugin-Update nicht berücksichtigt werden.3. Dimensionierung von PHP-FPM
Jede PHP-Anfrage belegt einen Prozess. Sind alle Prozesse belegt, müssen nachfolgende Besucher warten. Die entscheidende Einstellung lautet pm.max_children, die maximale Anzahl an Prozessen. Ist dieser Wert zu niedrig, kommt es zu Warteschlangen auf der Website; ist er zu hoch, geht dem Server der Speicher aus und er wird sehr langsam.
Messen Sie zunächst den durchschnittlichen Speicherverbrauch eines Prozesses auf einer laufenden Website:
ps --no-headers -o rss -C php-fpm8.3 | awk '{s+=$1; n++} END {printf "%.0f Mo en moyenne\n", s/n/1024}'
Berechnen Sie anschließend: Für PHP reservierter Speicher ÷ Speicher pro Prozess. Beispiel für einen VPS mit 4 GB: Wir reservieren etwa 1,5 GB für das System, Nginx und MariaDB, sodass 2,5 GB für PHP verbleiben. Bei 60 MB pro Prozess ergibt dies etwa vierzig; wir nehmen 35, um einen Spielraum zu lassen.
Stellen Sie den Pool in /etc/php/8.3/fpm/pool.d/www.conf :
pm = dynamic
pm.max_children = 35
pm.start_servers = 6
pm.min_spare_servers = 4
pm.max_spare_servers = 10
pm.max_requests = 500
pm.max_requests jeden Prozess nach 500 Anfragen neu startet, wodurch kleine Speicherlecks bestimmter Erweiterungen ausgeglichen werden. Auf einem VPS mit 2 GB, der nur wenig Datenverkehr verzeichnet, pm = ondemand gibt Speicherplatz frei, wenn auf der Website wenig los ist.
Um festzustellen, ob das Limit erreicht ist, achten Sie bitte auf folgenden Eintrag im Protokoll:
grep "max_children" /var/log/php8.3-fpm.log
Sollte dieser Wert regelmäßig angezeigt werden, erhöhen Sie ihn, sofern der Speicherplatz dies zulässt; andernfalls wechseln Sie zu einem höheren Tarif.
4. Den FastCGI-Seiten-Cache einrichten
Diese Einstellung hat die größte Wirkung: Nginx speichert eine Kopie des generierten HTML-Codes und liefert diese direkt aus, ohne PHP zu starten oder die Datenbank abzufragen. Eine zwischengespeicherte Seite wird innerhalb weniger Millisekunden bereitgestellt.
Deklarieren Sie den Cache-Bereich in /etc/nginx/conf.d/fastcgi-cache.conf :
fastcgi_cache_path /var/cache/nginx/fastcgi levels=1:2 keys_zone=WP:100m inactive=60m max_size=1g;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout updating http_500 http_503;
Anschließend im Block server Legen Sie für die Website fest, was niemals zwischengespeichert werden darf:
set $skip_cache 0;
if ($request_method = POST) { set $skip_cache 1; }
if ($query_string != "") { set $skip_cache 1; }
if ($request_uri ~* "/wp-admin/|/wp-json/|/xmlrpc.php|wp-.*\.php|/feed/|sitemap") { set $skip_cache 1; }
if ($request_uri ~* "/panier/|/commande/|/mon-compte/|/cart/|/checkout/|/my-account/") { set $skip_cache 1; }
if ($http_cookie ~* "comment_author|wordpress_logged_in|wp-postpass|woocommerce_items_in_cart|woocommerce_cart_hash") { set $skip_cache 1; }
Und im Block location ~ \.php$ :
fastcgi_cache WP;
fastcgi_cache_valid 200 301 302 60m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
add_header X-Cache $upstream_cache_status;
mkdir -p /var/cache/nginx/fastcgi
nginx -t && systemctl reload nginx
5. Den Cache nach einer Änderung leeren
Nginx erkennt nicht, dass ein Artikel geändert wurde: Ohne eine Bereinigung wird die alte Version weiterhin ausgeliefert, bis die Gültigkeitsdauer abläuft – in diesem Fall 60 Minuten. Es gibt zwei Lösungen:
- Einfach : Die Dauer kurz halten und nach einer wesentlichen Änderung manuell leeren mit
rm -rf /var/cache/nginx/fastcgi/*. - Automatisch : das Entlüftungsmodul einbauen (
apt install libnginx-mod-http-cache-purge) sowie das WordPress-Plugin Nginx Helper, das die betreffende Seite bei jeder Veröffentlichung aktualisiert.
6. Einen Redis-Objekt-Cache hinzufügen
Der Seiten-Cache ist bei dynamischen Seiten – wie dem Warenkorb, dem Kundenkonto und dem Administrationsbereich – nutzlos. Bei diesen Seiten verhindert ein Objekt-Cache, dass dieselben SQL-Abfragen von Seite zu Seite wiederholt werden müssen.
apt install -y redis-server php8.3-redis
systemctl enable --now redis-server
systemctl restart php8.3-fpm
Installieren Sie anschließend das WordPress-Plugin Redis Object Cache und aktivieren Sie es unter Einstellungen → Redis. Standardmäßig hört Redis nur auf der lokalen Adresse: Geben Sie diese niemals im Internet frei.
7. Komprimierung aktivieren
Die gzip-Komprimierung ist in der Nginx-Konfiguration von Ubuntu bereits aktiviert, jedoch nur für HTML. Ergänzen Sie den Abschnitt http von /etc/nginx/nginx.conf :
gzip on;
gzip_vary on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_types text/css text/plain text/xml application/javascript application/json
application/xml application/rss+xml image/svg+xml font/ttf;
Sie brauchen keine JPEG-, PNG- oder WebP-Bilder hinzuzufügen: Diese sind bereits komprimiert.
8. Das Ergebnis überprüfen
Rufen Sie dieselbe Seite zweimal auf und beachten Sie den oben hinzugefügten Header:
curl -sI https://monsite.fr/ | grep -i x-cache
curl -sI https://monsite.fr/ | grep -i x-cache
Die erste Antwort besagt MISS, die zweite HIT. Führen Sie anschließend die Messung aus Schritt 1 erneut durch: Bei einer im Cache gespeicherten Seite sollte die Antwortzeit von Frankreich aus unter 100 ms liegen. Bei dynamischen Seiten machen OPcache, PHP-FPM und Redis den Unterschied aus.
Häufig gestellte Fragen
Ist eine Cache-Erweiterung erforderlich, wenn ich den FastCGI-Cache von Nginx verwende?
Nein, nicht für das Seiten-Caching: Nginx erledigt dies effizienter als eine Erweiterung, da PHP gar nicht erst gestartet wird. Eine Erweiterung ist jedoch weiterhin nützlich für die automatische Leerkennung, wie beispielsweise Nginx Helper, oder zur Optimierung von CSS- und JavaScript-Dateien. Vermeiden Sie es, zwei Seiten-Caches zu kombinieren, da dies zu unvorhersehbaren Ergebnissen führen kann.
Welchen Wert sollte man für „pm.max_children“ festlegen?
Teilen Sie den für PHP reservierten Speicher durch den durchschnittlichen Speicherbedarf eines Prozesses, der auf Ihrer Website gemessen wurde. Bei einem VPS mit 4 GB und Prozessen von etwa 60 MB ist ein Wert um 35 angemessen. Es gibt keinen allgemeingültigen Wert: Dieser hängt von Ihren Erweiterungen ab.
Funktioniert der Nginx-Cache mit WooCommerce?
Ja, vorausgesetzt, Sie schließen den Warenkorb, die Bestellung, das Kundenkonto und Besucher mit einem offenen Warenkorb aus, wie es die Regeln in diesem Leitfaden vorsehen. Die Produkt- und Kategorieseiten bleiben für anonyme Besucher im Cache gespeichert, was den Server erheblich entlastet.
Ist Redis für eine kleine Präsentationswebsite sinnvoll?
Selten. Wenn fast alle Ihre Seiten aus dem Nginx-Cache bereitgestellt werden, bringt Redis so gut wie keinen Nutzen. Es wird erst dann sinnvoll, sobald ein erheblicher Teil des Datenverkehrs dynamisch ist: Online-Shop, Mitgliederbereich, Forum.










