Kirby ist bereits sehr schnell und gewinnt durch einen zusätzlichen Cache oft wenig. Bei langsamen WordPress-Seiten kann der Effekt dagegen enorm sein: NGINX liefert gespeicherte Seiten direkt aus, ohne PHP und Datenbank erneut zu bemühen.
Kirby eignet sich hier als übersichtliches Beispiel: Cache einrichten, Ausnahmen festlegen und nach Änderungen im Panel gezielt leeren.
Cache und Ausnahmen vorbereiten
Gespeichert werden nur öffentliche GET-Anfragen ohne Query-String, Cookies oder Authorization-Header. Panel, API und persönliche Inhalte bleiben außen vor.
Diese Definitionen gehören in den http-Kontext von NGINX:
fastcgi_cache_path /var/cache/nginx/kirby
levels=1:2
keys_zone=kirby:10m
max_size=256m
inactive=60m
use_temp_path=off;
map $request_method $skip_method {
default 1;
GET 0;
}
map $args $skip_args {
default 1;
"" 0;
}
map $request_uri $skip_path {
default 0;
~^/(panel|api)(/|\?|$) 1;
}
map $http_cookie $skip_cookie {
default 1;
"" 0;
}
map $http_authorization $skip_auth {
default 1;
"" 0;
}
Das Cache-Verzeichnis muss für den NGINX-Worker beschreibbar sein. Pfade und Größen anpassen. Die Cookie-Regel nimmt auch Statistik-Cookies aus; abweichende Panel- und API-Pfade brauchen angepasste Regeln.
Kirby und PHP-FPM anbinden
Diesen Ausschnitt in den bestehenden HTTPS-VHost integrieren. Domain, Document Root und PHP-FPM-Socket sind Platzhalter; Kirby liegt hier direkt im Document Root.
root /var/www/beispiel-domain.de;
index index.php;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
# Interne Kirby-Verzeichnisse und Inhaltsdateien schützen
location ~ ^/(content|site|kirby)(/|$) {
deny all;
}
location ~ /\.(?!well-known(?:/|$)) {
deny all;
}
# Nur Kirbys Front Controller an PHP-FPM übergeben
location = /index.php {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
fastcgi_pass unix:/run/php/kirby-fpm.sock;
fastcgi_cache kirby;
fastcgi_cache_key "$scheme|$request_method|$host|$request_uri";
fastcgi_cache_valid 200 10m;
fastcgi_cache_lock on;
fastcgi_cache_bypass $skip_method $skip_args $skip_path
$skip_cookie $skip_auth;
fastcgi_no_cache $skip_method $skip_args $skip_path
$skip_cookie $skip_auth;
add_header X-NGINX-FastCGI-Cache $upstream_cache_status always;
}
location ~ \.php$ {
return 404;
}
fastcgi_cache_bypass verhindert das Lesen, fastcgi_no_cache das Speichern bei einer Ausnahme. Die Cache-Dauer beträgt hier zehn Minuten. Details stehen in der NGINX-Dokumentation.
Vorhandene TLS-, FastCGI- und Security-Header-Regeln beibehalten und zusammenführen. Bei add_header auf die Header-Vererbung achten; Cache-Vorgaben der Anwendung nicht pauschal übergehen.
Vor dem Neuladen prüfen:
nginx -t
Cache prüfen
Die Seite zweimal mit einem GET-Aufruf abrufen:
curl -sS -D - -o /dev/null https://www.beispiel-domain.de/
Beim ersten Aufruf ist typischerweise MISS, beim zweiten HIT zu sehen:
X-NGINX-FastCGI-Cache: MISS
Mit Query-String sollte der Cache umgangen werden (BYPASS):
curl -sS -D - -o /dev/null 'https://www.beispiel-domain.de/?test=1'
Bleibt es bei MISS, Cookies und Antwort-Header prüfen. Für diesen Test kein curl -I verwenden: HEAD-Anfragen sind im Beispiel ausgenommen.
Einzelne Seiten aus dem Cache löschen
Das Beispiel benötigt das zusätzliche Modul ngx_cache_purge. Die kommerzielle NGINX-Purge-Funktion verwendet eine andere Syntax.
Dieser zusätzliche server-Block gehört in den http-Kontext. Er stellt den Purge-Endpunkt ausschließlich lokal bereit:
server {
listen 127.0.0.1:9080;
server_name localhost;
location ~ ^/purge(/.*)$ {
allow 127.0.0.1;
deny all;
fastcgi_cache_purge kirby "https|GET|www.beispiel-domain.de|$1";
}
location / {
return 404;
}
}
Der Schlüssel muss exakt zum öffentlichen VHost passen: hier https, GET und www.beispiel-domain.de. Eine Seite lässt sich so leeren:
curl -sS http://127.0.0.1:9080/purge/blog/mein-beitrag
PHP und NGINX müssen dafür denselben Netzwerk-Namensraum verwenden. Getrennte Container benötigen einen geschützten internen Zugriff. Den Purge-Port nicht öffentlich weiterleiten.
Nach Änderungen im Panel leeren
Diesen Hook in das vorhandene Array in site/config/config.php integrieren. page.update:after ruft nach Inhaltsänderungen den lokalen Endpunkt über Remote::request() auf:
<?php
use Kirby\Cms\Page;
use Kirby\Http\Remote;
return [
'hooks' => [
'page.update:after' => function (Page $newPage, Page $oldPage) {
$path = parse_url($newPage->url(), PHP_URL_PATH) ?: '/';
try {
$response = Remote::request(
'http://127.0.0.1:9080/purge' . $path,
['method' => 'GET', 'timeout' => 2]
);
if (!in_array($response->code(), [200, 404], true)) {
error_log('Kirby cache purge: HTTP ' . $response->code());
}
} catch (\Throwable $exception) {
error_log('Kirby cache purge failed: ' . $exception->getMessage());
}
},
],
];
200 bestätigt das Leeren. 404 kann einen fehlenden Eintrag, aber auch einen falschen Pfad oder Schlüssel bedeuten. Schlägt der Purge fehl, bleibt die alte Antwort gegebenenfalls bis zum Cache-Ablauf bestehen.
Der Hook leert nur die bearbeitete Seite. Betroffene Übersichten sowie Änderungen an Slug, Titel oder Status, Verschieben und Löschen brauchen eigene Regeln.
Zum Abschluss testen: HIT prüfen, Inhalt im Panel ändern und die neue Fassung abrufen. Auch Übersichten und angemeldete Benutzer einbeziehen.
Ursprünglich am 30. April 2024 bei Webhosting Franken erschienen. Text und Beispiele wurden überarbeitet.