WordPress mit Permalinks – den Webserver entlasten

Wie WordPress Permalinks verarbeitet

Durch Permalinks bekommen Artikel und Seiten lesbare URLs und auch Struktur. Alle Artikel in der Kategorie ‚Wordpess‘ können mit schnurpsel.de/themen/wordpress/ aufgerufen werden, das Monatsarchiv für Juli 2010 mit schnurpsel.de/date/2010/07/.

Auf dem Webserver existiert aber kein Verzeichnis /themen/wordpress/ oder /date/2010/07/. Damit die Seiten trotzdem aufgerufen werden können, erstellt WordPress eine einfache Regel für das Rewrite-Modul des Apache-Webservers:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

Diese drei Zeilen führen dazu, das alles, was nicht tatsächlich als Datei oder Verzeichnis auf dem Server existiert, einfach an die index.php von WordPress durchgereicht wird. WordPress kümmert sich nun darum, ob es z.B. eine Kategorie „WordPress“ gibt, stellt die Liste mit den passenden Artikeln zusammen und gibt sie aus.

Was es alles nicht gibt

Im Moment sind wohl mal wieder ein paar Bots oder Skriptkiddies unterwegs, die einfach versuchen, irgendwelche php-Skripte aufzurufen, um mögliche Sicherheitslücken ausnutzen zu können. Das sieht dann etwa so aus:

/scripts/setup.php
/pma/scripts/setup.php
/phpMyAdmin/scripts/setup.php
/phpmyadmin/scripts/setup.php
/myadmin/scripts/setup.php

Solche Dateien gibt es hier allerdings nicht. Auch andere Sachen können zu fehlerhaften Aufrufen führen, z.B. Standard-Icons wie favicon.ico oder apple-touch-icon.png, die manche Browser einfach aufrufen oder durch Nutzer aus der Bildersuche falsch kopierte BILd-URLs.

Durch die für die Permalinks notwendigen mod_rewrite-Regeln werden alle dies Aufrufe nun an WordPress weitergeleitet. WordPress wird geladen, stellt eine Datenbankverbingung her, klappert die internene Rewriteregeln ab um schließlich nur festzustellen, daß es mit dem Aufruf nichts anfangen kann. Dann gibt WordPress schließlich auch nur eine Fehlerseite aus, die möglicherweise auch noch aufwändig gestaltet ist und unnötig viel Daten als Antwort zurücküberträgt.

WordPress und den Webserver entlasten

Damit nun nicht WordPress wegen jeder Kleinigkeit behelligt werden, kann man eine spezielle Regel der WordPress-Regel vorschalten, die einfach gegebenfalls die Abarbeitung der Rewrite-Regeln beendet:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule \.[^\.]+$ - [L]
</IfModule>

Die Idee dabei ist, daß alle Permalink-URLs normalerweise keine Dateierweiterung wie .html, .jpg oder .php haben. Falls nun eine Datei nicht existiert (RewriteCond) und diese Datei mit einem Punkt und mindestens einem weiteren Zeichen endet, wird die Abarbeitung der Regeln an dieser Stelle beendet (RewriteRule). Diese Zeilen müssen vor den WordPress-Regeln stehen.

WordPress bekommt diese Aufrufe nicht mehr zu sehen, der Fehler wird einfach vom Webserver behandelt. Hier kommt dann auch eine konfigurierte und vorhanden benutzerdefinierte Fehlerseite zu Anwendung.

Ich weiß, es gibt auch Blogger, die aus welchen Gründen auch immer, die Permalinks mit einem abschließenden .html konfiguriert haben. Aber auch das ist kein Problem, es muß nur eine Zeile hinzugefügt werden, welche die Regel für die Endung .html (oder eine andere) ungültig macht:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI}	!\.html$
RewriteRule \.[^\.]+$ - [L]
</IfModule>

Optimierte Version

Mann kann die zusätzlichen Bedingungen auch direkt in die WordPress-Rules einfügen. Nachteil hierbei ist aber, daß sie bei Änderungen an den Permalinkeinstellungen verloren gehen, weil WordPress den Block zwischen # BEGIN WordPress und # END WordPress neu schreibt:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI}	!\.[^\.]+$
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

Die Version mit Endung .html:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI}	!\.[^\.]+$ [OR]
RewriteCond %{REQUEST_URI}	\.html$
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

Plugin-Version

Angeregt durch die Kommentare von Ralf habe ich nun eine Plugin-Version fertig gestellt.

Download: 123 Rewrite Error 0.10

Das Plugin schreibt die Regeln beim Aktivieren, Deaktivieren und bei Änderungen an der Permalinkstruktur wie bei der Optimierten Version beschrieben automtisch mit den WordPress-RewriteRules in die .htaccess. Dabei wird auch gleich berücksichtigt, ob in der Permalinkstruktur eine Erweiterung wie .html angegeben wurde.

Fazit

Wieviel Serverlast oder Traffic durch diese Maßnahme eingespart wird, kann ich nicht sagen. Das hängt sicher auch vom Nutzungsprofil und der Konfiguration der Website ab. Aber warum sollte man solch eine einfache Möglichkeiten auslassen, um WordPress und dem Webserver das Leben ein bißchen leichter zu machen.

8 Reaktionen zu “WordPress mit Permalinks – den Webserver entlasten”

  1. […] interessante Erweiterung der Mod Rewrite Regeln, um den Webserver bei der Abfrage von nicht existierenden Dateien zu entlasten. Schlagworte: Hack, […]

  2. Ralf sagt:

    Also das WP an meiner .htaccess rumfummelt und irgendwas neu schreibt, halte ich für höchst unwahrscheinlich. Meine .htaccess ist schreibgeschützt und somit auch vor den Zugriff durch WP sicher.
    Ich bin mir jetzt nicht sicher, habe es auch nicht ausprobiert, gehe aber nicht davon aus das WP die .htaccess neu schreibt wenn die Rewrite-Regeln geändert werden. Dies war wohl der Fall als WP die Rewrite-Regeln noch in die .htaccess geschrieben hatte. Seit WP2.0 (oder so) verwaltet WP die Rewrite-Regeln selber. Ein erneutes Beschreiben der .htaccess (mit dem glеiсhen Inhalt!) wäre recht unsinnig.

  3. Gut, wenn die Datei schreibgeschützt ist, kann WP natürlich nicht schreiben. :-)

    Ich habe es aber grad nochmal ausprobiert und auch ein Blick in den Quelltext (Funktion flush_rules) bestätigt es. Beim Ändern der Permalinks im Backend wird auch jedesmal die .htaccess neu geschrieben. Obglеiсh das, wie Du richtig schreibst, Unsinn ist, denn da ändert sich ja nichts bei den mod_rewrite-Rules.

  4. Ralf sagt:

    Whether to update .htaccess (hard flush) or just update rewrite_rules transient (soft flush). Default is true (hard).

    Ich habe mir jetzt auch mal ein wenig Zeit genommen und mir die rewrite.php angeschaut. Die Zeilen werden deswegen neu geschrieben, weil man auch eigene, nicht unbedingt auf WP bezogene, Rewite-Regeln anlegen kann. Zudem kann man auch zusätzliche Rewrite-Regeln (auf WP bezogen) anlegen. Deswegen wird der Block jedes mal neu geschrieben. Wenn jedoch keine eigenen Regeln definiert sind, dann werden immer die glеiсhen drei Zeilen eingetragen.
    Im Grunde genommen ist es ein Fehler in WP. Sofern keine externen oder eigene Rewrite-Regeln in WP definiert sind, müsste der Wert auf „false“ (soft flush) gesetzt werden, da ansonsten ja immer die glеiсhen Zeilen geschrieben werden.

    Daraus folgt aber auch, dass man deine Rewrite-Regeln nicht händisch in die .htaccess eintragen muss, sondern als Plugin bzw. Funktion in der functions.php ablegen kann. Dann bleiben sie auch nach einer Änderung der Permalink-Struktur erhalten.

    Da ich mich jetzt auch nur kurz mit der Rewrite API beschäftigt habe, müsste das Plugin in etwa so aussehen:

    // Rewrite API verfuegbar machen
    global $wp_rewrite;

    // Rewrite-Regeln festlegen
    $wp_rewrite->non_wp_rules = array (
    '%{REQUEST_FILENAME}' => '!-f',
    '%{REQUEST_FILENAME}' => '!-d',
    '%{REQUEST_URI}' => '!\.[^\.]+$',
    '.' => '/index.php [L]'
    );
    // Rewrite-Regeln in .htaccess schreiben
    $wp_rewrite->flush-rules();

    Das ganze dann als Funktion und in einen entsprechenden Filter (flush_rules?) einhängen.

    Ist mal so eben aus dem Ärmel geschüttelt, da müsste man sich dann halt mal näher mit der Rewrite-API beschäftigen.

  5. Markus sagt:

    Erstmal sehr guter Artikel, werde das bei mir auch umsetzen.

    @Ralf ich versteh jetzt nur nicht warum bei mir keine einzige Installation ohne .htaccess oder web-config je nach Serversystem funktioniert. Wenn keine eigenen Regeln drin sind, bräuchte man diese doch dann gar nicht, oder hab ich was falsch verstanden?

  6. Tom sagt:

    auf die Idee muss man erst mal kommen! werde es auch mal testen. danke schon mal für die Inspiration. :)

  7. […] weil man wissen will, was es für Neuerungen in WP 3.1 geben wird – und schon landet man auf Schnurpsels Blog mit einer sehr interessanten Überlegung zu mod_rewrite unter WordPress.Auch ich halte es […]

  8. wemaflo sagt:

    Erstmal: Danke für den Artikel! Das ist so ne Sache, der ich bisher überhaupt keine Beachtung geschenkt habe…

    @Markus: Prinzipiell braucht WordPress keine .htaccess mehr. Und zumindest bei WordPress 3.x wird standardmäßig auch gar keine mehr angelegt.
    Wenn man nun z.B das Blognetzwerk aktivieren will, muss man bei einer fabrikneuen Installation eine neue .htaccess anlegen.

Schreibe einen Kommentar

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

 Hier kein Häkchen setzen
 Ich bin kein Spambot

Hinweis: Kommentare von bisher unbekannten Schreibern (Name und eMail) oder mit mehr als einem Link werden moderiert.