Das Putzlowitsch Test- und SEO-Blog

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 Kommentare »

Bilderdiebe – was ich dagegen tue

Alter HutGut, das Thema des aktuellen Webmasterfridays ist zwar mit „Was tun bei Urheberrechtsverstößen?“ deutlich weiter gefaßt, als das es dabei nur um Bilder und Fotos ginge.

Der „Aufhänger“ war aber wohl der Bilderklau beim TagSeoBlog und so will ich mich hier auch nur auf dieses Problem beziehen.

Von Bilderdieben und Raubkopierern

Im richtigen Leben ist das alles klar und weitestgehend eindeutig definiert. Geht jemand in eine Gemäldegalerie, hängt dort heimlich ein Bild ab und nimmt es mit nach Hause, so ist das Diebstahl und derjenige ein Bilderdieb. Tut er so etwas zudem unter Anwendung von Gewalt oder Androhung von Gefahr für Leib oder Leben von Personen, so ist das Raub. Was nun genau ein Raubkopierer macht, ist mir allerdings nicht klar. Ich könnte mir aber vorstellen, daß das jemand ist, der z.B. eine bestimmte Ablauf eines bekannt gewordenen Raubes nachahmt, mithin also den Raub in der Vorgehensweise kopiert :-)

Beiden Delikten, Diebstahl und Raub, ist gemeinsam, daß es sich um die Wegnahme einer fremden beweglichen Sache handelt. Deshalb wird ein Diebstahl meist auch recht schnell bemerkt, denn der entwendete Gegenstand, z.B. das Gemälde, ist ja nicht mehr da.

Bildkopien und Hotlinking

In der digitalen Welt sieht das nun etwas anders aus, auch wenn hier unzutreffenderweise die Begriffe aus dem richtigen Leben verwendet werden. Denn normalerweise wird ein Bild ja nicht „entwendet“, so daß es plötzlich beim Besitzer fehlt, sondern nur eine Kopie angefertigt und an anderer Stelle verwendet (Bildkopie). Das führt auch dazu, daß die unrechtmäßige Verwendung eines Bildes erst sehr spät oder oft auch gar nicht bemerkt wird. Meist kommt so etwas nur eher zufällig ans Tageslicht.

Besonders im Internet wird oft noch nicht mal eine Kopie eines Bildes angefertigt, sondern das Bild einfach direkt von der fremden Seite eingebunden (Hotlink). Dadurch wird nicht nur das Bild möglicherweise unberechtigt verwendet, sondern auch noch der Server des „Bestohlenen“ belastet und ein zusätzliches Datenaufkommen erzeugt. Andererseits sind diese Hotlinks recht schnell zu erkennen, wenn man sich als Webmaster ab und zu die Serverlogfiles daraufhin ansieht.

Urheberrecht

UhrheberDie oben genannten Bildkopien bzw. das Hotlinking sind also kein Diebstahl oder gar Raub, sondern Verletzungen des Urheberrechtes.

Die wichtigsten Punkte im Urheberecht sind wohl Veröffentlichungs-, Verwertungs- und Folgerechte die es dem Schöpfer eines Werkes erlauben, allein darüber zu bestimmt, ob, wann, wo und in welcher Form sein Werk der Öffentlichkeit zugänglich gemacht und wie es im weiteren verwertet, verbreitet und vervielfältigt wird.

Meine Bilder

Im Allgemeinen habe ich nichts dagegen, wenn meine hier oder bei Putzlowitsch veröffentlichten Bilder von Dritten verwendet werden. Sei es nun in Communities, Foren oder anderen Blogs. Auch mit Hotlinks habe ich im Zeitalter von „unbegrenztem“ Traffic keine Probleme, ganz im Gegenteil, bin ich doch darüber schon auf die eine oder andere interessante Seite gestoßen.

Wenn nun aber meine Bilder dreist auf irgendwelchen Spam-Seiten landen oder in einem mir sonst wie nicht genehmen Kontext (z.B. rechtsradikale Foren) erscheinen, dann habe ich schon etwas dagegen. Da es bisher meist nur Hotlinks waren (bei Kopien habe ich es möglicherweise nur noch nicht bemerkt), gehe ich dagegen mit einer technischen Maßnahme vor.

Bilder-Hotlink unterbinden

Normalerweise sendet der Webbrowser eines Nutzers beim Aufruf einer Seite oder eines Bildes die Information mit, woher der Aufruf kommt. Bei einem Link ist das die verlinkende Seite oder bei einem sichtbaren Bild eben die Seite, auf der das Bild angezeigt wird. Diese Information, den so genannten REFERER kann der Webserver auswerten und gegebenenfalls bestimmte Aktionen ausführen. Das Ganze läuft über das Servermodul mod_rewrite und wird über die Datei .htaccess konfiguriert. Damit kann man dem Webserver z.B. sagen, daß wenn die Seite xyz aufgerufen wurde, er doch stattdessen bitte die Seite abc ausliefern oder einen Fehlercode zurückgeben soll.

Die einfachste und zugleich radikalste Variante, dem Hotlinking zu begegnen, ist folgender Dreizeiler:

RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www.)?schnurpsel.de/.*$ [NC]
RewriteRule \.(gif|jpe?g|png)$ - [F,L]

So oder ähnlich findet man das auf vielen Webseiten als Empfehlung, wie man sich gegen das Hotlinking schützen kann. Die Strategie ist hierbei, allen die Zugriffe auf Bilder zu verbieten (3. Zeile), und nur Zugriffe von der eigenen Seite zuzulassen (2. Zeile). Die 1. Zeile nimmt etwas Radikalität wieder raus, denn auch wenn der Referer leer, also nicht bekannt ist, woher der Aufruf kam, werden die Bilder angezeigt. Ohne Zeile eins würde man z.B. alle Suchmaschinen-Bots aussperren und auch die User, deren Browser den Referer unterdrückt.

Unberechtigte Zugriffe werden hier vom Webserver mit dem Fehlercode „403 Forbidden“ quittiert, der Browser zeigt dann für ein Bild nur den Alternativtext (falls vorhanden) und eventuell ein Fehlersymbol an. Die Antwort ist klar und deutlich, der Zugriff ist verboten und wird verweigert.

Meine Hotlink-Strategie

Ich bin da nicht ganz so konsequent sondern fahre eine andere Strategie. Ich erlaube prinzipiell allen den Zugriff und schließe nur unerwünschte Seiten aus. Ich will ja nicht die vielen netten User von Jappy, Schnappy und Zappy daran hindern, sich gegenseitig ihre „Gästebücher“ mit Bildern vollzukippen :-)

Bei mir sieht die Hotlinkabwehr deswegen etwas komplizierter aus:

RewriteCond	%{REQUEST_FILENAME} -f
RewriteCond	%{REQUEST_URI}	!^/images/1x5120.gif$
RewriteRule	\.(jpg|gif|png)$	-	[NC,C]
RewriteCond	%{HTTP_REFERER}	hotlink\.schnurpsel\.de [NC,OR]
RewriteCond	%{HTTP_REFERER}	bilderdieb\.schnurpsel\.de [NC,OR]
RewriteCond	%{HTTP_REFERER}	xxxx-yyyy\.zz
RewriteRule	.	/images/1x5120.gif	[T=image/gif,L]

In der 1. Zeile wird geprüft, ob die angeforderte Datei überhaupt existiert. Falls nicht, soll nicht die Hotlink-Abwehr greifen, sondern die normale Fehlerbehandlung ablaufen.

Da ich nicht einfach den Statuscode 403 zurückliefern will, sondern ein Ersatzbild, wird in der 2. Zeile geprüft, ob nicht gerade das Ersatzbild angefordert wird. Dann darf die Hotlink-Abwehr nicht erneut anspringen, sonst gäbe es eine prima Endlosschleife.

Die 3. Zeile selektiert nur die Zugriffe, die ein Bild mit einer der angegebenen Datei-Erweiterungen betreffen, hier also jpg-, gif- und png-Bilder. Die Liste kann natürlich beliebig erweitert werden. Dabei kann man ein klein wenig optimieren, in dem man den Bildtyp nach der Reihenfolge ihrer Häufigkeit angibt. Da bei mir die meisten Bilder vom Typ jpg sind, brauchen die restlichen Einträge dann nicht mehr überprüft werden.

Mit den Zeilen 1 bis 3 werden Vorbedingungen geprüft und nur wenn die angeforderte Datei existiert, nicht das Ersatzbild ist und dem richtigen Dateityp entspricht, wird der Rest abgearbeitet.

Die Zeilen 4, 5 … n-1 enthalten die eigentlichen Bedingungen, wann ein Hotlink als böse einzuordnen ist. Hier wird auf den oben schon angesprochenen Referer Bezug genommen und jede Seite eingetragen, von der Hotlinks unerwünscht sind. Auch hier kann man etwas optimieren, indem man die häufigsten Seiten an den Anfang der Liste stellt. Man kann hier aber auch andere Bedingungen einsetzen, z.B. IP-Adressen. Eine ausführliche Beschreibung zum Apache-Rewrite-Modul findet man hier.

Die letzte Zeile n gibt dann nur noch das Ersatzbild aus, bei mir ein transparentes GIF-Bild mit einem Pixel Breite aber über 5000 Bildpunkten Höhe. Zu sehen ist es nicht, aber es reißt die Seite an der Stelle weit auseinander, ja nach dem, wie das Bild auf der Hotlinkseite eingebunden ist. Außerdem liefere ich, egal was für ein Bildtyp angefordert wird, immer das Gif-Bild aus. Deshalb wird noch der richtige Content-Type (image/gif) gesetzt.

So sieht es aus

Zur Demonstration habe ich mal zwei böse und eine gute Sub-Domain erstellt, damit man sehen kann, wie sich das Ersatzbild auswirkt.
Die gute Seite:
Der alte Hut
Die bösen Seiten:
Bilderdieb
Hotlink
Hinweis zu den bösen Seiten: Wenn man sich zuerst die gute Seite angesehen hat, dann wird auf einer der bösen Seiten möglicherweise trotzdem der Hut und nicht das Ersatzbild angezeigt. Das liegt am Caching durch den Browser. Man muß dann nochmal das Neuladen der Seite erzwingen, beim Firefox z.B. mit Shift+Reload-Button oder Strg+F5.

Vorerst reicht mir meine Hotlink-Abwehr per Ersatzbild für böse Seiten, die Seiten und Abrufe sind allerdings auch recht überschaubar. Problematisch wird es, wenn die Liste mit den Seiten gar zu lang wird, denn die muß der arme Webserver immer von oben bis unten abarbeiten. Das könnte sich dann mit schlechten Antwortzeiten und höherer Serverlast bemerkbar machen.

Nachtrag: Ich habe es nicht extra erwähnt, aber damit die Regeln überhaupt abgearbeitet werden, muß normalerweise die Rewrite-Engine eingeschaltet werden. Zudem sollte man prüfen, ob das Modul mod_rewrite überhaupt zur Verfügung steht. So sieht dann meine Variante komplett aus:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_URI} !/bilder/bild-foto/die-besten-bilder-der-welt.jpg$
RewriteRule \.(jpg|gif|png)$ - [NC,C]
RewriteCond %{HTTP_REFERER} bilderr\.com [NC,OR]
RewriteCond %{HTTP_REFERER} pictures-images\.com [NC,OR]
RewriteCond %{HTTP_REFERER} freeimages-de\.bloggum\.com [NC,OR]
RewriteCond %{HTTP_REFERER} zaggla\.com [NC]
RewriteRule . /bilder/bild-foto/die-besten-bilder-der-welt.jpg [T=image/jpg,L]
</IfModule>

Dieser Block sollte noch vor allen anderen Rewrite-Blöcken stehen, also auch vor den WordPress-Permalink-Eintrag.

21 Kommentare »

Der Haken am Trick

Vor einiger Zeit hatte ich das 123 IIS Permalink-Plugin vorgestellt. Durch Kommentare zum 123 No Rewrite Permalink-Plugin wurde ich auf ein Problem aufmerksam gemacht, welches sich auch beim IIS auswirkt. Erfreulicherweise kann man das beim IIS im Unterschied zum Apache-Server wieder ausbügeln, da hier die POST-Daten nicht verloren gehen.

So gibt es nun also eine neue Version 0.11 des 123 IIS Permalink-Plugins, die auch mit Datenübergabe per POST oder GET funktioniert. Nebenbei habe ich gleich noch eine permanente Weiterleitung (301) der alten ‚/index.php/irgendwas‘-Aufrufe eingebaut. So braucht man sich wegen alter Permalinks z.B. bei Google keine Sorgen zu machen.

Keine Kommentare »

IIS WordPress Permalinks

Ja, es war mir schon klar, daß ich nicht der erste bin, der sich dieses Problems annimmt. Bei wordpress.org selbst ist es im Codex unter dem Titel „Using Permalinks Without mod_rewrite“ bereits angeschnitten und es gibt auch drei Lösungen dafür. Zwei gehen den Weg über ein spezielles ISAPI-Filter und eine Lösung verwendet auch den 404er Trick. Allerdings werden dort die Permalinks über ein .asp-Programm umgesetzt. Das funktioniert auch für die Oldstyle-Permalinks (WordPress 1.X), als noch alle Rewrite-Regeln in der .htaccess-Datei standen. Meine Lösung funktioniert nur bei den Newstyle-Permalinks (WordPress 2.X), bei denen nur noch die index.php angesprochen wird und die Auflösung der REQUEST_URI WP-intern erfolgt.

Generell kann ich die Lektüre der Permalink-Codex-Seite wärmstens empfehlen. Da bekommt man einen guten Überblick, was Permalinks sind, wie sie funktionieren und was man alles damit machen kann (und was nicht). Die Seite sollte auch mal auf Deutsch bei WordPress-Deutschland aufgenommen werden, viele Fragen im WPD-Forum drehen sich um Permalinks und wären sicher mit dieser Seite einfach beantwortet.

Ein Kommentar »

Exoten

Es scheint doch tatsächlich Leute zu geben, die ernsthaft WordPress auf einem IIS (was ist das?) laufen lassen :-)
Naja, es funktioniert wohl sogar. PHP mit MySQL bekommt man da auch ans laufen, also eigentlich kein großes Ding. Wenn da nicht die Sache mit den Permalinks wäre. Denn die erfordern nun mal ein funktionierendes mod_rewrite, was es aber meines Wissens nur für den Apache-Webserver gibt. Zumindest kann der IIS von Hause aus nichts mit den entsprechenden Einträgen in der .htaccess anfangen. Und WordPress ist auch so schlau, erkennt, daß es unter einem ISS läuft und bietet dann für die Permalinks gleich nur die Form mit dem vorangestellten /index.php an. Die sehen dann z.B. so aus:
/index.php/die-wordpress-import-schnittstelle-47/
Gut, es funktioniert auch aber ist doch eher nur ein Notbehelf, eine Krücke. Schöner sieht es natürlich so aus:
/die-wordpress-import-schnittstelle-47/

Das muß aber nicht bei der index.php-Variante bleiben, denn das Problem ist ein ähnliches wie bei den Strato-PowerWeb-Paketen, bei denen zwar ein Apache mit mod_rewrite läuft, dieses aber vom Kunden nicht genutzt werden kann. Wenn man es doch versucht, wird das knallhart mit einem 500er Fehler bestraft. Wie man es bei Strato doch hinbekommt, habe ich hier beschrieben.

Für den IIS ist der Ansatz ganz ähnlich. Es wird ein benutzerdefiniertes Fehlerdokument für den Fehler ‚404 Not Found‘ „mißbraucht“ und dieses ist einfach die ‚index.php‘ im WordPress-Wurzelverzeichnis. Was anderes macht die RewriteEngine praktisch auch nicht, bis auf einen kleinen, aber wichtigen Unterschied. Beim Fehlerdokument wird der Status auf 404 gesetzt, so das der normale Nutzer im Browser zwar keinen Unterschiede sehen würde, denn er bekommt die Seite ganz normal angezeigt. Ein Suchmaschinen-Robot würde die Seite aber wie einen „Not Found“-Fehler behandeln und nicht weiter beachten. Deshalb ist das in der Beschreibung genannte Plugin erforderlich, welches den Status wieder ordentlich zurechtbiegt.

Etwas anders liegt die Sache beim IIS. Wenn eine benutzerdefinierte Fehlerseite als URL aufgerufen wird, wird vom Webserver der Status auf ‚200 OK‘ gesetzte und der Fehlerseite als Parameter der Fehlerstatus und die aufgerufene Seite mitgegeben. Hier ist dann die Fehlerseite dafür zuständig, den Status entsprechend korrekt zu setzen. Eine sehr schöne Vereinfachung gegenüber den Verrenkungen, die bei der Stratolösung nötig sind.
Die einzig wirkliche Aufgabe besteht darin, aus dem übergebenen Parameter die eigenlich aufgerufene URL dem WordPress als REQUEST_URI unterzujubeln, da daraus dann mit den Permalinkregeln die anzuzeigende Seite ermittlet wird.

Lange Rede, kurzer Sinn, genau das macht mein neues Plugin „123 IIS Permalink„. Es ermöglich also auch unter IIS die schönen Permalinks ohne dem /index.php/… Vorspann :-)

Weitere Artikel mit Bezug zu diesem:
Keine Kommentare »