Apache Rewrite für zwei Domänen, die gemeinsame Datei-Ressourcen nutzen

Gestern wurden wir mit zwei Websites konfrontiert, die wir um einen Blog ergänzen sollten. Die Webserver-Installation, die wir vorfanden, war interessant und hat uns ein wenig beschäftigt:

Zwei Domain-Namen (alpha.de und beta.de) waren beim Hosting-Provider mit ein und demselben Webserver-Verzeichnis verbunden. Dieses wiederum wies zwei Unterverzeichnisse auf, in denen sich vor allem HTML-Seiten zu den verschiedenen Domänen befanden. Die Idee hinter diesem Setup war wohl, von den Webseiten beider Domänen aus gemeinsame Datei-Ressourcen im Hauptverzeichnis zu nutzen.

Setup zur Nutzung gemeinsamer Datei-Ressourcen durch zwei Web-Domänen auf demselben Webserver

Nennen wir das Hauptverzeichnis mal dir_domains und die Subverzeichnisse dir_alpha und dir_beta.

Die Webseiten von alpha.de und beta.de nutzen gleiche Datei-Ressourcen (CSS-Dateien, Javascripts, PHP-Programme, …). Entsprechende Verzeichnisse fanden sich unter dir_domains:

dir_domains (Webserververzeichnis für Domains alpha/beta)
|__css
|__js
|__php
|__index.php
| ….
|
|__dir_alpha
|        |__index.html
|        |…(HTML-Dateien für die Domäne beta.de)
|        | ….
|__dir_beta
         |__index.html
         |… (HTML-Dateien für die Domäne beta.de)
         |…

Die Datei index.php übernahm die Zugangssteuerung für die Startseiten: Je nach Domain-Anforderung (alpha.de oder beta.de) des Users wurde dieser auf die jeweilige Index-Seite unter dir_alpha oder dir_beta umgelenkt. So weit, so gut – oder eher so schlecht ….

Nach Inaugenscheinnahme der beiden Domänen im Internet war mir klar, warum das so aufgesetzt worden war:

Die Webseiten unter alpha.de bzw. beta.de haben einen ganz ähnlichen Aufbau und nutzen gleiche PHP-Programme und Scripts. Da bei der Anforderung von Ressourcen wie CSS-/JS-/PHP-Dateien Domaingrenzen in der Verzeichnisstruktur des Web-Servers normalerweise nicht überschritten werden dürfen, waren die Web-Designer gezwungen gewesen, beiden Domänen dasselbe Hauptverzeichnis des gehosteten Webserver-Accounts zuzuweisen. Zur Kompensation musste eine Art Umlenkung auf die jeweiligen Verzeichnisstrukturen integriert werden. (Anmerkung am Rande: Die Domängrenzen, im Sinne von Verzeichnisgrenzen, gelten übrigens nicht für Include-Dateien, die in PHP-Programmen nachgeladen werden. Solche Include-Dateien kann man ruhig oberhalb des Domainverzeichnisses unterbringen!).

Was war am Setup schlecht?

Während die Nutzung gemeinsamer Ressourcen durchaus zu befürworten ist, war die “Umlenkung” durch das PHP-Skript schlecht gelöst. Sie funktionierte eigentlich nur für den Aufruf einer der beiden Domän-Namen selbst (Umlenkung auf die jeweilige index.html-Seiten). Die Navigation innerhalb der Webseiten einer Domäne war über relative Pfade gelöst; sobald ein User sich einmal innerhalb einer Domäne bewegte, funktionierte deshalb alles aus Nutzersicht alles bestens.

Aber: Der Aufruf einer spezifischen Seite einer Domäne über eine direkte Eingabe in die Adresszeile des Browsers – z.B. http://alpha.de/infos/impressum.html – funktionierte mit dem vorhandenen PHP-Script nicht. Das Script index.php kümmerte sich nur um die Index-Seiten der Domänen. Es wurde als Index-Datei ja nur dann aktiv, wenn eine der Domän-Adressen alpha.de oder beta.de ohne weitere Zusätze im Browser
aufgerufen wurde.

Lösungsansatz über Apache Rewrite

Bei dem gehosteten Webserver handelte es sich um einen Apache-Server. Eine saubere Lösung für den gewünschten Setup-Ansatz mit geteilten Datei-Ressourcen besteht dann natürlich darin, das Apache Rewrite-Modul (mod_rewrite) zu nutzen. Die Servereinstellungen beim Provider waren so, dass die Rewrite Engine über lokale “.htaccess”-Dateien aktiviert und gesteuert werden konnte. Wir haben dann folgenden einfachen Vorschlag umgesetzt:

Inhalt der .htaccess-Datei für das Verzeichnis dir_domains:

Options +FollowSymLinks 
RewriteEngine On 
RewriteBase /

RewriteRule ^alpha/(.*)$ - [L]
RewriteRule ^beta/(.*)$ - [L]

RewriteRule ^css/(.*)$ - [L]
RewriteRule ^images/(.*)$ - [L]
RewriteRule ^php/(.*)$ - [L]
RewriteRule ^script/(.*)$ - [L]

RewriteCond %{SERVER_NAME} alpha.de [OR]
RewriteCond %{SERVER_NAME} www.alpha.de
RewriteRule ^$ alpha/index.html [L]

RewriteCond %{SERVER_NAME} alpha.de [OR]
RewriteCond %{SERVER_NAME} www.alpha.de
RewriteRule ^(.*)$ alpha/$1 [NC,L]

RewriteCond %{SERVER_NAME} beta.de [OR]
RewriteCond %{SERVER_NAME} www.beta.de
RewriteRule ^$ beta/index.html [L]

RewriteCond %{SERVER_NAME} beta.de [OR]
RewriteCond %{SERVER_NAME} www.beta.de
RewriteRule ^(.*)$ beta/$1 [NC,L]

 
Die ersten 2 Rewrite-Regeln sorgen dafür, dass keine Umlenkung mehr vorgenommen wird, wenn man sich bereits im Verzeichnisbereich der Seite befindet. Dieser Vorspann ist wichtiger, als man meinen möchte: die nachfolgenden Regeln würden für sich allein zu einer unbegrenzten Iteration von Rewrites führen!

Die nächsten 4 Regeln sorgen dann dafür, dass Verweise auf die gemeinsam genutzten Ressourcen-Verzeichnisse und zugehörige GET-Anforderungen an den Server unangetastet bleiben. Diese Verzeichnisse werden ja aus dem HTML-Code der Webseiten unter dem alpha- bzw. dem beta-Sub-Verzeichnis referenziert; z.B. über relative Pfade.

Danach kommen die eigentlichen Umlenkungsregeln. Wir haben hier die Grundregel befolgt, dass eine oder mehrere Rewrite Conditions sich nur und ausschließlich auf die nächste Rewrite Rule beziehen – also auf genau eine Rewrite Rule! Das wird in der hektik oft übersehen; es gibt keine native Klammerung mehrerer Rewrite Rules zu Rewrite Conditions. Allerdings kann man mit Negationen der Bedingungen und Skip-Zusätzen hinter den Rewrite-Regeln tricksen. Um das Verständnis nicht zu erschweren, haben wir hier auf solche Hacks verzichtet.

Wird keine Dateiname angegeben – ist also der Pfad hinter dem Domain-Anteil leer – wird auf die jeweilige Index-Seite umgelenkt. Sind konkrete Webseiten einer Domäne angefordert, wird auf die gewünschte Datei im jeweiligen Unterverzeichnis verwiesen.

Das war es schon; die Datei index.php kann und sollte danach gelöscht werden. Unser Kunde kann nun 2 Domänen im gleichen Webserververzeichnis nutzen und zwischen beiden Implementierungen gemeinsame Ressourcen teilen. Eigentlich eine nette kleine Geschichte, die ich vielleicht auch mal für eigene Sites nutzen werde – Apache sei Dank!

VMware Workstation WS 11 unter Opensuse Leap 42.1

Habe heute ein Upgrade eines Opensuse 13.1-Systems auf Opensuse Leap 42.1 durchgeführt. Das ging – bis auf einige typische OS 42.1-Probleme, die ich bereits an anderer Stelle in diesem Blog beschrieben habe, ganz gut.

Gestolpert bin ich dann allerdings über ein Problem mit der VMware-Workstation. Die auf dem fraglichen System installierte Version war WS 11.1.0.

Da sich der Kernel gegenüber der Version von 13.1 inzwischen natürlich massiv verändert hatte (aktuelle Leap42.1-Kernelversion 4.1.27), führte der Versuch VMware WS zu starten, zu einer automatisch eingeleiteten Neu-Kompilation der wichtigsten VMware-Module. Dieser Kompilationsversuch scheitert aber leider an dem vmnet-Modul; nachfolgend ein Auszug aus der Log-Datei:

2016-09-26T14:13:52.987+02:00| vthread-4| I120: Successfully extracted the vmnet source.
2016-09-26T14:13:52.987+02:00| vthread-4| I120: Building module with command “/usr/bin/make -j8 -C /tmp/modconfig-jZLoM6/vmnet-only auto-build HEADER_DIR=/lib/modules/4.1.31-30-default/build/include CC=/usr/bin/gcc IS_GCC_3=no”
2016-09-26T14:13:54.615+02:00| vthread-4| W110: Failed to build vmnet. Failed to execute the build command.
….
2016-09-26T14:14:12.914+02:00| vthread-4| I120: Read 17587 symbol versions
2016-09-26T14:14:12.914+02:00| vthread-4| I120: Invoking modinfo on “vmmon”.
2016-09-26T14:14:12.919+02:00| vthread-4| I120: “/sbin/modinfo” exited with status 0.
2016-09-26T14:14:12.919+02:00| vthread-4| I120: Invoking modinfo on “vmnet”.
2016-09-26T14:14:12.924+02:00| vthread-4| I120: “/sbin/modinfo” exited with status 256.
2016-09-26T14:14:13.334+02:00| vthread-4| I120: Setting destination path for vmnet to “/lib/modules/4.1.31-30-default/misc/vmnet.ko”.
2016-09-26T14:14:13.334+02:00| vthread-4| I120: Extracting the vmnet source from “/usr/lib/vmware/modules/source/vmnet.tar”.
2016-09-26T14:14:13.344+02:00| vthread-4| I120: Successfully extracted the vmnet source.
2016-09-26T14:14:13.344+02:00| vthread-4| I120: Building module with command “/usr/bin/make -j8 -C /tmp/modconfig-sDUVWe/vmnet-only auto-build HEADER_DIR=/lib/modules/4.1.31-30-default/build/include CC=/usr/bin/gcc IS_GCC_3=no”
2016-09-26T14:14:14.951+02:00| vthread-4| W110: Failed to build vmnet. Failed to execute the build command.

Dieses Problem lässt sich beheben, ohne gleich für teures Geld auf die WS 12 upgraden zu müssen. Es handelt sich nämlich um einen Fehler, der in einer späteren Version behoben wurde.

Kurz gesagt: Version 11.1.4 der WS runterladen => Installieren => VM-Ware WS auch unter Opensuse Leap 42.1 weiter betreiben !