Pagespeed: Microcaching mit Nginx

Nginx ist für sich schon ein sehr schneller Webserver – er bietet jedoch noch einige interessante Funktionen für Caching, womit Zugriffe auf PHP minimiert werden und Seiten deutlich schneller ausgeliefert werden. Eine kurze Anleitung.

Für diesen Blog verwende ich als Basis die aktuelle Nginx-Mainline-Version 1.7.0 mit ngx_pagespeed-Module. Dafür musste ich nginx selbst kompilieren, was aber kein grundlegendes Problem darstellt und mit den entsprechenden Anleitungen auch auf einem aktuellen Debian-System schnell erledigt ist.
Hier meine configure-Settings:

--prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-mail --with-mail_ssl_module --with-file-aio --with-http_spdy_module --with-cc-opt='-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,--as-needed' --with-ipv6 --add-module=../ngx_pagespeed-1.7.30.4-beta --add-module=../ngx_cache_purge-2.1

Damit kann nginx 1.7.0 als Drop-In-Replacement für den nginx aus den Debian-Repositories verwendet werden, alle Konfigurationsverzeichnisse bleiben gleich. Sollte mit der selbst kompilierten Version etwas nicht stimmen, kann man auch einfach wieder auf die ursprüngliche Version zurück wechseln.

Vorbereitung für Microcaching

Damit nginx Microcaching verwenden kann muss die Konfiguration angepasst werden. Dazu im Ordner /etc/nginx/conf.d eine neue Datei anlegen, ich habe sie microcache.conf genannt. Diese wird automatisch in die Haupt-Konfigurations-Datei eingeladen. Der Inhalt diese Datei:

fastcgi_cache_path /dev/shm/microcache levels=1:2 keys_zone=microcache:5M max_size=1G inactive=2h;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

Damit wird in einer Ramdisk ein Cache-Bereich von einem Gigabyte namens „microcache“ eingerichtet. Wer den Cache nicht im RAM halten kann oder will kann natürlich auch ein Verzeichnis auf der Festplatte anlegen und dieses verwenden. Der Key für jeden Cache-Eintrag ergibt sich aus dem Protokoll, der Request-Methode (POST oder GET), dem Host und der aufgerufenen URL. Damit können auch mehrere WordPress-Blogs gecacht werden, ohne das es zu Überschneidungen kommt.

Einrichtung des Cachings für VirtalHosts

Die meisten werden mit einer VirtualHost-Konfiguration arbeiten. Damit die Ausgabe von PHP gecacht wird muss fastcgi entsprechend konfiguriert werden. In der jeweiligen Konfigurations-Datei müssen folgende Angaben ergänzt werden:

set $skip_cache 0;

# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
 set $skip_cache 1;
}

if ($query_string != "") {
 set $skip_cache 1;
}

# Don't cache uris containing the following segments
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml {
set $skip_cache 1;
    }

# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}

location / {
try_files $uri $uri/ /index.php?$args;
}

# process any php scripts, not found gets redirected through routestring
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_cache microcache;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
# Set cache key to include identifying components
fastcgi_cache_valid 200        1d;
fastcgi_cache_valid 302 301    1m;
fastcgi_cache_valid 404        1s;
fastcgi_cache_min_uses          1;
fastcgi_cache_use_stale error timeout invalid_header updating http_500;
fastcgi_ignore_headers Cache-Control Expires;
fastcgi_pass_header Set-Cookie;
fastcgi_pass_header Cookie;
}

Fazit

Gegenüber der Lösung, die ich bisher eingesetzt habe (Caching ganzer Seiten via Memcached) bietet die Variante über die in Nginx integrierten Caching-Funktionen einige Vorteile:

  • Überhaupt kein Zugriff auf PHP-FPM zum ausliefern aus dem Cache
  • Seiten können auch ausgeliefert werden, wenn PHP einen Fehler zurückgibt (dies wird durch die Zeile fastcgi_cache_use_stale erreicht)
  • Für WordPress gibt es passende Plugins, die das leeren des Caches erleichtern (purge cache)

Ich werde dieses Setup hier im Blog nun weiter verwenden und schauen, welche Auswirkungen es sonst noch hat – schnelle Ladezeiten sind ja schon einmal ein grundlegender Vorteil.

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert