Archiv der Kategorie: Apache

Windows Developer System – Virtual Hosts (03)

Nachdem wir die Basis unseres Systems nun installiert haben kommen wir nun zu einem Punkt, der ein wenig Erklärung bedarf, bevor wir zur Umsetzung kommen können: den Virtual Hosts.

Virtual Hosts sind, wie der Name schon sagt, virtuelle Maschinen, die es nicht wirklich gibt, dessen rein virtuelle Existenz wir uns zunutze machen, um eine echte Maschine zu simulieren. Aber von vorn:

Jeder kennt DNS, man gibt www.example.com ein, der Browser lädt und gibt uns entweder eine Webseite oder eine Fehlermeldung aus. Mal ganz stark vereinfacht rufen wir aber gar nicht die Domain mit Namen auf, weil es die gar nicht gibt, sondern wir rufen einen bestimmten Verzeichnisinhalt einer bestimmten IP auf. Da sich aber kein Mensch eine URL a la

http://192.168.178.254/~fritzdiewurst/whatever

merken könnte, erfand man DNS. DNS „matched“ einen Namen auf eine bestimmte IP.

Dieser Name ist in 2, meist in 3, Teile geteilt, damit die Auflösung schneller geht (das System ist recht alt, heute würde man dies nicht mehr mit Schnelligkeit begründen, damals war das aber echt so) und zwar der „First Level Domain“ (oder „Top Level Domain“ TLD), das ist meist das Länderkennzeichen am Ende, in unserem Fall das „com“, die „Second Level Domain“, das ist der eigentliche Name, bei uns also „example“ und die „Third Level Domain“, besser bekannt als „Subdomain“, bei uns das „www“. Top- und Second Level werden per DNS aufgelöst, Third ist Sache des Domaininhabers, aber das sind nur Details, wichtig also, dass dieser Name nun in eine bestimmte IP aufgelöst wird und der Request dann beim Webserver dieser IP weitergeht. Der Webserver bekommt nun ebenfalls den gesamten Request und kann dieser weiter auflösen auf bestimmte Verzeichnisse, so dass ein Webserver viele Domain mit unterschiedlichen Inhalten beinhalten kann.

Damit das alles funktioniert gibt es auf der ganzen Welt sogenannte DNS-Server die diese Auflösungsarbeit erledigen. Diese Synchronisieren sich alle untereinander, damit alle die gleiche Antwort auf die selbe Frage geben. Wie gesagt, stark vereinfacht, aber im Prinzip funktioniert das so.

Und warum erzähle ich das? Ganz einfach. Jedes Betriebssystem hat eine Steuerdatei die es dem lokalen System erlaubt, seine eigenen DNS-Richtlinien zu hinterlegen. Man kann also angeben, dass man gern bei der Eingabe von example.com auf eine bestimmte IP gelangen möchte. Dies ist die sogenannte „hosts“ Datei.

Und wofür brauchen wir als Entwickler so eine „hosts“ Datei?
Okay, zum Kern des „sagen-wollen’s“. Du betreust bei deiner Arbeit meist ein Projekt, das unter einer bestimmten URL zu erreichen ist, nehmen wir dieses Blog, da ist die URL

http://www.codemercenary.de

Wenn ich nun was an meinem Blog umprogrammiere, dann mache ich das nicht Live auf dem Server (sog. „hot coding“), sondern lokal auf meinem Entwicklungsrechner zuhause. Da habe ich meinen Webserver und meinen Datenbankserver.

Normalerweise legst du deine Daten auf deinem lokalen Webserver in das sogenannte „Document Root“ ab, dass ist in unserem Beispiel des Zend Servers das Verzeichnis „C:\zend\Apache2\htdocs“. Alles, was du da ablegst, kannst du mit der Eingabe von

http://127.0.0.1

abrufen, legst du also eine „phpinfo.php“ direkt in „htdocs“ rein, dann tippst du in deinem Browser

http://127.0.0.1/phpinfo.php

ein und du erhälst die Antwort, die das Script liefert. Easy, oder?

Das kannst du nun für alle deine Projekte machen, am besten jedes Projekt in ein neues Verzeichnis unterhalb von „htdocs“. So könnte ich z.B. mein Blog unter

http://127.0.0.1/codemercenary

aufrufen und alles wäre gut … oder nicht?

Eigentlich nicht, denn bald wirst du feststellen, dass sich manche Skripte sehr seltsam verhalten, wenn die nicht der „Platzhirsch“ auf der URL sind. Kurz: Manches lässt sich besser testen, wenn du es möglichst Live auf dem Server haben würdest. Willst du aber nicht, weil das „bad style“ bzw. „hot coding“ wäre und das gewöhnst du dir besser erst gar nicht an.

Es wäre doch super, wenn ich einfach

http://www.codemercenary.de

eintippe und der Browser ruft die Daten direkt von meinem lokalen Webserver ab. Ne, auch nicht gut, weil du dich dann gar nicht mehr per FTP verbinden könntest, falls dein FTP-Hostname der gleiche wäre. Doof, und nun?

Simpel: So gut wie alle Skripte die ich kenne (und das sind ne Menge, vor allem im Legacy Bereich) reagieren nur auf die TLD und die SLD, so gut wie nie auf die Subdomain und das nutzen wir nun aus. Wir definieren uns nun fest in den Kopf, dass es bei jedem Projekt nur 2 URLs gibt: eine mit www, die ist Live und eine mit einer Subdomain, die uns anzeigt, dass es sich um das Entwicklersystem handelt, also unser lokales System. Ich benutze dafür die Subdomain „dev“, so dass mein Aufruf

http://dev.codemercenary.de

lautet, wenn ich mal meine lokale Version testen oder debuggen will.

Damit nun der Aufruf nicht ins Internet geht sondern bei mir lokal verarbeitet wird muss ich meine „hosts“ anpassen. Die „hosts“ Datei findest du unter Windows immer an diesem Platz:

\Windows\System32\drivers\etc\hosts

Du musst zum bearbeiten übrigens Admin-Rechte haben.

Die Einträge machst du – vereinfacht gesagt – im Format IP<Leerzeichen>Name, in meinem Fall trage ich dort also

127.0.0.1 dev.codemercenary.de

ein. Damit wird der Aufruf

http://dev.codemercenary.de

schon mal auf die IP 127.0.0.1 umgeleitet und das ist bei jedem System die lokale Adresse!

Leider weiß nun unser Zend Server noch nix davon. Falls du nun schon mit gestartetem Server diese URL eingebt kommst du zwar auf dein lokales System, aber der Server führt dich in das globale Document Root, also direkt in „htdocs“. Da willst du aber nicht hin, sondern in das Unterverzeichnis deines Projektes.

Zur Info: Falls du schon <VirtualHost> Einträge hast, von denen aber keiner auf den ServerName matched, dann benutzt der Apache deinen ersten <VirtualHost> Eintrag in der .conf.

Nun gäbe es zwei Möglichkeiten. Du glücklicher, der du nur ein Projekt zu betreuen hast, kannst nun das Document Root des ganzen Servers auf das entsprechende VZ legen oder gleich alles in „htdocs“ speichern, du hast eh nur ein Projekt, da ist der Rest egal.

Die meisten von uns haben aber mehr wie nur ein Projekt und da heißt es nun, dass wir unserem Zend Server – genauer gesagt dem Apache Webserver – beibringen wollen, dass er beim Aufruf von

http://dev.exampleA.com

ins Unterverzeichnis „A“ gehen soll und bei

http://dev.exampleB.net

ins Verzeichnis „B“.

Für diese „Magie“ brauchen wir nun die Virtual Hosts, wir teilen unseren einen physikalischen Webserver nun in viele Virtuelle Webserver auf und können damit für unsere Projekte „echtes“ Internet simulieren.

Auch hierfür, für die Bearbeitung der Virtual Hosts, gibt es viele Wege. Keiner davon ist falsch, keiner der einzig richtige. Ich zeige dir einen Weg, mit dem ich nun seit 3 Jahren erfolgreich Beruflich arbeite. Es muss nicht der beste sein, aber er funktioniert und ist recht einfach zu bedienen und darüberhinaus ist dieser Weg der Updatesichere Weg, sobald du deinen Server updatet. Ich versuche an geeigneter Stelle auch alternative Wege zu zeigen, so wie mir diese bekannt sind.

An alle Linux-SysAdmins: Nicht böse sein, aber niemand weiß alles und ich bin gern bereit, dazu zu lernen. Die Kommentarfunktion bietet für Aufklärung Platz 😉

Also, Editor auf, folgende Datei laden:

\zend\Apache2\conf\zend.conf

Die Datei fängt meist so oder ähnlich an:

<Location /server-info>
    SetHandler server-info
    Order deny,allow
    Deny from all
    Allow from 127.0.0.1
</Location>

Kleiner Tip am Rande: Lass alles stehen, was in der Datei steht, zumindest so lange, bis du weißt, was die einzelnen Einträge zu bedeuten haben. Für’s erste brauchst du das alles nicht.

Zuallererst brauchst du in deiner „zend.conf“ einen Eintrag „NameVirtualHost“, sonst weiß der Apache gar nicht, was er machen soll. Dazu steht als erste Zeile der Datei:

NameVirtualHost 127.0.0.1:80

Um nun einen Aufruf des Browsers Namensabhängig zu verarbeiten habe ich diesen Eintrag:

<VirtualHost 127.0.0.1>
 ServerName dev.codemercenary.de
 DocumentRoot "C:\zend\Apache2\htdocs\codemercenary"
 RewriteEngine On
 ErrorLog "logs/codemercenary.log"
 CustomLog "logs/codemercenary.log" common
 <Directory "C:\zend\Apache2\htdocs\codemercenary">
  AllowOverride All
  Allow from all
  Options Indexes FollowSymLinks
 </Directory>
</VirtualHost>

Was bedeutet das nun alles? Die wichtigen Stellen sind diese:

  • ServerName: Dort steht der Name, so wie du ihn im Browser eingibst
  • DocumentRoot: Dort sucht der Server nach Inhalten
  • RewriteEngine On: Die mod_rewrite Engine wird benutzt
  • ErrorLog/CustomLog: Die Logfiles werden getrennt von den anderen geschrieben, sehr nützlich zur Fehlersuche
  • Directory-Eintrag: Ohne den läuft nix 😉 Hier nochmal das DR des Projektes angeben

Hast du mehrere Projekte, dann kannst du diese hintereinander dort eingeben, also mehrere <VirtualHost> Knoten. Die VirtualHosts für einen bestimmten Port müssen direkt nach der „NameVirtualHost“ Direktive eingetragen werden, die diesen Port bezeichnet und vor einer Direktive, die andere Port behandelt.

Hast du ein Projekt, dass mehrere Domains mit einem Script behandelt (Multi-Domain-Shops als Beispiel), dann gibst du einfach mehrfach untereinander die „ServerName“ Direktive ein, jeweils eine Domain pro „ServerName“ … zumindest funktioniert das bei mir so 😉

Hast du ein Projekt für andere Ports als Port 80 siehst du etwas weiter unten ein Beispiel für Port 10081, den Admin-Zugang des Zend Servers. Analog dazu lässt sich auch jeder andere Port ansprechen, es sei denn, er ist anderweitig belegt (21 für FTP als Beispiel).

Die Ports musst du übrigens NICHT in der „hosts“ Datei angeben, die ist Portunabhängig.

Wichtig ist nun, dass du deinen Server neu startest, denn sonst kennt der deine neuen Regeln für die VirtualHosts nicht. Bei den Einträgen der „hosts“ ist es zumindest beim Firefox so, dass du den einmal komplett zu und wieder auf machen musst, damit der die „hosts“ neu einliest, der Chrome und der IE (bei mir 10) machen das bei jedem Aufruf.

So, und da nun einige nach der versprochenen Alternative schreien: Ja, es geht auch anders. Du kannst anstelle einfach alle VirtualHosts in eine große Datei zu schreiben auch eine Datei für jeden VirtualHost anlegen, falls du das möchtet oder braucht (ließe sich zum Beispiel in deine Versionskontrolle integrieren). Der Zend Server ist standardmäßig so konfiguriert, dass er alle .conf Dateien im Verzeichnis

\zend\ZendServer\etc\sites.d\http\__default__\0

einliest und verarbeitet.

Du kannst also den <VirtualHost> Eintrag dort als Datei

codemercenary.conf

hinterlegen, dann noch eine „exampleA.conf“ mit der <VirtualHost> für exampleA.com usw.

Dieser Weg ist näher am „normalen“ Apache Server, funktioniert aber genauso.

Abschließend noch der Vorteil dieser gesamten Aktion: In deinem Projekt kannst du nun recht simpel prüfen, ob du lokal oder produktiv bist und dann entsprechend verschiedene Konfigurationen laden, z.B. für die Datenbankverbindung.

Einfach ein

if ('dev.codemercenary.de' == $_SERVER['HTTP_HOST']) {
  // lade lokale configuration
} else {
  // lade produktive configuration
}

und schon hast du auch in deiner Versionskontrolle keine verschiedenen Dateien mehr für lokal oder produktiv und kannst gefahrlos deployen.

Im nächsten Teil geht es dann weiter mit der Konfiguration deines Systems für PEAR, als Vorbereitung auf QA-Tools wie phpcs, pdepend, phpmd und natürlich auch phpunit. Bis dann…

RewriteRule nur für nicht vorhandene Dateien

… oder wie stelle dynamische Inhalte in statischen webEdition Seiten dar?

Die Apache RewriteRule kennt wohl jeder, der etwas mehr mit Webseiten macht. RewriteCond sollte auch bekannt sein, allerdings hatte ich bisher diese beiden Direktiven nicht in dieser Form miteinander verbunden.

Das Problem:

Ursächlich war, dass ich in webEdition Seiten dynamische Inhalte anzeigen wollte. Die Inhalte kommen von extern und somit wollte ich a) die Seite nur einmal bauen und b) einen Teil der Inhalte von ausßen dynamisch füllen (z.B. die neuesten Twitter-Feeds oder oder oder).

Nun merke ich schnell: Ist eine webEdition Seite einmal als “statisch” definiert, dann ist diese auch genau das: statisch. Es ist HTML, webEdition zieht alle Informationen die es braucht in dem Moment aus alles Quellen und schreibt eine .html-Seite. Mehr nicht. Aber genau das soll webEdition ja auch machen. Also kein Grund zum meckern … oder? Bedingt.

Ja, webEdition macht rein technisch alles richtig, nur will ich doch in einer Sidebar dynamische Inhalte haben 🙁

Okay, Seite auf “dynamisch” umstellen und dann: Lasse ich die Dateiendung auf .html, dann sehe ich nur PHP-Code.

Sicher, ich könnte nun die Dateiendung umstellen – auf .php funktioniert das ganze wie gewünscht – aber das ist weder Sinn der Übung, noch ist das gewünscht; Stichwort Kundenwunsch!

Lösungsvorschläge:

Also, hier der andere Weg: mod_rewrite.

Der einfachste Weg: Alles, was .php heißt in .html umleiten, aber Halt! Der erfahrende Mensch sieht: Das geht schief, denn es können durchaus .php Dateien auf dem Server liegen, die auch ausgeführt werden wollen.

Lösungsvorschlag 1:

AddHandler-Direktive nutzen.
Man könnte die AddHandler Direktive nutzen und allen .html-Code als PHP ausführen lassen. Bei statischen Seiten würde dies nur sehr geringen Zeitverlust bedeuten und es würden die .html-Seiten auch korrekt ausgeführt, die PHP-Code beinhalten (also unsere dynamischen webEdition Seiten).

Lösungsvorschlag 2:

Bedingtes Umleiten!
Funktioniert Lösung 1 nicht (warum auch immer) oder ist dieser Weg nicht gewünscht (der Kunde ist doch König), dann sollte man es so versuchen – und kommen damit wieder zur Überschrift zurück (was für ein Handlungsbogen).
Man leitet alle Anfragen auf .html-Seiten, die nicht existieren, auf .php-Seiten um, die exakt so heißen, wie die .php Version.

Schritt 1: Zuerst werden die webEdition-Seiten geparkt, als dynamisch markiert und dann als xyz.php gespeichert.

Schritt 2: In der .htaccess wird folgende neue RewriteCond mit folgender RewriteRule ergänzt … ich habe diese ganz ans Ende gepackt, kommt aber immer auf den individuellen Fall an:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)\.html $1.php [L]

So werden nun nur die .html-Aufrufe an .php-Scripte übergeben, deren .html-Datei nicht real auf dem Dateisystem des Servers existiert.

Viel Erfolg…

Homepage für andere sperren

Während man eine Webseite erstellt oder bearbeitet, möchte man natürlich nicht, dass andere einen “Zwischenstand” sehen und man sperrt die Domain. Oder man möchte einfach allein auf seiner Homepage rumsurfen … warum auch immer.

Zuerst braucht Mensch seine IP, dazu gibt es genug AddOns oder Webseiten, auf denen Mensch das rausbekommt.

Dannach braucht es noch zwei Zeilen in der .htaccess; RewriteEngine sollte “on” sein.

RewriteCond %{REMOTE_ADDR} !^IPADRESSE$
RewriteRule ^(.*)$ URL_ZUR_UMLEITUNG [NC,QSA,L,R=302]

Wichtig ist das ! vor der PrüfungsIP-Adresse in der RewriteCond Zeile.

Somit sehen alle anderen Besucher die URL die bei der RULE eingegeben wird, Mensch selbst sieht aber die “normalen” Inhalte.

Kleines Beispiel (Domain ist my-example-web.com)

RewriteCond %{REMOTE_ADDR} !^78.201.9.12$
RewriteRule ^(.*)$ http://example.com [NC,QSA,L,R=302]

Hier greifen alle User auf example.com zu, nur der User von der IP 78.201.9.12 (sollte die eigene sein) greift auf die “echten” Inhalte der Seite zu.

Referenz: Doku zu RewriteCond