Das Putzlowitsch Testblog für alles mögliche
Thema: Konfiguration

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 un 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 /
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 /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI}	!\.[^\.]+$ [OR]
RewriteCond %{REQUEST_URI}	\.html$
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

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.

4 Kommentare »

my-hacks.php wird auch in Wordpress 3.0 noch unterstützt

Puhhh, Glück gehabt. Nachdem bereits mit Wordpress 2.8 die Option für die my-hacks.php aus dem Backend verschwunden war, hatte ich befürchtet, daß auch die Unterstützung für diese älteste Wordpress-Erweiterungs-Schnittstelle ab Wordpress 3.0 ganz unter den Tisch fallen würde.

Das scheint aber nicht der Fall zu sein, denn in WP 3.0 RC1 wird die my-hacks.php weiterhin geladen, sofern sie aktiviert ist. Damit ist gewährleistet, daß nicht plötzlich nach dem Update wichtige Funktionen ausgesperrt werden, die möglicherweise in der my-hacks.php stehen.

Allerdings kann man nach einer Neuinstalltion die my-hacks-Erweiterung nicht mehr im Backend aktivieren. Dafür müßte man direkt in der Datenbank rumfummeln oder man verwendet das “123 Hackfile Option”-Plugin:

Download: Plugin 123 Hackfile Option 0.12

Die Option dafür erscheint nun allerdings nicht mehr bei Einstellungen->Verschiedenes (gibt es nicht mehr), sondern ganz am Ende von Einstellungen->Allgemein.

0 Kommentare »

Alles Nichts oder nicht alles?

Google-Treffer mit Parameter

Wenn Besucher über Google auf die eigene Webseite kommen, ist das ja normalerweise eine schöne Sache. Allerdings nicht, wenn es über einen seltsamen Link, wie er oben zu sehen ist, passiert. Wie kommt aber soetwas überhaupt in den Index einer Suchmaschine?

Das gibts doch gar nicht

Bereits im Oktober letzen Jahres hatte ich etwas Ähnliches beobachtet. Da wurden Google massiv mit Links auf irgendwelche nicht existierende Seiten gefüttert. Wenn nun eine dieser nicht vorhandenen Seiten auf die Anfrage des Googlebots einen HTTP-Status “200 OK” zurückliefert, geht Google davon aus, daß es die Seite gibt und nimmt sie in den Index auf. Korrekterweise sollte aber mit dem Fehlerstatus “404 Not found” geantwortet werden, so daß die Seite nicht im Index landet. Genau das war damals bei mir der Fall, also ist eigentlich alles in Butter. Nur habe nicht mit der Großzügigkeit von Wordpress gerechnet.

Die Wordpress.presse.pressung

In manchen Dingen ist Wordpress recht großzügig. Früher war es möglich, wenn in den Permalinks die Artikel ID verwendet wurde, einen Artikel über nahezu beliebig viele URLs aufzurufen. Sobald die ID erkannt wurde und existierte, wurde der Rest der URL nicht weiter überprüft. So hätte man diesen Beitrag hier auch noch mit /alles-quark-399/ oder /blafasel-399/ aufrufen können. Das geht mittlwerweile nicht mehr. Allerdings ist zur Zeit etwas Ähnliches immer noch möglich, wenn man in den Permalinks die Kategorie verwendet.

Wenn nun eine Wordpress-Seite mit Parametern in der Form /?parameter=wert aufgerufen wird, ignoriert Wordpress einfach unbekannte Patemeter oder ungültige Paremeterwerte und tut so, als würde es diese Parameter gar nicht geben. Somit führen folgende Aufrufe zu gültigen Seiten:

http://testblog.schnurpsel.de/?q=Diese Seite gibt es nicht
http://testblog.schnurpsel.de/?quark=Gesund und schmeckt lecker
http://testblog.schnurpsel.de/?p=Hier steht normalerweise die ID

Bei den ersten beiden Beispielen wir ein unbekannter Paremeter verwendet, im dritten Beispiel der gültige Parameter p= (Short-Link), der allerdings eine numerische Artikel-ID erwartet. In allen Fällen wird die Startseite mit dem Status “200 OK” angezeigt. Es funktioniert aber ebenso mit Einzelseiten oder anderen Permalinks:

http://testblog.schnurpsel.de/...hallo-welt/?frage=was-soll-das
http://testblog.schnurpsel.de/2010/03/?jahreszeit=Frühling

Gut oder schlecht

Ob dieses Verhalten von Wordpress nun gut oder schlecht, gewollt oder ein Fehler ist, mag ich nicht beurteilen. Ich finde es zumindest suboptimal, denn dadurch entstehet z.B. die oben gezeigte URL als Google-Treffer, und sowas möchte ich nicht haben. Dabei wäre es für Wordpress kein größeres Problem, unbekannte Parameter oder ungültige Parameterwerte als Fehler zu behandeln. Das schöne an Wordpress ist ja, daß es recht einfach erweitert und modifiziert werde kann.

Fehler bleibt Fehler

Deshalb habe ich mir diese Parameterprüfung hier nachgerüstet (aber nicht für den Testblog!), übrigens auch für die worpdresseigene Suchfunktion. Denn falls es keinen Suchtreffer gibt, finde ich, ist das auch einen “404 Not Found” wert :-)
Nun sollte auch die ganz oben gezeigte, hier nicht existierende Seite nach einiger Zeit aus dem Suchindex verschwinden.

Nachtrag:
Weil es angefragt wurde, hier mein Code zur Parameterprüfung, der sich per Action-Hook in parse_request reinhängt:

<?php
 function plw123_parse_request( $data ) {
  // Liste der numerischen Parameter
  $num_para = array( 'p', 'page_id', 'attachment_id', 'tag_id',
          'page', 'paged',
          'year', 'monthnum', 'day', 'w', 'm',
          'hour', 'minute', 'second' );
  // Parameter übergeben, aber nicht gefunden
  foreach( $_GET as $key => $value )
   if( !array_key_exists( $key, $data->query_vars ) ) {
    $data->query_vars['error'] = '404';
    return;
   }
  // Numerische Parameter prüfen
  foreach( $data->query_vars as $key => $value ) {
   // Sonderbehandlung Kategorie-IDs
   if( 'cat' == $key ) {
    // darf eine Liste von kommaseparierten Integerwerten sein
    $test_value = preg_replace( '|[^0-9,-]|', '', $value );
    if( $test_value != $value ) {
     $data->query_vars['error'] = '404';
     return;
    }
   }
   // Numerische Werte
   if( in_array( $key, $num_para ) ) {
    $value = trim( $value );
    // Page bei Einzelansicht (Seite, Artikel) kann führenden Slash enthalten
    if( 'page' == $key )
      $value = ltrim( $value, '/' );
    $test_value = absint( $value );
    if( !$test_value ) {
     $data->query_vars['error'] = '404';
     return;
    }
   }
  }
 }
 add_action( 'parse_request', 'plw123_parse_request' );
?>
4 Kommentare »

Höher, schneller, weiter

Mit den Google-Webmastertools bekommt man einen guten Überblick, wie oft der Googlebot vorbeischaut und wieviele Daten er in welcher Zeit Abfragt.

Pro Tag gecrawlte Seiten

Google - Crawling Anzahl der Seiten pro Tag Februar 2010
Auf dem Diagramm ist noch das Ende vom November, der ganze Dezember und Januar und der Anfang vom Februar zu sehen. Scheinbar tritt der Googlebot auch über den Jahreswechsel etwas kürzer, feiert Weihnachten und Silvester und legt dann erst Mitte Januar wieder richtig los.

Pro Tag heruntergeladene Kilobyte

Google - Crawling Datenmenge in kByte pro Tag Februar 2010
In etwa parallel dazu verläuft normlerweise die Kurve zu den täglich heruntergeladenen Datenmengen. Klar, je mehr Seiten angefragt werden, um so mehr Daten fallen da durchschnittlich an.

Eines fällt aber auf, denn obwohl die Anzahl der pro Tag abgefragten Seiten ab Mitte Januar und im Februar höher liegen als noch im November, ist die Datenmenge nicht in gleichem Maße angestiegen. Der Grund ist recht einfach. Ich hatte Anfang/Mitte Dezember die gzip-Komprimierung für die Seiten aktiviert.

Dauer des Herunterladens einer Seite (in Millisekunden)

Google - Crawling Zeit in Millisekunden pro Seite Februar 2010
Die Geschwindigkeit der Seitenauslieferung ist die für den normalen Nutzer, also den Besucher einer Website der wohl wichtigste, technische Wert. Wenn erstmal ein paar Sekunden nach dem Aufrufen einer Seite oder länger nichts passiert, ist das aus Anwendersicht eher unerfreulich.

Der Wert lag im November bei etwa 1,5 Sekunden und schließt damit an die Zahlen vom Oktober an. Anfang Dezember bin ich dann Dank SpeedPlus wieder zu Strato zurückgekehrt und seitdem liegen die Ladezeiten fast immer bei erfreulichen 0,8 Sekunden. Aber eben nur fast. Wie man im Diagramm sieht, gab es schon im Dezember und Anfang Januar Ladezeitspitzen, die dann im Februar nochmal deutlich zunahmen. Allerdings ist das eher darin zu sehen, daß durch die größere Anzahl der pro Tag abgefragten Seiten auch die Wahrscheinlichkeit für den Googlebots auf eine Lastspitze zu treffen, größer war.

Ungeachtet dessen gibt es aber diese Lastspitzen, die nicht nur der Googlebot “sieht”, sondern auch der normale Nutzer bemerkt. Wenn man Pech hat, dauert das Laden einer Seite wieder 4 bis 6 Sekunden, ganz so wie vor der SpeedPlus-Zeit bei Strato. Diesmal ist es aber meiner Meinung nach nicht die schlechte PHP-Performance, sondern eher die Datenbank. Die Datenbankserver sind zwar grundsätzlich nicht wirklich lahm, legen aber ab und zu ein paar Gedenkminuten ein, wie mir scheint. Und genau dann dauert der Seitenaufruf wieder mehrere Sekunden. Kürzlich gab es auch wieder mal einen Totalausfall, der dann zu einem 500er Fehler führt.

Hin und weg

Nun sind zwar PHP und Webserver bei Strato schnell, aber die Datenbank klemmt mitunter. Deshalb bin ich vorerst wieder zu meiner externen Datenbank zurückgekehrt. Das eigentlich langsame ist hierbei die Datenübertragung über das Internet zwischen Strato (Karlsruhe/Berlin) und Host-Europe (Köln). Um das etwas abzudämpfen, habe ich zusätzlich ein Datenbank-Cache-Plugin installiert, welches häufig benötigte Daten auf dem Webspace bei Strato im Dateisystem ablegt, um diese nicht jedesmal neu übertragen zu müssen. Zumal sich viele Daten, z.B. die Artikel und Seiten normalerweise eh nicht ändern.

Nun werde ich das Alles mal weiter beobachten, wie das mit den Ladezeiten so aussieht und hoffe aber trotzdem, das Strato die Datenbankaussetzer in den Griff bekommt.

0 Kommentare »

Permalinks – Was verwenden die 33 deutschen Top-Blogs

Welcher Permalink ist das beste Ding?

Die Diskussion taucht immer wieder mal auf, wie sieht optimalerweise ein Permalink, also die Struktur der URL aus. Sollten das Datum oder die Artikel-ID enthalten sein, ist es sinnvoll Kategorien oder Tags mit aufzunehmen?

Eine allgemeingültige und endgültige Empfehlung kann es nicht geben, wenn man die unterschiedlichen Sichtweisen dazu berücksichtigt, die dann zu eher widersprüchliche Aussagen führen.

Betreibt man ein Blog im Sinne eines Tagebuches, ist sicher das Datum oder Bestandteile davon eine gute Wahl. Aus SEO-Gesichtspunkten bzw. für eine eher thematische Ausrichtung wird oft die Kategorie mit in die Permalinkstruktur aufgenommen. Für eine Webseite mit vielen Schreibern könnte auch der Autorenname eine geeignete Option sein.

Ich habe mir einfach mal die Permalink-Struktur der 33 deutschen Top-Blogs angesehen. Vielleicht läßt sich ja daraus eine Empfehlung ableiten.

Die Permalink-Struktur der 33 deutschen Top-Blogs

Zunächst stellt sich natürlich die Frage, welche sind denn die Top-Blogs in Deutschland? Auch hier kann man sich endlos streiten, wenn man will. Ich habe als erste Näherung einfach die aktuell zusammengerechnete Liste von heute, dem 24.02.2010, genommen. Die Permalinkstruktur habe ich in Gruppen zusammengefaßt, vor dem jeweiligen Blog steht der aktuelle Platz in der Top-33-Liste :

Mehr als die Hälfte (57,6%) der Top-33-Blogs verwendet neben dem Artikelnamen das Datum oder einen Bestandteil davon in der URL. Bei allein fast 40% findet man das komplette Datum mit Jahr, Monat und Tag im Permalink. Gut 18% benutzen nur den Namen des Artikels als Permalink und weitere etwa 12% kombinieren dazu noch eine Nummer (Artikel-ID). Immerhin knapp 10% der Top-Blogs verwenden keine Permalinks, sondern setzen auf die Artikelnummer als URL-Parameter (?id=1234).

Erste Ableitung des Permalink-Aufbaus

Wenn man Permalinks verwendet, ist der Artikelname (in seiner Umwandlung zu einem URL-Pfad) gewissermaßen eine feste Größe. Die Einbeziehung des Datums oder von Teilen kann so schlecht nicht sein, diese Verwendet ein Großteil der Top-Blogs. Auch ganz auf Permalinks zu verzichten, hat gewisse Vorteile. Die URLs sind kurz und bleiben immer gültig, auch wenn man mal was am Artikel-Titel, dem Datum oder sonstigen Einflußfaktoren ändert.

Ich habe mir stichprobenartig noch weitere Blogs der Top-100 angesehen und zumindest keine Seite entdeckt, die etwa die Kategorie oder gar Tags in der URL verwendet. Mal davon abgesehen, daß Tags bei Wordpress bis zur Version 2.9.x nicht als Bestandteil der Permalinks funktionieren (obwohl in der Dokumentation genannt), gibt es auch noch andere Probleme.

Kategorie oder Tag im Permalink

In Wordpress kann man Artikel in mehreren Kategorien ablegen. Einem Artikel können zudem auch mehrere Tags zugeordnet werden. Verwendet man Kategorien oder Tags in Permalinks, erstellt Wordpress die die URL aus der Kategorie oder dem Tag mit der kleinsten ID. Ändert man nun die Kategoriezuordnung oder die Tags, kann sich möglicherweise auch die URL ändern.

Das ist aber erstmal nicht weiter schlimm, denn der Artikel wird auch weiterhin mit der alten Kategorie gefunden und angezeigt. Wordpress geht sogar soweit, einfach die Kategorie beim Auflösen der Permalinks zu ignorieren. Damit ergeben sich dann theoretisch beliebig viele URLs für einen Artikel.

Als Beispiel ist das auf meinem Testblog zu sehen. Die Permalink-Struktur sieht so aus:

/%category%/%postname%/

Der Artikel ist in der Kategorie “Allgemein” einsortiert, die URL sieht so aus:
http://testblog.schnurpsel.de/allgemein/hallo-welt/

Er ist aber auch mit der Kategorie “Blafasel”, “Hundekuchen” oder “Gibtesnicht” aufrufbar:
http://testblog.schnurpsel.de/blafasel/hallo-welt/
http://testblog.schnurpsel.de/hundekuchen/hallo-welt/
http://testblog.schnurpsel.de/gibtesnicht/hallo-welt/
Genau, diese Kategorien gibt es gar nicht.

Man hat damit potentiell also ganz viel bösen “Duplicate content” (DC). Da sage noch einer, die Kategorie im Permalink sei unter SEO-Gesichtspunkten empfehlenswert. ;-)

Permalink, so oder so

Letztendlich muß jeder selbst entscheiden, ob und wie er seine Permalinks gestaltet. Bei Putzlowitsch habe ich mich für das Datum entschieden, da ich dort eher im Sinne eines Tagebuchs schreibe. Hier verwende ich eine Kombination aus Artikelname und Artikel-ID, weil die sichtbare ID schnelle interne Links mit dem 123 IntLink-Plugin ermöglicht. Bei Twitter verwende ich übrigens gerne die WP-Shortlinks mit der ID als URL-Parameter, die sind schön kurz und funktionieren auch ohne Shortlink-Dienst.

1 Kommentar »

Mit welcher Wordpress-Version läuft ein Wordpress-Blog?

Wordpress habe ich seit Oktober 2006 in Benutzung (1&1 Fertigblog), mein erstes selbstinstalliertes Wordpress im November 2006 hatte die Version 2.0.4. Seitdem ist einige Zeit ins Land gegangen und mittlerweile sind wir bei Wordpress Version 2.9.1 angekommen, die Version 3.0 ist schon angekündigt und soll im März erscheinen.

Mit jeder neuen Wordpress-Version gab es meist neue Funktionen, manchmal war eine neue Ausgabe aber auch nur ein Sicherheits-Release, um bekannt gewordene Sicherheitslöcher zu stopfen. Damit sind Sicherheitslücken und deren Ausnutzbarkeit immer von der Wordpress-Version abhängig, wodurch die Versions-Information für einen Angreifer durchaus interessant ist.

Die Wordpress-Versionsnummer anzeigen

Wordpress liefert in der Standardinstallation die Versionsinformationen gleich an drei Stellen mit. Zwar sind diese für den normalen Besucher üblicherweise nicht sichtbar, aber in der Seite vorhanden.

Im Header der Seite
Wen man sich den HTML-Quelltext einer Seite ansieht, findet man dort möglicherweise im Header einen Eintrag wie <meta name=”generator” content=”WordPress 2.9.1″ />
Wordpress-Version im Header der Seite

Im Feed
Wen man sich den XML-Quelltext eines Feeds (RSS, Atom) ansieht, findet man dort möglicherweise am Anfang (channel) einen Eintrag wie <generator>http://wordpress.org/?v=2.9.1</generator>

Wordpress-Version im Feed

In der readme.html
Mit jeder Wordpress-Version wird eine Datei readme.html und in der deutschen Version auch liesmich.html mitgeliefert bzw. installiert. Diese findet man im Wordpress-Wurzelverzeichnis. Da steht die Wordpress-Version ebenso drin:
Wordpress-Version in der readme.html

Wordpress-Version verbergen

Man mag darüber streiten, ob es sinnvoll ist, die Versionsnummer vor Bots oder wem auch immer zu verbergen. Für die Unterdrückung der Ausgabe in den Seiten und Feeds gibt es diverse Lösungen. Wenn man nun aber so großen Wert darauf legt, die WP-Version zu verstecken, sollte man unbedingt auch die readme.html (liesmich.html) löschen. Aber Achtung, beim nächtens (automatischen) Update ist sie wieder da.

0 Kommentare »