Vor ein paar Wochen habe ich meinen VServer auf das aktuelle Angebot von Netcup umgestellt: Quadcore, 16GB Ram, 250GB SSD. Die SSD zeigt deutlich Wirkung – vor allem bei meinem kleinen Shoutcast Server. Da ich auch gleich mit der schnelleren Webserver-Variante arbeiten wollte, habe ich Apache deinstalliert und verwende nun Nginx.
Nach gut 3 Wochen mit Nginx habe ich zwar noch nicht alle Kniffe herausgefunden, aber bis WordPress und auch die Multisites wieder voll funktionstüchtig waren, hat mich das ein paar Nerven und viele Internetrecherchen gekostet. Ich möchte euch meine Erfahrungen gebündelt weitergeben.
Allgemein
Ich verwende nginx unter Debian 7 mit PHP5-FPM. SNI Support ist angeschaltet. Ich verwende zur Seitenverwaltung das gleiche System wie bei Apache mittels sites-available und sites-enabled. Dazu muss in der nginx.conf folgende Zeile hinzugefügt werden:
include /etc/nginx/sites-enabled/*;
Unterschiede
Der wichtigste und größte Unterschied ist, dass nginx kein .htacces kennt. D.h. alle Einstellungen wie mod rewrite u.ä. werden direkt bei den Domainstellungen im Webserver definiert. In diesen Einstellungen werden im Gegenzug zu Apache keine VirtualHosts definiert, sondern server { }, die auf einem bestimmten Port lauschen, z.B. 80. Erst dann wird der server_name definiert, was in diesem Fall die Domain ist.
[AdSense-A]
PHP läuft im Gegenzug zu Apache als eigener Prozess, der mit nginx erst verknüpft werden muss. Dafür gibt es in nginx auch die sogenannten Fast CGI Parameter. D.h. wenn bei einem Webseitenverzeichnis PHP-Dateien ausgeführt werden sollen, muss das in den Webseiteneinstellungen für jede Domain + Port definiert werden.
Optimierungen – Basics
In dieser Hauptkonfigurationsdatei kann auch gleich gzip eingeschalten werden, damit alle Webdateien komprimiert an den Browser übertragen werden:
gzip on; gzip_comp_level 6; gzip_min_length 1000; gzip_proxied any; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; gzip_buffers 16 8k; gzip_vary on; gzip_http_version 1.1; gzip_disable "MSIE [1-6]\.";
Eine weitere wichtige Einstellung ist client_max_body_size. Diese legt fest, wie groß der Bodybereich einer HTML-Datei sein darf, d.h. wenn im HTML Text einer einzelnen Seite Bilder, Audios oder gar Videos beinhaltet sind, muss diese Einstellung je Webseite oder global angepasst werden. Wenn also eine Webseite Videos integriert hat (nicht eingebettete Videos wie YouTube etc.), dann sollte mit dieser Einstellung der Wert in Megabyte oder Gigabyte festgelegt werden, ansonsten führt das Ansehen des Videos zu einem Fehler. Mit 0 kann diese Funktion auch deaktiviert werden. Ich regle das für jede Seite einzeln, was die Sicherheit bei nginx erhöht.
Das hat allerdings noch keinen Effekt auf z.B. die Uploadgröße in der WordPress Mediathek. Dafür muss auch in PHP jeweils wie gewohnt die upload_max_filesize und post_max_size angepasst werden. Als letztes möchte ich noch den keepalive_timeout erwähnen, der standardmäßig zu lang eingestellt ist, d.h. die Zeit, in der Nginx die Verbindung zum Client (Besucher) noch offen hält.
WordPress
In WordPress verwende ich das Plugin iThemes Security, das bestimmte IP-Adressen und hostnames bereits sperrt. Das Plugin erstellt automatisch eine .conf, die in nginx für jede Domain eingebunden werden kann (siehe unten). Ich habe das allerdings nicht dynamisch zu der aktuellen Konfigurationsdatei im WordPress Ordner bei iThemes Security verknüpft, sondern lediglich eine statische (erste) Konfigurationsdatei erstellt – schlicht aus Sicherheitsgründen. Da diese Datei automatisch erstellt wird, werde ich sie hier nicht angeben (im Folgenden: wordpress-sec.conf).
Sicherheit und 404 Fehlervermeidung (drop.conf)
Damit bei fehlendem Favicon oder einer robots.txt, die standardmäßig bei jeder Domain abgefragt werden, kein 404 Fehler kommt, kann diese Log ausgeschaltet werden. Das ist dann sinnvoll, wenn eine 404-Fehlererkennung über nginx läuft, z.B. mit fail2ban. Ansonsten kann es sein, dass Besucher nach ein paar Klicks ausgesperrt werden. Im übrigen wird mit der vorletzten Definition der Zugriff auf alte .htaccess und ähnliche Dateien verwehrt. Der letzte Absatz gestattet keinen Zugriff auf URLs, bei denen etwas mit .php angehängt wird, z.B. /bild.jpg/test.php.
location = /robots.txt { access_log off; log_not_found off; } location = /favicon.ico { access_log off; log_not_found off; } location ~ /\. { deny all; } location ~ \..*/.*\.php$ { return 403; }
WordPress Konfiguration – Einzelne Seite
Für eine einzelne Installation sieht meine Webseiten-Conf folgendermaßen aus:
WordPress Konfiguration – Multisite
Konfiguration der Multisite auf Subdomainbasis
Einstellen einer Domain mittels WordPress MU Domain Mapping