Full Page Caching für WordPress

Nginx, PHP-FPM und W3Total Cache im Zusammenspiel

An dieser Stelle hatte ich eine kleine Artikelreihe zum Thema „Speedranking für WordPress“ gestartet.
Heute möchte ich einen alternativen Weg aufzeigen, der zu einem ähnlichen, in Summe jedoch sicherlich “besseren” Ergebnis führt, da wesentlich weniger Komponenten zusammen funktionieren müssen.

Der Fairness halber muss man als Präambel vorausschicken, dass ich alle meine relevanten Webseiten inzwischen auf HTTP2 umgestellt habe; somit ergibt sich „per se“ ein Plus an Geschwindigkeit – zumindest für Browser die HTTP2 unterstützen.
Zum Thema „HTTP2“ werde ich in Bälde hier auf dem WP-Loft Blog ein wenig mehr erzählen.

Aber zurück zum Thema dieses Beitrages: FullPage Caching für WordPress mit Nginx – PHP-FPM und W3TotalCache am Beispiel meiner 365-Tage-Fotoprojektseite

1. Schaubild der bisherigen technischen Umsetzung

Somit waren für eine optimierte WordPress-Installation drei „Server-Layer“ notwendig, die zu jeder Zeit fein granular auf einander abgestimmt sein mussten.
Ein nicht unerheblicher Aufwand, zudem Varnish einfach zu installieren, aber diffizil zu konfigurieren ist.

So möchte ich an dieser Stelle gerne Steve Jobs, oder war es Leonardo da Vinci (?),  zitieren:

„Simplicity is the ultimate sophistication“
(„Einfachheit ist die höchste Form der Raffinesse!“)

Es geht also „raffinierter“ 🙂

2. Schaubild der neuen technischen Umsetzung

Folgende Vereinfachungen ergeben sich aus diesem Setup:

  • Kein HTTP / HTTPS – Mix mehr
  • Nur noch zwei „Server-Layer“ anstatt drei
  • Einfacher zu konfigurieren, daher übersichtlicher

Gut, man muss daran denken, die Funktionalität einer „Apache .htaccess Funktionalität“ in eine Nginx-Konfiguration  zu überführen; es wird sich jedoch zeigen, dass das nicht weiter problematisch ist.
So weit, so gut – oder Butter bei die Fische: Wie ist das Ganze nun in Konfiguration-Details umgesetzt ?

3. Die Umsetzung im Detail

An dieser Stelle habe ich ein Ubuntu-Derivat benutzt und die Thematik mit folgenden zwei Schritten umgesetzt.

1. Installation und Konfiguration von PHP-FPM

Sofern nicht schon auf dem Server vorhanden installiert man PHP-FPM. Per Default wird der “FastCGI Prozess Manager” als Linux-Socket installiert:

foo@whatever:/var/run# sudo apt-get install php5-fpm
foo@whatever:/var/run# ls -l | grep php5
-rw-r--r-- 1 root     root        5 Dez  1 17:16 php5-fpm.pid
srw-rw---- 1 www-data www-data    0 Dez  1 17:16 php5-fpm.sock
root@lvps91-250-113-206:/var/run#

Danach schauen wir in der /etc/php5/fpm/php.ini Datei nach, ob der Wert für cgi.fix_pathinfo auf „0“ steht:

; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI.  PHP's
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is.  For more information on PATH_INFO, see the cgi specs.  Setting
; this to 1 will cause PHP CGI to fix its paths to conform to the spec.  A setting
; of zero causes PHP to behave as before.  Default is 1.  You should fix your scripts
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
; http://php.net/cgi.fix-pathinfo
cgi.fix_pathinfo=0

2. Konfiguration des Nginx-Vhosts für PHP-FPM

...
 # PHP-FPM und W3total Cache Gedoehns
 root /var/www/htdocs/365-tage-fotoprojekte.de;
 index index.php
....
 location ~ .php$ {
                try_files $uri =404;
                fastcgi_split_path_info ^(.+.php)(/.+)$;
                fastcgi_pass unix:/var/run/php5-fpm.sock;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                include fastcgi_params;
        }
...

Testen ob die Konfiguration korrekt ist, und danach die neue Nginx-Konfiguration laden:

nginx -t && service nginx reload

4. FullPage Cache mit W3Total Cache

Das W3TotalCache-Plugin bringt ein paar sehr nette (!) Features mit.
Zwei davon werden wir im Folgenden benutzen:

  • Den Page-Cache
  • Die „Auto-Nginx-Configuration

Benutzen des Page-Caches auf der Festplatte / SSD:
Dieses Feature macht meiner Meinung nach nur Sinn, wenn man einen Server mit SSD-Platte, oder ein entsprechend gemountetes temporäres Filesystem dafür benutzen kann.
Man geht also in die Einstellungen des W3TotalCache-Plugins und stellt den Page-Cache wie folgt ein:

In der Folge legt das W3TotalCache-Plugin im Dokument-Root der entsprechenden WordPress-Installation unter /pfad/zur/WordPress/Installation/wp-content/cache einen Unterordner mit dem Namen „page_enhanced“ an. In diesem Pfad speichert das Cache-Plugin alle aufgerufenen WordPress Seiten als fertig gerenderte *.html Datei ab.
Spannend wird das Ganze, wenn man in der Nginx-Vhost Konfiguration folgendes ergänzt:

location / {
            try_files /wp-content/cache/page_enhanced/${host}${cache_uri}_index.html $uri $uri/ /index.php?$args ;
        }

Mit dieser Zeile sieht der Nginx nach, ob es zu einer aktuell angefragten WordPress-Seite bereits eine aktuelle und fertig gerenderte HTML Datei gibt. Wenn ja, so wird diese direkt ausgeliefert ohne

  1. den PHP-FPM Server zu bemühen
  2. Anfragen an die MySQL-Datenbank zu senden, zu empfangen und zu interpretieren

Conclusio: eine bereits fertig gerenderte WordPress Seite wird sehr viel schneller ausgeliefert, da sehr viel weniger Ressourcen benötigt werden.

Wie bei jedem anderen Cache auch gilt: Nur ein vorgewärmter Cache ist ein guter Cache!

W3Total Cache “Auto Nginx-Konfiguration”
Das zweite „nette“ Feature des W3TotalCache-Plugins ist die automatische Erzeugung einer „nginx.conf“ Datei.
Diese wird vom Cache-Plugin dann ins Document-Root geschrieben, wenn man das Plugin einmal kurz deaktiviert und wieder aktiviert; unter der Voraussetzung, dass die WordPress-Installation hinter einem Nginx mit PHP-FPM läuft.
Dort legt das W3TotalCache-Plugin, je nach Konfiguration, passende Nginx-Regeln ab.

Diese „nginx.conf“ kann ganz einfach mit der folgenden Direktive in die Nginx-Vhost-Konfiguration eingebaut werden: include /pfad/zur/WordPress/Installation/nginx.conf

Testen ob die Konfiguration korrekt ist, und danach die neue Nginx-Konfiguration laden und fertig:

nginx -t && service nginx reload

5. Ergänzende Informationen

Am Rande sei erwähnt, dass ich den Browser-Cache in der W3TotalCache-Konfiguration abgeschaltet habe. Das kann der Nginx in einer „nativen Form“ in der Vhost-Konfiguration auch:

        # Browser Caching
        location ~* .(?:ico|css|js|jpe?g|png|gif|svg|pdf|mov|mp4|mp3|woff)$ {
                expires 365d;
                add_header Pragma public;
                add_header Cache-Control "public";
                gzip_vary on;
        }