Zum Inhalt springen

RegEx-Grundlagen für Apache-Regeln

Der Ausschnitt regulärer Ausdrücke, den RewriteRule und RedirectMatch tatsächlich brauchen: Anker, Zeichenklassen, Quantoren, Gruppen und die Unterschiede zwischen den beiden Direktiven.

Zuletzt geprüft: Gedacht für: Einstieg vor der ersten Rewrite-Regel

Das Wichtigste

  • RewriteRule sieht den Pfad ohne führenden Schrägstrich, RedirectMatch mit. Derselbe Ausdruck greift deshalb nicht in beiden Direktiven.
  • Ohne ^ und $ ist ein Muster ein Teilstring-Treffer. Genau daran scheitern die meisten zu breiten Regeln.
  • Der Punkt steht für ein beliebiges Zeichen. Ein Dateiname wie seite.htm gehört als seite\\.htm geschrieben.
  • Gruppen in Klammern landen als $1, $2 im Ziel. Aus einer RewriteCond holst du sie dagegen mit %1.

Für .htaccess-Regeln brauchst du keinen vollständigen Kurs in regulären Ausdrücken. Es reicht ein kleiner, klar umrissener Teil der Syntax, und der lässt sich in zwanzig Minuten lernen.

Anker: der wichtigste Teil

Ohne Anker ist ein Muster ein Teilstring-Treffer. Das ist die Ursache für praktisch jede Regel, die zu viel abfängt.

Mustertriffttrifft auch
produkteprodukte/alte-produkte-liste/, x/produkte.htm
^produkteprodukte/produkte-alt/
^produkte/produkte/schuhe/
^produkte/$nur produkte/

^ bindet an den Anfang, $ an das Ende. In einer RewriteRule ist der Anfang der Pfad ohne führenden Schrägstrich, weil Apache ihn vorher relativ zum Verzeichnis auflöst. In RedirectMatch ist er dagegen mit Schrägstrich. Dasselbe Muster verhält sich in beiden Direktiven also unterschiedlich:

RewriteRule   ^produkte/(.*)$  /shop/$1  [R=301,L]
RedirectMatch 301 ^/produkte/(.*)$  /shop/$1

Zeichenklassen und Quantoren

ZeichenBedeutung
.ein beliebiges Zeichen
\deine Ziffer
\wBuchstabe, Ziffer oder Unterstrich
[a-z0-9-]genau eines dieser Zeichen
[^/]alles ausser einem Schrägstrich
*null oder mehr
+eins oder mehr
?null oder eins
{2,4}zwei bis vier

Der Punkt ist die häufigste Falle. In seite.htm steht er für ein beliebiges Zeichen, das Muster trifft also auch seiteXhtm. Richtig ist seite\.htm.

Praktisches Beispiel für eine Artikel-URL mit numerischer ID:

# archiv-artikel_97_greylisting.htm  ->  /artikel/greylisting/
RewriteRule ^archiv-artikel_(\d+)_([a-z0-9_]+)\.htm$ /artikel/$2/ [R=301,L]

(\d+) fängt die ID, ([a-z0-9_]+) den sprechenden Teil. Beides steht anschliessend als $1 und $2 zur Verfügung.

Gruppen: $1 aus der Regel, %1 aus der Bedingung

Klammern erzeugen eine Gruppe. Woher du sie später holst, hängt davon ab, wo sie stand:

# Gruppe aus der RewriteCond -> %1
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L,NE]

# Gruppe aus der RewriteRule -> $1
RewriteRule ^blog/(.*)$ /artikel/$1 [R=301,L]

Diese Verwechslung erzeugt keine Fehlermeldung, sondern eine leere Ersetzung. Das Ergebnis ist eine Weiterleitung auf https:///pfad oder ein 500er, je nach Konstellation.

Wenn du eine Gruppe nur zum Zusammenfassen brauchst und nicht referenzieren willst, spart (?:...) den Zähler:

RewriteCond %{HTTP_HOST} ^(?:www\.)?alte-domain\.de$ [NC]

Alternativen und optionale Teile

Der senkrechte Strich trennt Alternativen, das Fragezeichen macht den vorangehenden Teil optional:

# fängt .htm und .html
RewriteRule ^doku_(htaccess|regex|modauth)\.html?$ /apache/htaccess/ [R=301,L]

html? heisst: htm, gefolgt von einem optionalen l. Die Alternativen in der ersten Gruppe sind bewusst aufgezählt statt mit .* erschlagen – so kann die Regel nichts abfangen, was du nicht kennst.

Greedy oder nicht

.* ist gierig und nimmt so viel wie möglich. Bei verschachtelten Pfaden führt das zu falschen Treffern:

# nimmt bei /a/b/c/ alles bis zum letzten Schrägstrich
RewriteRule ^(.*)/(.*)$ ...

# nimmt bei /a/b/c/ nur bis zum ersten
RewriteRule ^([^/]+)/(.*)$ ...

[^/]+ ist in Pfadregeln fast immer die bessere Wahl als .*, weil es an Verzeichnisgrenzen stoppt.

Testen, bevor es live geht

Reguläre Ausdrücke lassen sich ohne Apache prüfen. Für einen schnellen Gegentest reicht grep mit erweiterten Ausdrücken:

# trifft das Muster die erwarteten Alt-URLs - und nur die?
grep -E '^archiv-artikel_[0-9]+_[a-z0-9_]+\.htm$' alt-urls.txt

Nimm dafür die echte Alt-URL-Liste aus Logfile oder Backlink-Export. Ein Muster, das gegen fünf ausgedachte Beispiele funktioniert, sagt wenig über 3.000 gewachsene URLs.

Häufige Fragen

Warum greift meine Regel auf mehr URLs als gedacht?

Vermutlich fehlen die Anker. Ohne ^ am Anfang und $ am Ende sucht Apache das Muster irgendwo im Pfad. Die Regel ^produkte matcht damit auch /alte-produkte-liste/.

Was ist der Unterschied zwischen $1 und %1?

Mit dem Dollarzeichen greifst du auf Gruppen aus dem Muster der RewriteRule zu, mit dem Prozentzeichen auf Gruppen aus der zuletzt ausgewerteten RewriteCond. Wer die beiden verwechselt, bekommt ein leeres Ergebnis statt einer Fehlermeldung.

Muss ich Sonderzeichen im Muster maskieren?

Punkt, Fragezeichen, Plus, Sternchen, Klammern und der senkrechte Strich haben in regulären Ausdrücken eine Bedeutung. Sollen sie wörtlich gelten, gehört ein Backslash davor. Der Schrägstrich braucht in Apache keine Maskierung.

Ist die Auswertung von Gross- und Kleinschreibung abhängig?

Ja, standardmässig unterscheidet Apache. Mit dem Flag [NC] wird die Regel unempfindlich. Bei Host-Prüfungen ist [NC] fast immer richtig, bei Pfaden solltest du bewusst entscheiden.