Nach größeren Änderungen an einem Internetauftritt gibt es oft den Wunsch, veraltete URLs auf neue URLs umzuleiten. Dazu kann man in Webservern sogenannte „Redirects“ anlegen – Umleitungen für URLs. Sowohl Besucher mit Lesezeichen wie auch Suchmaschinen werden so eure neuen Inhalte umgeleitet, auch wenn sie eine alte URL aufrufen.

Für den Apache Webserver gibt es 2½ Wege, wie man Redirects konfigurieren kann: redirect, redirectmatch sowie RewriteRule. Tatsächlich ist die korrekte und fehlerfreie Konfiguration von Redirects aber eine trickreiche Sache – und ein genaues Studium der jeweiligen Anleitung notwendig, um Redirect Loops zu vermeiden.

Die 2½ verschiedenen Redirect-Direktiven funktionieren relativ ähnlich: Sie leiten eine Anfrage-URL, die einem bestimmten Muster entspricht, auf eine Ziel-URL um. Dazu können sie der Anfrage einen HTTP-Statuscode mitgeben, der den ursprünglichen Aufrufer mitteilt, aus welchem Grund und wie lange die Umleitung existiert.

Wo kann ich für den Apache-Webserver Redirects einrichten?

Der Ort für die Konfiguration von Redirects ist entweder die Apache-Konfigurationsdatei, oder aber (wenn der Webserver dieses Feature eingeschaltet hat) die .htaccess-Konfigurationsdatei direkt im Hosting-Verzeichnis bzw. der Document Root des Webauftritts.

Wenn kein Apache zum Einsatz kommt, funktioniert diese Methoden nicht – in der Regel verfügt aber jeder Webserver über eine zumindest ähnliche Methode, wie Redirects eingerichtet werden können.

Wie sollte ich für den Apache Redirects einrichten?

Bei der Einrichtung von Redirects sollte in der Konfigurationsdatei vermerkt werden, warum die Redirects eingerichtet wurden, oder wann sie gelöscht werden können. Nichts ist schlimmer, als in einem Wust von 6.500 Redirects nicht mehr durchzublicken und auch nicht zu wissen, ob nicht 6.000 Regeln schon lange hätten weggeworfen werden können. Hier bieten sich Kommentare an:

# Basic redirects START
Redirect permanent "/index" "/"
# Basic redirects END

# SEO redirects DELETE AFTER 10/2020 START
Redirect permanent "/artikel" "/articles"
Redirect permanent "/kontakt" "/contact"
# SEO redirects DELETE AFTER 10/2020 END

Gerade bei Redirects, die Suchmaschinen von einer alten, nicht mehr im Einsatz befindlichen URL auf eine neue URL umleiten sollen, kann nach zwei Jahren spätestens davon ausgegangen werden, dass sie nicht mehr notwendig sind.

Ein weiterer Vorschlag ist, die Direktiven für Redirects in Blöcke einzupacken, die testen, ob das für die Direktiven notwendige Modul überhaupt installiert ist:

<IfModule mod_alias.c>
  Redirect permanent "/index" "/"
</IfModule>

<IfModule mod_rewrite.c>
  RewriteRule "^/source$" "/target" [R=301,L]
</IfModule>

Dies verhindert, dass der Webserver seinen Betrieb einstellt, falls das Modul deaktiviert wird. Andersherum kann man diese Blöcke natürlich weglassen, wenn man explizit möchte, dass das Deaktivieren von Modulen und der damit verbundenen Redirects auffällt. 😉

Fallstricke bei der Konfiguration von Redirects im Apache

Wenn man sich die Anleitung für mod_alias inklusive redirect und redirectmatch sowie die Anleitung für mod_rewrite inklusive RewriteRule genau anschaut, wird man überraschenderweise darauf stoßen, dass alle Varianten bei der Anfrage-URL nicht eine fixe URL entgegen nehmen, sondern ein Muster (bzw. Pattern). Diese Muster erwischen meistens mehr Anfrage-URLs, als man auf den ersten Blick vermuten möchte.

Selbst die harmlos wirkende Redirect-Direktive sucht nach einem Muster (und nicht nach einem festen Wert), und hängt alle überschüssigen URL-Teile inklusive GET-Parameter an die Ziel-URL an:

Redirect permanent "/source" "/target"
# Redirects /source    to /target
# Redirects /source123 to /target123
# Redirects /source/12 to /target/12
# Redirects /source/?a to /target/?a

Das stellt eine größere Quelle für Verwirrung dar, da ein unbedarfter Einrichter mit der obigen Direktive nicht eine einzige Anfrage-URL umleitet, sondern tatsächlich eine unüberschaubar große Menge. Zudem kann eine frühere Regel nachfolgende Regeln unbenutzbar machen, ohne dass dies auf den ersten Blick auffällt:

Redirect permanent "/source"    "/target"
Redirect permanent "/source/12" "/target/some-special-place"

# Redirects /source    to /target
# Redirects /source123 to /target123
# Redirects /source/12 to /target/12 (!)
# Redirects /source/?a to /target/?a

Reguläre Ausdrücke werden die Welt retten

Verständlicher ist dort die RedirectMatch-Direktive, die von vorne herein mitteilt, dass sie mittels eines regulären Ausdrucks die Anfrage-URL in eine Ziel-URL umformt. Bei einer Fehlbedienung sind die Konsequenzen aber noch viel weitreichender:

RedirectMatch permanent "/source" "/target"
# Redirects /source               to /target
# Redirects /source123            to /target
# Redirects /source/12            to /target
# Redirects /source/?a            to /target
# Redirects /your-shiny/source/?a to /target

Eine Entsprechung zu RedirectMatch findet sich bei mod_rewrite, das auch kompliziertere Umleitungen abbilden kann.

mod_alias is designed to handle simple URL manipulation tasks. For more complicated tasks such as manipulating the query string, use the tools provided by mod_rewrite.

Die RewriteRule-Direktive hat entsprechende Fallstricke im Angebot, da sie ebenfalls mit regulären Ausdrücken arbeitet und je nach Einsatzort ein anderes Matching verwendet:

In VirtualHost context, The Pattern will initially be matched against the part of the URL after the hostname and port, and before the query string (e.g. „/app1/index.html“). This is the (%-decoded) URL-path.
In per-directory context (Directory and .htaccess), the Pattern is matched against only a partial path, for example a request of „/app1/index.html“ may result in comparison against „app1/index.html“ or „index.html“ depending on where the RewriteRule is defined.
[…]
The removed prefix always ends with a slash, meaning the matching occurs against a string which never has a leading slash. Therefore, a Pattern with ^/ never matches in per-directory context.

Die Einschränkung für .htaccess-Dateien kann übrigens mit einem vorangestellten RewriteCond %{REQUEST_URI} aufgehoben werden, so dass sich die Regeln wieder analog zu ihrem Aufruf innerhalb einer <VirtualHost>-Direktive verhalten.

Damit sehen die Matches wie folgt aus:

RewriteRule "/source" "/target" [R=301,L]
# Redirects /source               to /target
# Redirects /source123            to /target
# Redirects /source/12            to /target
# Redirects /source/?a            to /target
# Redirects /your-shiny/source/?a to /target

Fallstricke zum Selberknüpfen

Die Gefährlichkeit von Redirect wird dann offenbar, wenn man seine Funktionalität mit RedirectMatch und RewriteRule nachbaut. Denn tatsächlich benutzt Redirect implizit ein nicht wenig komplexes Pattern-Matching. Folgendes Beispiel zeigt, wie inhaltlich identische Regeln teilweise sehr unschuldig aussehen können:

Redirect      permanent "/source"      "/target"
RedirectMatch permanent "^/source(.*)" "/target$1"
RewriteRule             "^/source(.*)" "/target$1" [R=301,L]

Wie richte ich bombensichere Redirects für den Apache ein?

Um sich komplett sicher zu sein, von wo nach wo Redirects erzeugt werden, sollten nur die Redirect-Direktiven mit regulären Ausdrücken verwendet werden. Diese weisen von vorne herein darauf hin, dass ihre Konfiguration wohl überlegt sein möchte. Dabei helfen die Steuerzeichen für PCREs bzw. Perl-kompatible reguläre Ausdrücke:

  • ^: Stimmt mit dem Anfang einer Zeichenkette überein.
  • $: Stimmt mit dem Ende einer Zeichenkette überein.
  • ?: Das Zeichen bzw. die Gruppe vor dem ? ist optional.

Ein super-einfacher, direkter Redirect von exakt einer Anfrage-URL auf exakt eine Ziel-URL kann mittels Umschließung mit ^…$ realisiert werden:

RewriteEngine On
RewriteCond %{REQUEST_URI}
RewriteRule "^/source$" "/target" [R=301,L]
# Redirects /source to /target

Wenn Anfrage-URLs ohne und mit abschließenden / erlaubt sein sollen, kann dieses Muster um ein optionales / erweitert werden:

RewriteEngine On
RewriteCond %{REQUEST_URI}
RewriteRule "^/source(/)?$" "/target$1" [R=301,L]
# Redirects /source  to /target
# Redirects /source/ to /target/

Wenn ganze URL-Bereiche auf eine Ziel-URL umgeleitet werden sollen, kann der letzte Teil der URL explizit mit einem Muster erfasst werden. .* erfasst bei regulären Ausdrücken eine beliebige Anzahl von beliebigen Zeichen:

RewriteEngine On
RewriteCond %{REQUEST_URI}
RewriteRule "^/source/.*$" "/target/" [R=301,L]
# Redirects /source/        to /target/
# Redirects /source/example to /target/
# Redirects /source/?abc    to /target/

Und nicht zuletzt kann ein ganzer Bereich auch 1:1 auf einen anderen Bereich umgeleitet werden, indem man die überschüssigen URL-Teile der Anfrage-URL an die Ziel-URL weiterleitet:

RewriteEngine On
RewriteCond %{REQUEST_URI}
RewriteRule "^/source/(.*)$" "/target/$1" [R=301,L]
# Redirects /source/        to /target/
# Redirects /source/example to /target/example
# Redirects /source/?abc    to /target/?abc

Fazit

Die Einrichtung von Redirects im Apache-Webserver kann schnell unbeabsichtigte Folgen heraufbeschwören, und sogar den gefürchteten Redirect-Loop mit seiner bekannten Fehlermeldung „Too many redirects“ provozieren. Die Einrichtung mit Augenmaß und das Studium der Anleitung bewahrt euch davor, euren Internetauftritt unerreichbar zu machen.

Falls ihr Wünsche für Redirects in Form einer Liste „Anfrage → Ziel“ erhaltet, dürft ihr diese Liste nicht 1:1 in eure Redirect-Direktiven umwandeln, sondern solltet mit den obigen Beispielen eine präzisere Übersetzung durchführen.