Title: URL-Manipulationen
Weitere Themen

Erstfassung von
Ralf S. Engelschall <[EMAIL PROTECTED]>
Dezember 1997

Diese Ausführungen ergänzen die Beschreibung des Moduls mod_rewrite. . Sie erläutern, wie mit diesem Apache-Modul typische URL-Probleme gelöst werden können, mit denen ein Webmaster in der alltäglichen Praxis konfrontiert wird. Detaillierte Beschreibungen erklären, wie jedes einzelne Problem durch Konfiguration eines entsprechenden URL-Rewriting-Regelsatzes behoben werden kann.

<code>mod_rewrite</code> - Einführung

Das Apache-Modul mod_rewrite ist ein "Alleskönner". Dieses ausgeklügelte Modul bietet leistungsstarke Möglichkeiten für alle Arten von URL-Manipulationen. Im Gegenzug muss man jedoch ein hohes Maß an Komplexität in Kauf nehmen, denn mod_rewrite ist für den Neuling weder leicht verständlich noch einfach in der Verwendung. Selbst Apache-Experten entdecken zuweilen neue Situationen, in denen mod_rewrite helfen kann.

Leger ausgedrückt, graben Sie sich beim ersten Einsatz von mod_rewrite entweder selbst eine Grube, die Sie von der weiteren Verwendung des Moduls abhält, oder schwören bis ans Ende Ihrer Tage auf dessen Stärke. Diese Ausführungen sollen dem Leser einige erste Erfolgserlebnisse verschaffen, indem fertige Lösungen vorgestellt werden, um so den zweiten Fall zu vermeiden.

Praktische Lösungen

Es folgen zahlreiche praktische Beispiele, die speziell entwickelt oder von anderen übernommen wurden. Sie sollen die ungeahnten Möglichkeiten für URL-Manipulationen demonstrieren.

ACHTUNG: Je nach der vorliegenden Server-Konfiguration kann es erforderlich sein, geringfügige Veränderungen an den Beispielen vorzunehmen, beispielsweise das [PT]-Flag hinzuzufügen, wenn zusätzlich die Module mod_alias und mod_userdir verwendet werden usw. Gegebenenfalls muss ein Regelsatz für den .htaccess-Kontext anstatt für den Serverkontext umgeschrieben werden. Versuchen Sie immer zu verstehen, was ein bestimmter Regelsatz wirklich auslöst, bevor sie ihn verwenden. So vermeiden Sie Probleme.
URL-Layout
Vorschriftsmäßige URLs
Beschreibung:

Bei einigen Webservern gibt es mehr als eine URL für eine Ressource. Normalerweise sind dies die vorschriftsmäßigen URLs (die tatsächlich benutzt und weitergereicht werden sollten) und die Abkürzungen, internen URLs usw. Unabhängig davon, welche URL für die Anfrage des Benutzers benutzt wird, sollte dieser nur die vorschriftsmäßigen URLs sehen.

Lösung:

Dies wird mit einer externen HTTP-Umleitung für alle nicht vorschriftsmäßigen URLs in der Browseransicht und für alle nachfolgenden Anfragen behoben. Im Beispiel wird /~user durch das vorschriftsmäßige /u/user ersetzt und ein fehlender nachgestellter Schrägstrich für /u/user ergänzt.

RewriteRule   ^/~([^/]+)/?(.*)    /u/$1/$2  [R]
RewriteRule   ^/([uge])/([^/]+)$  /$1/$2/   [R]

    
Vorschriftsmäßige Hostnamen
Beschreibung:
...
Lösung:
RewriteCond %{HTTP_HOST}   !^fully\.qualified\.domain\.name [NC]
RewriteCond %{HTTP_HOST}   !^$
RewriteCond %{SERVER_PORT} !^80$
RewriteRule ^/(.*)         http://fully.qualified.domain.name:%{SERVER_PORT}/$1 [L,R]
RewriteCond %{HTTP_HOST}   !^fully\.qualified\.domain\.name [NC]
RewriteCond %{HTTP_HOST}   !^$
RewriteRule ^/(.*)         http://fully.qualified.domain.name/$1 [L,R]
Verschobene <code>DocumentRoot</code>
Beschreibung:

Normalerweise bezieht sich die DocumentRoot des Webservers direkt auf die URL /. Häufig sind diese Daten aber nicht von höchster Priorität sondern vielleicht nur eine Einheit aus einer Menge von Datenpools. Bei Intranet-Sites kann es beispielsweise /e/www/ (die Homepage für WWW), /e/sww/ (die Homepage für das Intranet) usw. geben. Da die Daten der DocumentRoot sich immer unter /e/www/ befinden, muss sichergestellt werden, das alle Inline-Bilder und anderen Dinge aus dem Datenpool mit nachfolgenden Anfragen funktionieren.

Lösung:

Die URL / wird einfach nach /e/www/ umgeleitet. Das mag zwar trivial erscheinen, ist es aber nur Dank dem Modul mod_rewrite. Denn der übliche alte Mechanismus der URL-Aliase (siehe mod_alias und verwandte Module) nahm nur einen Abgleich des Präfix vor. Damit ist eine solche Umleitung nicht möglich, weil DocumentRoot ein Präfix für alle URLs ist. Mit mod_rewrite wird es wirklich einfach:

RewriteEngine on
RewriteRule   ^/$  /e/www/  [R]
Nachgestellter Schrägstrich
Beschreibung:

Jeder Webmaster kann ein Lied vom Problem mit dem nachgestellten Schrägstrich URLs mit Verzeichnisverweisen singen. Fehlen sie, stellt der Server einen Fehler fest, weil bei Angabe von /~quux/foo an Stelle von /~quux/foo/ der Server nach einer Datei namens foo sucht. Da es sich aber um ein Verzeichnis handelt, meldet er einen Fehler. In den meisten Situationen versucht er selbst, den Fehler zu beheben, manchmal muss dieser Mechanismus jedoch emuliert werden. Beispielsweise wenn sehr viele komplizierte URL-Manipulationen für CGI-Skripte usw. durchgeführt wurden.

Lösung:

Gelöst wird dieses subtile Problem dadurch, dass der Server den Schrägstrich automatisch hinzufügt. Damit dies korrekt geschieht, muss eine externe Umleitung verwendet werden, damit der Browser nachfolgende Bilder usw. korrekt anfordert. Mit einer internen Umleitung würde das nur für die Verzeichnisseite funktionieren, würde jedoch fehlschlagen, wenn in diese Seite Bilder mit relativen URLs eingebunden würden, weil der Browser ein Inline-Objekt anfordern würde. Eine Anfrage nach image.gif in /~quux/foo/index.html würde ohne externe Umleitung beispielsweise zu /~quux/image.gif!

Der Trick wird wie folgt realisiert:

RewriteEngine  on
RewriteBase    /~quux/
RewriteRule    ^foo$  foo/  [R]

Wem das zu umständlich ist, der kann auch kann folgendes in die oberste .htaccess-Datei des Stammverzeichnisses setzen. Allerdings ist damit ein wenig zusätzlicher Rechenaufwand verbunden.

RewriteEngine  on
RewriteBase    /~quux/
RewriteCond    %{REQUEST_FILENAME}  -d
RewriteRule    ^(.+[^/])$           $1/  [R]
Webcluster durch homogenes URL-Layout
Beschreibung:

Es soll ein homogenes und konsistentes URL-Layout für alle WWW-Server eines Intranet-Webclusters erzeugt werden, d.h. alle URLs (per Definition serverlokal und daher serverabhängig!) werden serverunabhängig. Erreicht werden soll ein konsistentes severunabhängiges Layout für den WWW-Namespace: Keine URL darf einen physisch korrekten Zielserver enthalten. Der Cluster selbst soll automatisch zum physischen Ziel geleiten.

Lösung:

Zum einen stammt das Wissen über die Zielserver aus (verteilten) externen Maps mit Informationen zu den Benutzern, Gruppen und Entitäten. Sie haben das Format: form

Benutzer1  Server_von_Benutzer1
Benutzer2  Server_von_Benutzer2
:      :

Sie werden in die Dateien map.xxx-zum-host geschrieben. Zum anderen müssen alle Server angewiesen werden, URLs folgender Form

/u/Benutzer/Pfad
/g/Gruppe/Pfad
/e/Entität/Pfad

nach

http://physischer-Host/u/Benutzer/Pfad
http://physischer-Host/g/Gruppe/Pfad
http://physischer-Host/e/Entität/Pfad

umzuleiten, wenn die URL kein lokal zulässiger Server ist. Der folgende Regelsatz bewerkstelligt dies mit Hilfe der Map-Dateien (vorausgesetzt, server0 ist ein Standardserver, der benutzt wird, wenn ein Benutzer keine Eintragung im Map besitzt):

RewriteEngine on

RewriteMap      user-to-host   txt:/path/to/map.user-to-host
RewriteMap     group-to-host   txt:/path/to/map.group-to-host
RewriteMap    entity-to-host   txt:/path/to/map.entity-to-host

RewriteRule   ^/u/([^/]+)/?(.*)   http://${user-to-host:$1|server0}/u/$1/$2
RewriteRule   ^/g/([^/]+)/?(.*)  http://${group-to-host:$1|server0}/g/$1/$2
RewriteRule   ^/e/([^/]+)/?(.*) http://${entity-to-host:$1|server0}/e/$1/$2

RewriteRule   ^/([uge])/([^/]+)/?$          /$1/$2/.www/
RewriteRule   ^/([uge])/([^/]+)/([^.]+.+)   /$1/$2/.www/$3\
Stammverzeichnisse auf unterschiedliche Webserver verschieben
Beschreibung:

Viele Webmasters suchten nach einer Lösung für folgende Situation: Alle Stammverzeichnisse auf einem Webserver sollten auf einen anderen Webserver umgeleitet werden. Normalerweise ist das erforderlich, wenn ein neuer Webserver als Ersatz für einen alten eingerichtet werden soll.

Lösung:

Die Lösung ist mit mod_rewrite trivial. Auf dem alten Webserver werden alle /~user/Pfad-URLs nach http://NeuerServer/~user/Pfad umgeleitet.

RewriteEngine on
RewriteRule   ^/~(.+)  http://NeuerServer/~$1  [R,L]
Strukturierte Stammverzeichnisse
Beschreibung:

Sites mit Tausenden von Benutzern verwenden häufig ein strukturiertes Stammverzeichnis-Layout, d.h. jedes Stammverzeichnis befindet sich in einem Unterverzeichnis, das beispielsweise mit dem ersten Buchstaben des Benutzernamens beginnt. /~foo/Pfad ist /home/f/foo/.www/Pfad und /~bar/Pfad ist /home/b/bar/.www/Pfad.

Lösung:

Mit folgendem Regelsatz wird die Tilde in den URLs gemäß dem oben beschriebenen Layout expandiert.

RewriteEngine on
RewriteRule   ^/~(([a-z])[a-z0-9]+)(.*)  /home/$2/$1/.www$3
Reorganisation des Dateisystems
Beschreibung:

Das nächste Beispiel ist sehr extrem: Eine Anwendung, die die im Verzeichniskontext starken Gebrauch von RewriteRules macht, um eine elegante Erscheinung im Web zu erreichen, ohne dass die Datenstruktur davon berührt oder dem angepasst wird. Zum Hintergrund: net.sw ist ein Archiv mit einer vom Autor seit 1992 angelegten Sammlung frei verfügbarer Unix-Softwarepaketen, die in einer tiefen Verzeichnishierarchie gespeichert sind:

drwxrwxr-x   2 netsw  users    512 Aug  3 18:39 Audio/
drwxrwxr-x   2 netsw  users    512 Jul  9 14:37 Benchmark/
drwxrwxr-x  12 netsw  users    512 Jul  9 00:34 Crypto/
drwxrwxr-x   5 netsw  users    512 Jul  9 00:41 Database/
drwxrwxr-x   4 netsw  users    512 Jul 30 19:25 Dicts/
drwxrwxr-x  10 netsw  users    512 Jul  9 01:54 Graphic/
drwxrwxr-x   5 netsw  users    512 Jul  9 01:58 Hackers/
drwxrwxr-x   8 netsw  users    512 Jul  9 03:19 InfoSys/
drwxrwxr-x   3 netsw  users    512 Jul  9 03:21 Math/
drwxrwxr-x   3 netsw  users    512 Jul  9 03:24 Misc/
drwxrwxr-x   9 netsw  users    512 Aug  1 16:33 Network/
drwxrwxr-x   2 netsw  users    512 Jul  9 05:53 Office/
drwxrwxr-x   7 netsw  users    512 Jul  9 09:24 SoftEng/
drwxrwxr-x   7 netsw  users    512 Jul  9 12:17 System/
drwxrwxr-x  12 netsw  users    512 Aug  3 20:15 Typesetting/
drwxrwxr-x  10 netsw  users    512 Jul  9 14:08 X11/

Im Juli 1996 sollte das Archiv über eine passende Web-Schnittstelle öffentlich gemacht werden. "Passend" bedeutet in diesem Zusammenhang, dass eine unmittelbares Durchsuchen der Verzeichnishierarchie möglich sein sollte, ohne dass irgendwelche Veränderungen an der Hierarchie vorgenommen oder CGI-Skripte an die Spitze der Hierarchie gestellt werden sollten. Grund dafür war die Tatsache, dass diese Struktur später auch über FTP zugänglich und daher frei von Web- oder CGI-Elementen sein sollte.

Lösung:

Die Lösung besteht aus zwei Teilen: Der erste ist eine Reihe von CGI-Skripten, die alle Seiten auf allen Verzeichnisebenen im Vorbeigehen erzeugen. Sie werden im Verzeichnis /e/netsw/.www/ wie folgt platziert:

-rw-r--r--   1 netsw  users    1318 Aug  1 18:10 .wwwacl
drwxr-xr-x  18 netsw  users     512 Aug  5 15:51 DATA/
-rw-rw-rw-   1 netsw  users  372982 Aug  5 16:35 LOGFILE
-rw-r--r--   1 netsw  users     659 Aug  4 09:27 TODO
-rw-r--r--   1 netsw  users    5697 Aug  1 18:01 netsw-about.html
-rwxr-xr-x   1 netsw  users     579 Aug  2 10:33 netsw-access.pl
-rwxr-xr-x   1 netsw  users    1532 Aug  1 17:35 netsw-changes.cgi
-rwxr-xr-x   1 netsw  users    2866 Aug  5 14:49 netsw-home.cgi
drwxr-xr-x   2 netsw  users     512 Jul  8 23:47 netsw-img/
-rwxr-xr-x   1 netsw  users   24050 Aug  5 15:49 netsw-lsdir.cgi
-rwxr-xr-x   1 netsw  users    1589 Aug  3 18:43 netsw-search.cgi
-rwxr-xr-x   1 netsw  users    1885 Aug  1 17:41 netsw-tree.cgi
-rw-r--r--   1 netsw  users     234 Jul 30 16:35 netsw-unlimit.lst

Das Unterverzeichnis DATA/ enthält die oben aufgeführte Verzeichnisstruktur, d.h. die tatsächlichen net.sw-Elemente und wird automatisch in gewissen Zeitabständen über rdist aktualisiert. Der zweite Teil stellt das Problem dar: Wie werden diese beiden Strukturen zu einem eleganten URL-Baum miteinander verknüpft? Das Verzeichnis DATA/ soll vorm Benutzer verborgen bleiben, während die entsprechenden CGI-Skripte für die unterschiedlichen URLs ausgeführt werden. So sieht die Lösung aus: Zuerst werden folgende Zeilen in die Konfigurationsdatei für den Verzeichniskontext in der DocumentRoot des Servers eingefügt, um die angegebene URL /net.sw/ in den internen Pfad /e/netsw umzuwandeln:

RewriteRule  ^net.sw$       net.sw/        [R]
RewriteRule  ^net.sw/(.*)$  e/netsw/$1

Die erste Regel ist für Anfragen bestimmt, denen der nachgestellte Schrägstrich fehlt. Die zweite Regel ist für die eigentliche Arbeit zuständig. Anschließend folgt die Konfiguration, die in der Konfigurationsdatei des Verzeichniskontext /e/netsw/.www/.wwwacl bleibt:

Options       ExecCGI FollowSymLinks Includes MultiViews

RewriteEngine on

#  Erreichbar über den Präfix/net.sw/ 
RewriteBase   /net.sw/

#  Umschreiben des Stammverzeichnisses für das
#  CGI-Skript
RewriteRule   ^$                       netsw-home.cgi     [L]
RewriteRule   ^index\.html$            netsw-home.cgi     [L]

#  Unterverzeichnisse entfernen, wenn 
#  der Browser über Verzeichnisseiten anfragt.
RewriteRule   ^.+/(netsw-[^/]+/.+)$    $1                 [L]

#  Das Umschreiben für lokale Dateien aufheben
RewriteRule   ^netsw-home\.cgi.*       -                  [L]
RewriteRule   ^netsw-changes\.cgi.*    -                  [L]
RewriteRule   ^netsw-search\.cgi.*     -                  [L]
RewriteRule   ^netsw-tree\.cgi$        -                  [L]
RewriteRule   ^netsw-about\.html$      -                  [L]
RewriteRule   ^netsw-img/.*$           -                  [L]

#  Alles Übrige ist ein Unterverzeichnis, das von einem
#  anderen CGI-Skript behandelt wird.
RewriteRule   !^netsw-lsdir\.cgi.*     -                  [C]
RewriteRule   (.*)                     netsw-lsdir.cgi/$1

Hinweise zur Interpretation:

  1. Beachten Sie, dass das L-Flag (last) im vorerden Teil (kein Substitutionsfeld ('-')).
  2. Beachten Sie das !-Zeichen (nicht) und das C-Flag (Kette) in der ersten Regel im letzten Teil.
  3. Beachten Sie das Muster zum universellen Abfangen in der letzten Regel.
NCSA-Bild-Map für <code>mod_imap</code>
Beschreibung:

Beim Wechsel vom NCSA-Webserver zum moderneren Apache-Webserver wird vielfach ein eleganter Übergang gewünscht. Seiten, die das alte NCSA-imagemap-Programm verwenden, sollen unter Apache mit dem modernen mod_imap funktionieren. Leider gibt es sehr viele Hyperlinks, die auf über /cgi-bin/imagemap/path/to/page.map auf das imagemap-Programm verweisen, was unter Apache /path/to/page.map lauten muss.

Lösung:

Mit einer globalen Regel wird der Präfix nebenbei für alle Anfragen entfernt:

RewriteEngine  on
RewriteRule    ^/cgi-bin/imagemap(.*)  $1  [PT]
Seiten in mehreren Verzeichnissen suchen
Beschreibung:

Manchmal muss der Webserver in mehreren Verzeichnissen nach Seiten suchen. MultiViews oder andere Verfahren können in diesem Fall nicht helfen.

Lösung:

Mit einem expliziten Regelsatz wird in den Verzeichnissen nach den Dateien gesucht.

RewriteEngine on

#   Zuerst wird wie gewohnt gesucht
#   ...und falls nicht gefunden, abgebrochen:
RewriteCond         /your/docroot/dir1/%{REQUEST_FILENAME}  -f
RewriteRule  ^(.+)  /your/docroot/dir1/$1  [L]

#   Als zweites wird in pub/... gesucht
#   ...und falls nicht gefunden, abgebrochen:
RewriteCond         /your/docroot/dir2/%{REQUEST_FILENAME}  -f
RewriteRule  ^(.+)  /your/docroot/dir2/$1  [L]

#   Andernfalls folgen andere Alias- oder ScriptAlias-Direktiven
#   usw.
RewriteRule   ^(.+)  -  [PT]
Umgebungsvariablen nach URL-Teilen setzen
Beschreibung:

Statusinformationen werden zwischen Anfragen aufbewahrt und mit der URL verschlüsselt. Dafür soll aber kein CGI-Wrapper für alle Seiten eingesetzt werden, der lediglich diese Informationen entnimmt.

Lösung:

Mit einer Manipulationsregel werden die Statusinformationen herausgelöst und in einer Umgebungsvariablen gespeichert, die später über XSSI oder CGI dereferenziert werden kann. Auf diese Weise wird die URL /foo/S=java/bar/ in /foo/bar/ umgewandelt und die Umgebungsvariable STATUS auf den Wert java gesetzt.

RewriteEngine on
RewriteRule   ^(.*)/S=([^/]+)/(.*)    $1/$3 [E=STATUS:$2]
Virtuelle Benutzer-Hosts
Beschreibung:

Angenommen, es soll www.username.host.domain.com für die Homepage von username über DNS A-Records für den gleichen Rechner bereitgestellt werden, ohne dass der Rechner über virtuelle Hosts verfügt.

Lösung:

Für HTTP/1.0-Anfragen gibt es keine Lösung, aber für HTTP/1.1-Anfragen mit einem Host: HTTP-Header kann mit folgendem Regelsatz http://www.username.host.com/Pfad intern in /home/username/Pfad umgeschrieben werden:

RewriteEngine on
RewriteCond   %{HTTP_HOST}                 ^www\.[^.]+\.host\.com$
RewriteRule   ^(.+)                        %{HTTP_HOST}$1          [C]
RewriteRule   ^www\.([^.]+)\.host\.com(.*) /home/$1$2
Stammverzeichnisse für Fremde umleiten
Beschreibung:

Stammverzeichnis-URLs sollen zum Webserver www.somewhere.com umgeleitet werden, wenn der anfragende Benutzer nicht zur gleichen lokalen Domäne ourdomain.com gehört. Das ist manchmal im virtuellen Host-Kontext notwendig.

Lösung:

Lediglich einen Manipulationsbedingung:

RewriteEngine on
RewriteCond   %{REMOTE_HOST}  !^.+\.ourdomain\.com$
RewriteRule   ^(/~.+)         http://www.somewhere.com/$1 [R,L]
Fehlgeschlagene URLs zu anderen Webservern umleiten
Beschreibung:

Eine häufig gestellte Frage zur URL-Manipulationen bezieht sich auf die Umleitung fehlgeschlagener Anfragen an Webserver A an den Webserver B. Normalerweise geschieht dies über ErrorDocument-CGI-Skripte in Perl, aber es gibt auch eine mod_rewrite-Lösung. Allerdings ist sie nicht so schnell wie ein ErrorDocument-CGI-Skript.

Lösung:

Die erste Lösung hat die besseren Leistungen, bietet aber weniger Flexibilität und ist weniger fehlersicher:

RewriteEngine on
RewriteCond   /your/docroot/%{REQUEST_FILENAME} !-f
RewriteRule   ^(.+)                             http://webserverB.dom/$1

Sie funktioniert nur für Seiten innerhalb der DocumentRoot. Zwar können weitere Bedingungen hinzugefügt werden (z.B. für Stammverzeichnisse usw.), es gibt jedoch noch eine bessere Variante:

RewriteEngine on
RewriteCond   %{REQUEST_URI} !-U
RewriteRule   ^(.+)          http://webserverB.dom/$1

Hier wird die Möglichkeit zur Vorabsuche einer URL von mod_rewrite genutzt, was für alle Arten von URLs funktioniert und sicher ist. Diese Variante belastet allerdings den Webserver stärker, weil für jede Anfrage eine weitere interne Unteranfrage erforderlich ist. Wird der Webserver mit einer leistungsstarken CPU ausgeführt, kann diese Variante gewählt werden. Bei einem langsamen Rechner sollte die erste Methode noch besser ein ErrorDocument-CGI-Skript vorgezogen werden .

Erweiterte Umleitung
Beschreibung:

Manchmal ist mehr Kontrolle hinsichtlich der Zeichenersetzung in URLs bei Umleitungen erforderlich. Normalerweise ersetzt die Escape-Funktion des Apache-Kerns auch Anker, d.h. URLs wie "url#anchor". Bei Umleitungen mit mod_rewrite kann das nicht unmittelbar genutzt werden, weil die uri_escape()-Funktion des Apache auch das #-Zeichen ersetzen würde. Wie kann eine solche URL umgeleitet werden?

Lösung:

Als Ausweg dient ein NPH-CGI-Skript, das die Umleitung selbst durchführt. Da keine Ersetzung erfolgt (NPH=non-parseable headers). Zuerst wird das neue URL-Schema xredirect: mit der folgenden Zeile in der Konfiguration des Serverkontexts eingeführt (es sollte sich um eine der letzten Rwrite-Regel handeln):

RewriteRule ^xredirect:(.+) /path/to/nph-xredirect.cgi/$1 \
            [T=application/x-httpd-cgi,L]

Alle URLs mit dem Präfixxredirect: werden an das Programm nph-xredirect.cgi weitergereicht. Dieses Programm sieht folgendermaßen aus:

#!/Perl-Pfad
##
##  nph-xredirect.cgi -- NPH/CGI-Skript für erweiterte Umleitungen
##  Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved.
##

$| = 1;
$url = ""

print "HTTP/1.0 302 Moved Temporarily\n";
print "Server: $ENV{'SERVER_SOFTWARE'}\n";
print "Location: $url\n";
print "Content-type: text/html\n";
print "\n";
print "<html>\n";
print "<head>\n";
print "<title>302 Moved Temporarily (EXTENDED)</title>\n";
print "</head>\n";
print "<body>\n";
print "<h1>Moved Temporarily (EXTENDED)</h1>\n";
print "The document has moved <a HREF=""
print "</body>\n";
print "</html>\n";

##EOF##

Mit diesem Programm können alle URL-Schemata umgeleitet werden, einschließlich derjenigen, die von mod_rewrite nicht unmittelbar akzeptiert werden. Mit der nächsten Zeile kann beispielsweise eine Umleitung nach news:newsgroup erfolgen:

RewriteRule ^anyurl  xredirect:news:newsgroup
Hinweis: Die Regel darf nicht mit den Flags [R] oder [R,L] versehen werden, weil xredirect: später vom der speziellen Regel für das Weiterreichen expandiert werden muss.
Archivzugriffs-Multiplexer
Beschreibung:

Kennen Sie das CPAN (Comprehensive Perl Archive Network) unter http://www.perl.com/CPAN? Dies ist eine Umleitung zu einem von mehreren über die Welt verteilten FTP-Servern mit einem CPAN-Mirror, der sich in ungefährer Nähe des anfragenden Clients befindet. In diesem Zusammenhang kann von einem FTP-Zugriffs-Multiplexing-Service gesprochen werden, der mit CGI-Skripten arbeitet. Wie lässt sich so etwas mit mod_rewrite implementieren?

Lösung:

Zum Ersten ist anzumerken, dass ab der Version 3.0.0 mod_rewrite auch das ftp:-Schema für Umleitungen verwenden kann. Zum anderen kann die Annäherung an den Standort über ein RewriteMap über die oberste Domäne des Clients erfolgen. Mit einem komplizierten verketteten Regelsatz kann diese oberste Domäne als Schlüssel für das Multiplexing-Map verwendet werden.

RewriteEngine on
RewriteMap    multiplex                txt:/path/to/map.cxan
RewriteRule   ^/CxAN/(.*)              %{REMOTE_HOST}::$1                 [C]
RewriteRule   ^.+\.([a-zA-Z]+)::(.*)$  ${multiplex:$1|ftp.default.dom}$2  [R,L]
##
##  map.cxan -- Multiplexing-Map für CxAN
##

de        ftp://ftp.cxan.de/CxAN/
uk        ftp://ftp.cxan.uk/CxAN/
com       ftp://ftp.cxan.com/CxAN/
 :
##EOF##
Zeitabhängige URL-Manipulationen
Beschreibung:

Bei zeitabhängigen Inhalten verwenden viele Webmaster weiterhin CGI-Skripte, die beispielsweise zu speziellen Seiten umleiten. Wie kann dies mit mod_rewrite geschehen?

Lösung:

Es gibt viele Variablen mit der Bezeichnung TIME_xxx für Manipulationsbedingungen. In Verbindung mit dem speziellen lexikografischen Vergleichsmustern <STRING, >STRING und =STRING lassen sich zeitabhängige Umleitungen durchführen:

RewriteEngine on
RewriteCond   %{TIME_HOUR}%{TIME_MIN} >0700
RewriteCond   %{TIME_HOUR}%{TIME_MIN} <1900
RewriteRule   ^foo\.html$             foo.day.html
RewriteRule   ^foo\.html$             foo.night.html

Hiermit wird der Inhalt von foo.day.html unter der URL foo.html vom 07:00-19:00 und während der übrigen Zeit der Inhalt von foo.night.html bereitgestellt. Eine ganz nette Möglichkeit für die Homepage...

Abwärtskompatibilität für die Migration von YYYY auf XXXX
Beschreibung:

Wie können URLs nach dem Übergang von Dokument.YYYY zum Dokument.XXXX abwärtskompatibel bleiben (noch virtuell vorhanden sein), beispielsweise nach der Umwandlung von .html- in .phtml-Dateien?

Lösung:

Der Name wird einfach in den Basisnamen umgeschrieben und das Vorhandensein der neuen Dateinamenserweiterung überprüft. Ist sie vorhanden, wird diese Name genommen, andernfalls wird die URL wieder in den ursprünglichen Zustand versetzt.

#   Regelsatz für Abwärtskompatibilität
#   Umschreiben von document.html zu document.phtml
#   wenn (und nur dann) das document.phtml vorhanden
#   und document.html nicht mehr vorhanden ist.
RewriteEngine on
RewriteBase   /~quux/
#   Basisname ermitteln und berücksichtigen:
RewriteRule   ^(.*)\.html$              $1      [C,E=WasHTML:yes]
#   Falls vorhanden zu document.phtml umschreiben
RewriteCond   %{REQUEST_FILENAME}.phtml -f
RewriteRule   ^(.*)$ $1.phtml                   [S=1]
#   Andernfalls Rückverwandlung des Basisnamens
RewriteCond   %{ENV:WasHTML}            ^yes$
RewriteRule   ^(.*)$ $1.html
Inhalts-Handling
Aus alt mach Neu (intern)
Beschreibung:

Angenommen eine Seite wurde kürzlich von foo.html in bar.html umbenannt und aus Gründen der Abwärtskompatibilität soll die alte URL weiter zur Verfügung stehen. Die Benutzer der alten URL sollen nicht einmal bemerken, dass die Seite umbenannt wurde.

Lösung:

Die alte URL wird intern mit der folgenden Regel in die neue umgeschrieben:

RewriteEngine  on
RewriteBase    /~quux/
RewriteRule    ^foo\.html$  bar.html
Aus alt mach neu (extern)
Beschreibung:

Nehmen wir noch einmal an, eine Seite wurde kürzlich von foo.html in bar.html umbenannt und aus Gründen der Abwärtskompatibilität soll die alte URL weiter zur Verfügung stehen. Diesmal sollen die Benutzer der alten URL darauf hingewiesen werden, dass es eine neue URL gibt. Im Browser soll also die neue Adresse angezeigt werden.

Lösung:

Es wird eine HTTP-Umleitung zur neuen URL erzwungen, die zu einer Änderung in der Adressanzeige des Browsers führt und somit für den Benutzer sichtbar ist:

RewriteEngine  on
RewriteBase    /~quux/
RewriteRule    ^foo\.html$  bar.html  [R]
Browserabhängiger Inhalt
Beschreibung:

Zumindest bei Seiten auf oberster Ebene ist es manchmal wichtig, den Inhalt in Abhängigkeit vom Browser optimal darzustellen. Das bedeutet, dass aktuellste Version der Netscape-Varianten, eine minimale Version der Lynx-Browser und eine durchschnittliche Version aller übrigen Browser berücksichtigt werden müssen.

Lösung:

Die Content-Negotiation kann nicht benutzt werden, weil die Browser ihren Typ nicht in der Form angeben. Stattdessen muss der HTTP-Header User-Agent berücksichtigt werden. Die folgende Bedingung bewirkt folgendes: Wenn der HTTP-Header User-Agent mit Mozilla/3 beginnt, wird die Seite foo.html zu foo.NS.html umgeschrieben und die Manipulation abgebrochen. Handelt es sich um den Lynx- oder Mozilla-Browser der Version 1 oder 2, wird die URL zu foo.20.html. Alle übrigen Browser erhalten die Seite foo.32.html. Dies geschieht mit folgendem Regelsatz:

RewriteCond %{HTTP_USER_AGENT}  ^Mozilla/3.*
RewriteRule ^foo\.html$         foo.NS.html          [L]

RewriteCond %{HTTP_USER_AGENT}  ^Lynx/.*         [OR]
RewriteCond %{HTTP_USER_AGENT}  ^Mozilla/[12].*
RewriteRule ^foo\.html$         foo.20.html          [L]

RewriteRule ^foo\.html$         foo.32.html          [L]
Dynamischer Mirror
Beschreibung:

Wenn Sie ansprechende Webseiten anderer Hosts in den eigenen Namespace stellen möchten, dann würden Sie für FTP-Server das Programm mirror verwenden, das eine aktuelle Kopie der entfernten Daten auf dem eigenen Server unterhält. Bei einem Webserver kann hierfür das Programm webcopy benutzt werden, das über HTTP in ähnlicher Wiese funktioniert. Beide Verfahren haben jedoch einen Nachteil: Die lokale Kopie ist nur so aktuell, wie häufig das Programm ausgeführt wurde. Günstiger wäre es, wenn die Spiegelung nicht statisch und explizit vorgenommen würde, sondern dynamisch mit bei Bedarf automatisch aktualisierten Daten erfolgen würde.

Lösung:

Um dies zu erreichen, wird die entfernte Webseite oder auch der gesamte Webbereich dem eigenen Namespace mit der Proxy Throughput-Eigenschaft zugeordnet ([P]-Flag):

RewriteEngine  on
RewriteBase    /~quux/
RewriteRule    ^hotsheet/(.*)$  http://www.tstimpreso.com/hotsheet/$1  [P]
RewriteEngine  on
RewriteBase    /~quux/
RewriteRule    ^usa-news\.html$   http://www.quux-corp.com/news/index.html  [P]
Reverser dynamischer Mirror
Beschreibung:
...
Lösung:
RewriteEngine on
RewriteCond   /mirror/of/remotesite/$1           -U
RewriteRule   ^http://www\.remotesite\.com/(.*)$ /mirror/of/remotesite/$1
Fehlende Daten im Intranet suchen
Beschreibung:

Dies ist eine trickreiche Möglichkeit für einen virtuellen firmeninternen (externen) Internet-Webserver (www.quux-corp.dom), wobei die Daten tatsächlich auf einem (internen) Intranet-Webserver (www2.quux-corp.dom) unterhalten werden, der von einer Firewall geschützt wird. Der Trick ist, dass die vom externen Webserver angeforderten Daten auf dem internen Server sofort zu finden sind.

Lösung:

Zuerst muss sichergestellt werden, dass interne Webserver geschützt ist und dass nur der externe Webserver Daten auf ihm suchen darf. Bei einer Firewall mit Paketfilterung könnte beispielsweise folgender Regelsatz formuliert werden:

ALLOW Host www.quux-corp.dom Port >1024 --> Host www2.quux-corp.dom Port 80
DENY  Host *                 Port *     --> Host www2.quux-corp.dom Port 80

Sie müssen lediglich eine Anpassung für Ihre Konfiguration vornehmen. Als nächstes können die mod_rewrite-Regeln eingerichtet werden, welche die fehlenden Daten im Hintergrund über den Proxy anfordern:

RewriteRule ^/~([^/]+)/?(.*)          /home/$1/.www/$2
RewriteCond %{REQUEST_FILENAME}       !-f
RewriteCond %{REQUEST_FILENAME}       !-d
RewriteRule ^/home/([^/]+)/.www/?(.*) http://www2.quux-corp.dom/~$1/pub/$2 [P]
Lastverteilung
Beschreibung:

Es soll eine Last die Last des Servers www.foo.com auf die Server www[0-5].foo.com (insgesamt 6 Server) verteilt werden.

Lösung:

Dieses Problem lässt sich auf mehrere Arten lösen. Hier soll zuerst eine allgemein bekannte auf DNS basierende Lösung und anschließend eine spezieller mit mod_rewrite vorgestellt werden:

  1. DNS-Rundruf

    Die einfachste Methode für die Lastverteilung ist die DNS-Eigenschaft des Rundrufs für BIND. In diesem Fall werden www[0-9].foo.com wie gewöhnlich für DNS A(dress)-Datensätzen konfiguriert:

    www0   IN  A       1.2.3.1
    www1   IN  A       1.2.3.2
    www2   IN  A       1.2.3.3
    www3   IN  A       1.2.3.4
    www4   IN  A       1.2.3.5
    www5   IN  A       1.2.3.6
    

    Anschließend wird folgender Eintrag hinzugefügt:

    www    IN  CNAME   www0.foo.com.
           IN  CNAME   www1.foo.com.
           IN  CNAME   www2.foo.com.
           IN  CNAME   www3.foo.com.
           IN  CNAME   www4.foo.com.
           IN  CNAME   www5.foo.com.
           IN  CNAME   www6.foo.com.
    

    Das scheint auf den ersten Blick falsch zu sein, entspricht aber einer beabsichtigten Eigenschaft von BIND, die so benutzt werden kann. Wenn jetzt www.foo.com aufgelöst wird, liefert BIND www0-www6, allerdings jeweils in einer leicht veränderten, rotierenden Reihenfolge. Auf diese Weise werden die Clients auf die unterschiedlichen Server verteilt. Hierbei handelt es sich nicht um ein perfektes Lastverteilungssystem, denn die DNS-Auflösungsinformationen werden von den anderen Name-Server im Netzt zwischengespeichert, so dass die nachfolgenden Anfragen eines Clients, der www.foo.com für einen bestimmten wwwN.foo.com-Server aufgelöst hat, ebenfalls an diesen bestimmten Server wwwN.foo.com gehen. Im Endergebnis stört das aber nicht, weil die Gesamtsumme aller Anfragen auf die unterschiedlichen Webserver verteilt wird.

  2. DNS-Lastverteilung

    Eine raffinierte, auf DNS basierende Methode der Lastverteilung ist die Verwendung des Programms lbnamed, dass Sie unter http://www.stanford.edu/~schemers/docs/lbnamed/lbnamed.html finden können. Es handelt sich um ein Perl 5-Programm mit einigen Hilfsprogrammen, das eine reale Lastverteilung für DNS ermöglicht.

  3. Proxy-Weiterverteilung

    Bei dieser Variante wird mod_rewrite und die Möglichkeit des Weiterreichen durch den Proxy genutzt. Zuerst wird www0.foo.com mit einem einzigen DNS-Eintrag zum dedizierten www.foo.com-Server gemacht:

    www    IN  CNAME   www0.foo.com.
    

    Anschließend wird www0.foo.com in einen ausschließlichen Proxy-Server umgewandelt, d.h. dieser Rechner wird so konfiguriert, dass alle eingehenden URLs durch den internen Proxy an einen der 5 übrigen Server (www1-www5) weitergereicht werden. Dazu wird zuerst ein Regelsatz eingerichtet, der für alle URLs das Lastausgleichsskript lb.pl zu Rate zieht.

    RewriteEngine on
    RewriteMap    lb      prg:/path/to/lb.pl
    RewriteRule   ^/(.+)$ ${lb:$1}           [P,L]
    

    Anschließend wird das Skript lb.pl verfasst:

    #!/Pfad zu Perl
    ##
    ##  lb.pl -- Lastverteilung
    ##
    
    $| = 1;
    
    $name   = "www";     # die Hostnamensbasis
    $first  = 1;         # der erste Server(hier nicht 0, weil er selbst 0 ist)
    $last   = 5;         # der letzte Server im Ring
    $domain = "foo.dom"; # der Domänenname
    
    $cnt = 0;
    while (<STDIN>) {
        $cnt = (($cnt+1) % ($last+1-$first));
        $server = sprintf("%s%d.%s", $name, $cnt+$first, $domain);
        print "http://$server/$_";
    }
    
    ##EOF##
    
    Ein letzter Hinweis: Warum ist das sinnvoll? Es scheint doch so, als sei www0.foo.com nach wie vor überlastet? Die Antwort ist ja, er ist es, aber nur mit dem einfachen Durchreichen der Anfragen! Die gesamte SSI-, CGI-, ePerl-Verarbeitung usw. wird vollständig von den anderen Rechnern übernommen, was der entscheidende Punkt ist.
  4. Hardware/TCP-Verteilung

    Auch eine Hardware-Lösung steht zur Verfügung. Die Firma Cisco produziert den LocalDirector, der eine Lastverteilung auf TCP/IP-Ebene durchführt. Eigentlich handelt es sich hier um eine Lösung auf Gateway-Ebene vor einem Webcluster, eine sehr teure, aber auch sehr leistungsfähige Lösung.

Neuer MIME-Typ, neuer Service
Beschreibung:

Im Internet gibt es eine Reihe guter CGI-Programme, allerdings ist ihr Einsatz mühsam, so dass sie häufig nicht benutzt werden. Selbst die Action-Handler-Eigenschaft für MIME-Typen des Apache eignet sich nur, wenn die CGI-Programme keine speziellen URLs als Eingabe benötigen (PATH_INFO und QUERY_STRINGS). Zuerst soll ein neuer Dateityp mit der Erweiterung .scgi (für sicheres CGI) eingerichtet werden, der vom bekannten cgiwrap-Programm verarbeitet wird. Das Problem besteht dabei darin, dass bei Verwendung eines homogenen URL-Layouts (siehe oben) eine Datei innerhalb des Stammverzeichnisses des Benutzers die URL /u/user/foo/bar.scgi hat. cgiwrap benötigt die URL aber in der Form /~user/foo/bar.scgi/. Die folgende Regel löst das Problem:

RewriteRule ^/[uge]/([^/]+)/\.www/(.+)\.scgi(.*) ...
... /internal/cgi/user/cgiwrap/~$1/$2.scgi$3  [NS,T=application/x-http-cgi]

Oder angenommen, es gibt noch zwei praktischere Programm: wwwlog (zeigt die Datei access.log für einen URL-Unterzweig an) und wwwidx (führt Glimpse für einen URL-Unterzweig aus). Diese Programme benötigen den URL-Bereich, damit sie wissen, mit welchem Bereich sie arbeiten müssen. Das ist normalerweise umständlich, weil sie immer noch aus diesen Bereichen angefordert werden. Normalerweise würde das Programm swwidx aus /u/user/foo/ über einen Hyperlink zu

/internal/cgi/user/swwidx?i=/u/user/foo/

ausgeführt, was unschön ist. Weil sowohl die Position des Bereichs als auch die CGI-Position im Hyperlink fest kodiert werden muss. Muss der Bereich reorganisiert werden, dann wird viel Zeit für die Anpassung der verschiedenen Hyperlinks benötigt.

Lösung:

Als Lösung bietet sich ein spezielle neues URL-Format an, das automatisch zum korrekten CGI-Aufruf führt:

RewriteRule   ^/([uge])/([^/]+)(/?.*)/\*  /internal/cgi/user/wwwidx?i=/$1/$2$3/
RewriteRule   ^/([uge])/([^/]+)(/?.*):log /internal/cgi/user/wwwlog?f=/$1/$2$3

Der Hyperlink für die Suche in /u/user/foo/ lautet jetzt

HREF=""

was internautomatisch in

/internal/cgi/user/wwwidx?i=/u/user/foo/

umgewandelt wird. Das gleiche Verfahren führt zu einem Aufruf des wwwlog-Programms, wenn der Hyperlink :log verwendet wird.

Von statisch zu dynamisch
Beschreibung:

Wie kann die statische Seite foo.html in die dynamische Variante foo.cgi umgewandelt werden, ohne dass der Browser beziehungsweise der Benutzer etwas bemerkt?

Lösung:

Die URL zum CGI-Skript wird einfach umgeschrieben und der korrekte MIME-Typ erzwungen, so dass es als CGI-Skript ausgeführt wird. Dadurch führt die Anfrage nach /~quux/foo.html intern zum Aufruf von /~quux/foo.cgi.

RewriteEngine  on
RewriteBase    /~quux/
RewriteRule    ^foo\.html$  foo.cgi  [T=application/x-httpd-cgi]
Inhaltsregeneration im Vorübergehen
Beschreibung:

Die folgende Lösung mutet esoterisch an: Dynamisch erzeugte aber statisch bediente Seiten, d.h. Seiten sollen als rein statische ausgeliefert (aus dem Dateisystem gelesen und weitergereicht) werden, müssen aber dynamisch vom Webserver erzeugt werden, wenn sie fehlen. So können mit CGI erzeugte Seiten statisch ausgeliefert werden, es sei denn, man (oder ein cron-Job) entfernt den statischen Inhalt. In diesem Fall wird der Inhalt aktualisiert.

Lösung:
Dies geschieht mit folgendem Regelsatz:
RewriteCond %{REQUEST_FILENAME}   !-s
RewriteRule ^page\.html$          page.cgi   [T=application/x-httpd-cgi,L]

Eine Anfrage nach page.html führt zu einer internen Ausführung des entsprechenden page.cgi, wenn page.html noch fehlt oder die Dateigröße null hat. Der Trick dabei ist, dass page.cgi ein normales CGI-Skript ist, das seine Ausgabe neben STDOUT auch in die Datei page.html schreibt. Wurde es einmal ausgeführt, versendet der Server page.html. Soll eine Aktualisierung durchgeführt werden, muss die Datei page.html nur entfernt werden (was normalerweise mit einem cron-Job geschieht).

Dokumente mit automatischer Aktualisierung
Beschreibung:

Wäre es nicht schön, wenn während des Erstellens einer umfangreichen Webseite der Webbrowser automatisch die Seite aktualisieren würde, wenn eine neue Version mit dem Editor verfasst wurde? Unmöglich?

Lösung:

Mit einer Kombination der MIME-Multipart-Eigenschaft, der Webserver-NPH-Eigenschaft und den Möglichkeiten für die URL-Manipulation mit mod_rewrite ist das zu realisieren. Zuerst wird eine neue URL-Eigenschaft eingerichtet: Durch Hinzufügen von :refresh zu einer beliebigen URL wird eine bei jeder Aktualisierung im Dateisystem eine auch eine Aktualisierung des Dokuments ausgelöst.

RewriteRule   ^(/[uge]/[^/]+/?.*):refresh  /internal/cgi/apache/nph-refresh?f=$1

Anschließend wird die URL referenziert:

/u/foo/bar/page.html:refresh

Dies führt zum internen Aufruf der URL:

/internal/cgi/apache/nph-refresh?f=/u/foo/bar/page.html

Nun fehlt nur noch das NPH-CGI-Skript, dessen Programmierung, wie an solchen Stellen oft üblich, hier nicht dem Leser zur Übung angedient werden soll ;-):

#!/sw/bin/perl
##
##  nph-refresh -- NPH/CGI-Skript für das automatische
##  Aktualisieren von Seiten
##  Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved.
##
$| = 1;

#   Die QUERY_STRING-Variable aufspalten
@pairs = split(/&/, $ENV{'QUERY_STRING'});
foreach $pair (@pairs) {
    ($name, $value) = split(/=/, $pair);
    $name =~ tr/A-Z/a-z/;
    $name = 'QS_' . $name;
    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
    eval "\$$name = \"$value\"";
}
$QS_s = 1 if ($QS_s eq '');
$QS_n = 3600 if ($QS_n eq '');
if ($QS_f eq '') {
    print "HTTP/1.0 200 OK\n";
    print "Content-type: text/html\n\n";
    print "&lt;b&gt;ERROR&lt;/b&gt;: No file given\n";
    exit(0);
}
if (! -f $QS_f) {
    print "HTTP/1.0 200 OK\n";
    print "Content-type: text/html\n\n";
    print "&lt;b&gt;ERROR&lt;/b&gt;: File $QS_f not found\n";
    exit(0);
}

sub print_http_headers_multipart_begin {
    print "HTTP/1.0 200 OK\n";
    $bound = "ThisRandomString12345";
    print "Content-type: multipart/x-mixed-replace;boundary=$bound\n";
    &print_http_headers_multipart_next;
}

sub print_http_headers_multipart_next {
    print "\n--$bound\n";
}

sub print_http_headers_multipart_end {
    print "\n--$bound--\n";
}

sub displayhtml {
    local($buffer) = @_;
    $len = length($buffer);
    print "Content-type: text/html\n";
    print "Content-length: $len\n\n";
    print $buffer;
}

sub readfile {
    local($file) = @_;
    local(*FP, $size, $buffer, $bytes);
    ($x, $x, $x, $x, $x, $x, $x, $size) = stat($file);
    $size = sprintf("%d", $size);
    open(FP, "&lt;$file");
    $bytes = sysread(FP, $buffer, $size);
    close(FP);
    return $buffer;
}

$buffer = &readfile($QS_f);
&print_http_headers_multipart_begin;
&displayhtml($buffer);

sub mystat {
    local($file) = $_[0];
    local($time);

    ($x, $x, $x, $x, $x, $x, $x, $x, $x, $mtime) = stat($file);
    return $mtime;
}

$mtimeL = &mystat($QS_f);
$mtime = $mtime;
for ($n = 0; $n &lt; $QS_n; $n++) {
    while (1) {
        $mtime = &mystat($QS_f);
        if ($mtime ne $mtimeL) {
            $mtimeL = $mtime;
            sleep(2);
            $buffer = &readfile($QS_f);
            &print_http_headers_multipart_next;
            &displayhtml($buffer);
            sleep(5);
            $mtimeL = &mystat($QS_f);
            last;
        }
        sleep($QS_s);
    }
}

&print_http_headers_multipart_end;

exit(0);

##EOF##
Virtuelle Hosts in großer Anzahl
Beschreibung:

Die VirtualHost-Direktive des Apache ist praktisch und funktioniert gut, wenn es sich um einige Dutzend virtueller Hosts handelt. Für einen Service-Provider, der Hunderte von virtuellen Hosts bedienen muss, ist sie nicht die geeignete Lösung.

Lösung:

Als Lösung wird die entfernte Webpage oder auch der komplette Webbereich mit der Proxy Throughput-Eigenschaft ([P]-Flag) dem eigenen Namespace zugeordnet:

##
##  vhost.map
##
www.vhost1.dom:80  /path/to/docroot/vhost1
www.vhost2.dom:80  /path/to/docroot/vhost2
     :
www.vhostN.dom:80  /path/to/docroot/vhostN
##
##  httpd.conf
##
    :
#   Verwendung der vorschriftsmäßigen Hostnamen bei Umleitungen usw.
UseCanonicalName on

    :
#   Einfügen des virtuellen Host vor dem CLF-Format
CustomLog  /path/to/access_log  "%{VHOST}e %h %l %u %t \"%r\" %>s %b"
    :

#   Aktivieren der Rewriting-Engine des Hauptservers
RewriteEngine on

#   Zwei Maps definieren: eines für die Reparatur der URL und eines, das
#   die verfügbaren virteullen Hosts mit ihrer entsprechenden
#   DocumentRoot definiert.
RewriteMap    lowercase    int:tolower
RewriteMap    vhost        txt:/path/to/vhost.map

#   Die eigentliche Zuordnung der virtuellen Hosts mit einer
#   einzigen umfangreichen und komplizierten Regel:
#
#   1. Keine Zuordnung für allgemeine Orte
RewriteCond   %{REQUEST_URL}  !^/commonurl1/.*
RewriteCond   %{REQUEST_URL}  !^/commonurl2/.*
    :
RewriteCond   %{REQUEST_URL}  !^/commonurlN/.*
#
#   2. Für einen Host-Header sorgen, weil die Herangehensweise
#      zur Zeit nur das virtuelle Hosting
#      über diesen Header zulässt.
RewriteCond   %{HTTP_HOST}  !^$
#
#   3. Hostname in Kleinschreibung
RewriteCond   ${lowercase:%{HTTP_HOST}|NONE}  ^(.+)$
#
#   4. Suche nach diesem Hostnamen in vhost.map, nur
#      aufzeichnen, wenn es sich um einen Pfad handelt
#      (und um keinen der oben aufgeführten)
RewriteCond   ${vhost:%1}  ^(/.*)$
#
#   5. Die URL kann der docroot-Position zugeordnet werden
#      und der virtuelle Host Protokollzwecke aufgezeichnet werden
RewriteRule   ^/(.*)$   %1/$1  [E=VHOST:${lowercase:%{HTTP_HOST}}]
    :
Zugriffseinschränkungen
Robots blockieren
Beschreibung:

Wie können lästige Robots vom Durchsuchen der Seiten eines bestimmten Webbereichs abgehalten werden? Eine Datei /robots.txt mit Einträgen aus dem "Robot Exclusion Protocol" reicht hierfür in der Regel nicht aus.

Lösung:

Ein Regelsatz verbietet die URLs des Webbereichs /~quux/foo/arc/ (möglicherweise ein sehr tief mit Verzeichnissen gegliederter Bereich, der Robot-Durchlauf den Server stark belasten würde). Es soll nur der Zugriff eines bestimmten Robot unterbunden werden, so dass es nicht ausreicht, nur den Host, der den Robot ausführt, auszuschließen. Dadurch würden gleichzeitig Benutzer von diesem Host ausgegrenzt. Zur Lösung dieses Problems wird auch der HTTP-Header User-Agent benutzt.

RewriteCond %{HTTP_USER_AGENT}   ^NameOfBadRobot.*
RewriteCond %{REMOTE_ADDR}       ^123\.45\.67\.[8-9]$
RewriteRule ^/~quux/foo/arc/.+   -   [F]
Gesperrte Inline-Bilder
Beschreibung:

Angenommen unter http://www.quux-corp.de/~quux/ befinden sich einige Seiten Inline-GIF-Bildern, die so schön sind, dass andere sie über Hyperlinks direkt in ihre Seiten einbinden. Das soll unterbunden werden, weil es den Server unnötig belastet.

Lösung:

Ein Einbinden der Bilder lässt sich zwar nicht hundertprozentig unterbinden, es können aber die Fälle unterbunden werden, in denen der Browser einen HTTP Referer-Header sendet.

RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
RewriteRule .*\.gif$        -                                    [F]
RewriteCond %{HTTP_REFERER}         !^$
RewriteCond %{HTTP_REFERER}         !.*/foo-with-gif\.html$
RewriteRule ^inlined-in-foo\.gif$   -                        [F]
Host ablehnen
Beschreibung:

Wie kann eine Liste extern konfigurierter Hosts von der Benutzung des Servers abgehalten werden?

Lösung:

Ab Apache Version 1.3b6:

RewriteEngine on
RewriteMap    hosts-deny  txt:/path/to/hosts.deny
RewriteCond   ${hosts-deny:%{REMOTE_HOST}|NOT-FOUND} !=NOT-FOUND [OR]
RewriteCond   ${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND} !=NOT-FOUND
RewriteRule   ^/.*  -  [F]

Ab Apache Version 1.3b6:

RewriteEngine on
RewriteMap    hosts-deny  txt:/path/to/hosts.deny
RewriteRule   ^/(.*)$ ${hosts-deny:%{REMOTE_HOST}|NOT-FOUND}/$1
RewriteRule   !^NOT-FOUND/.* - [F]
RewriteRule   ^NOT-FOUND/(.*)$ ${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND}/$1
RewriteRule   !^NOT-FOUND/.* - [F]
RewriteRule   ^NOT-FOUND/(.*)$ /$1
##
##  hosts.deny
##
##  ACHTUNG! Dies ist ein Map, keine Liste, auch wenn es als.
##             solche behandelt wird. mod_rewrite durchsucht sie nach
##             Schlüssel-/Wertepaaren, so dass mindestens ein
##             Dummy-Wert "-" für jeden Eintrag vorhanden sein muss.
##

193.102.180.41 -
bsdti1.sdm.de  -
192.76.162.40  -
Proxies ablehnen
Beschreibung:

Wie kann ein bestimmter Host oder auch ein Benutzer eines speziellen Hosts daran gehindert werden, den Apache-Proxy zu benutzen?

Lösung:

Zuerst muss sichergestellt werden, dass beim Kompilieren des Apache-Webservers die mod_rewrite-Direktive in der Konfigurationsdatei nach der mod_proxy-Direktive steht. Auf diese Weise wird es vor mod_proxy aufgerufen. Anschließend wird die Bedingung und die Regel für eine vom Host abhängige Ablehnung...

RewriteCond %{REMOTE_HOST} ^badhost\.mydomain\.com$
RewriteRule !^http://[^/.]\.mydomain.com.*  - [F]

...und für die von [EMAIL PROTECTED]ängige Ablehnung formuliert:

RewriteCond [EMAIL PROTECTED]  [EMAIL PROTECTED]
RewriteRule !^http://[^/.]\.mydomain.com.*  - [F]
Spezielle Authentifizierungsvariante
Beschreibung:

In manchen Situationen ist eine sehr spezielle Authentifizierung erforderlich, bei der beispielsweise eine Reihe explizit eingerichteter Benutzer überprüft wird. Nur diese Benutzer erhalten ohne explizite Eingabeaufforderung (die bei der Authentifizierung mit dem Module mod_auth_basic erscheinen würde) Zugriff.

Lösung:

Mit Hilfe einer Liste von Manipulationsbedingungen werden alle bis auf die gewünschten Benutzer ausgeschlossen:

RewriteCond [EMAIL PROTECTED] [EMAIL PROTECTED]
RewriteCond [EMAIL PROTECTED] !^friend2@client2.quux-corp\.com$
RewriteCond [EMAIL PROTECTED] !^friend3@client3.quux-corp\.com$
RewriteRule ^/~quux/only-for-friends/      -                                 [F]
Ablehung in Abhängigkeit von der verweisenden URL
Beschreibung:

Wie lassen sich auf flexible Weise Ablehnungen basierend auf dem HTTP-Header "Referer" für beliebig viele Seiten vornehmen?

Lösung:

Dies kann mit folgendem Regelsatz....

RewriteMap  deflector txt:/path/to/deflector.map

RewriteCond %{HTTP_REFERER} !=""
RewriteCond ${deflector:%{HTTP_REFERER}} ^-$
RewriteRule ^.* %{HTTP_REFERER} [R,L]

RewriteCond %{HTTP_REFERER} !=""
RewriteCond ${deflector:%{HTTP_REFERER}|NOT-FOUND} !=NOT-FOUND
RewriteRule ^.* ${deflector:%{HTTP_REFERER}} [R,L]

... und in Verbindung mit dem entsprechenden Map geschehen:

##
##  deflector.map
##

http://www.badguys.com/bad/index.html    -
http://www.badguys.com/bad/index2.html   -
http://www.badguys.com/bad/index3.html   http://somewhere.com/

Die Anfrage wird automatisch an die anfragende Seite (wenn im Map "-" als Wert steht) oder an eine bestimmte URL (wenn sie im Map als zweites Argument angegeben wird) zurückgeleitet.

Other
Externe Rewriting-Engine
Beschreibung:

Eine häufig gestellte Frage lautet: Wie lässt sich das Problem mit FOO/BAR/QUUX/usw. lösen? mod_rewrite scheint sich hierfür nicht anzubieten...

Lösung:

Die Lösung ist eine externe RewriteMap-Direktive, d.h. ein Programm, das wie RewriteMap agiert. Es wird einmal beim Start des Apache ausgeführt und erhält die angeforderten URLs über STDIN und gibt die resultierende (meist umgeschriebene) URL über STDOUT aus (gleiche Reihenfolge).

RewriteEngine on
RewriteMap    quux-map       prg:/path/to/map.quux.pl
RewriteRule   ^/~quux/(.*)$  /~quux/${quux-map:$1}
#!Pfad zu Perl

#   Gepufferte I/O deaktivieren, um
#   Endlosschleifen zu vermeiden.
$| = 1;

#   URLs Zeile für Zeile über stdin lesen und
#   die Substitutions-URL für stdout erzeugen
while (<>) {
    s|^foo/|bar/|;
    print $_;
}

Dieses Beispiel soll nur der Anschauung dienen. Es schreibt einfach alle URLs der Form /~quux/foo/... zu /~quux/bar/... um. Im Prinzip kann alles Mögliche definiert werden. Solche Maps können zwar vom einfachen Benutzer verwendet aber nur vom Systemadministrator definiert werden.

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to