Too Cool for Internet Explorer

cookie based redirect mit nginx


Vor einiger Zeit habe ich einen Tip beschrieben, wie man einen cookie-based redirect mit dem LightTPD konfigurieren kann. Das Problem an der Sache ist für mich, dass das für diesen Zweck verwendete Modul mod_proxy von LightTPD in dem von mir eingesetzen Entwicklungszweig (1.4.x) nicht SSL kompatibel ist und dementsprechend HTTPS Verbindungen fehlschlagen.

Seit einiger Zeit schon habe ich den Web- und (Reverse-) Proxy-Server nginx im Auge. Auch mit diesem Server ist es möglich einen Redirect einzurichten, so wie ich ihn brauche. Und: nginx unterstützt an dieser Stelle SSL!


server {
    listen          80;
    server_name     *.devcenter.int;

    proxy_redirect      off;
    proxy_set_header    Host            $host;
    proxy_set_header    X-Real-IP       $remote_addr;
    proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;

    location / {
        if ($http_cookie ~ "(; )?devredirect=harald") {
            proxy_pass              http://10.0.0.20;
            break;
        }
        if ($http_cookie ~ "(; )?devredirect=markus") {
            proxy_pass              http://10.0.0.22;
            break;
        }

        ...
    }
}


server {
    listen          443;
    server_name     ....devcenter.int;

    ssl                     on;
    ssl_certificate         /etc/nginx/....crt;
    ssl_certificate_key     /etc/nginx/....key;

    proxy_redirect      off;
    proxy_set_header    Host            $host;
    proxy_set_header    X-Real-IP       $remote_addr;
    proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;

    location / {
        if ($http_cookie ~ "(; )?devredirect=harald") {
            proxy_pass              https://10.0.0.20;
            break;
        }
        if ($http_cookie ~ "(; )?devredirect=markus") {
            proxy_pass              https://10.0.0.22;
            break;
        }

        ...
    }
}



cookie based redirect mit lighttpd


Alle unsere Entwickler haben eine komplett eigene Entwicklungsumgebung inkl. WebServer installiert. Manchmal ist es praktisch den aktuellen Entwicklungsstand am Checkout eines Entwicklers zu sehen. Anstatt für jedes Projekt und jeden Entwickler eine interne Subdomain einzurichten, kann man viel praktischer einen zentralen Reverse Proxy nutzen, der anhand einer Cookie Einstellung den Host des jeweiligen Entwicklers auswählt:

$SERVER["socket"] == "10.0.0.20:80" {
    ...
    $HTTP["host"] =~ "^.*\.devcenter.int$" {
        $HTTP["cookie"] =~ "(; )?devredirect=harald" {
            proxy.server = (
                "" => (("host" => "10.0.0.20", "port" => 8080))
            )
        }
        $HTTP["cookie"] =~ "(; )?devredirect=markus" {
            proxy.server = (
                "" => (("host" => "10.0.0.22", "port" => 8080))
            )
        }
    }
}    

Die oben gezeigte Konfiguration installiert einen Reverse Proxy für Subdomains von 'devcenter.int' -- z.B. 'clipdealer.devcenter.int'. Über das Cookie 'devredirect' kann spezifiert werden, welcher Host angesprochen werden soll.



lighttpd + virtual host + verschiedene php.ini Dateien


Im Moment beherberge ich auf meinem Rechner eine Entwicklungs- sowie eine Testumgebung, die verschiedene PHP Konfigurationen benötigen. Um verschiedene PHP Konfigurationen zu laden, kann die fastCGI Konfiguration einfach unterhalb des jeweiligen virtuellen Hosts verlagert werden und die 'bin-path' Einstellung entsprechend um den Parameter zum Laden einer speziellen Konfigurationsdatei ergänzt werden:

fastcgi.server = ( ".php" => ((
"socket" => "/tmp/php-fastcgi.socket",
"bin-path" => "/opt/php5/bin/php-cgi -c /opt/php5/lib/php-devel.ini",
"bin-environment" => (
...
),
...
)))


LightTPD mit mod_cml und mod_magnet


Kleine Gedankenstütze für mich:

Sowohl 'mod_cml' als auch 'mod_magnet' in LightTPD >= 1.4.13 benötigen Lua 5.1. Falls Lua 5.1 nicht in der Linux Distribution enthalten ist oder z.b. auch unter Mac OSX, bekommt man Lighty folgendermassen compiliert (vorausgesetzt lua wurde compiliert und unter /usr/local/ installiert):

$ export LUA_CFLAGS="-I/usr/local/include"
$ export LUA_LIBS="-L/usr/local/lib -llua"
$ ./configure --prefix=/usr --with-pcre --with-lua
$ make


(PHP) Entwicklungsumgebung unter Windows


Mein eigenes PHP Framework, das ich für all meine (privaten) Web Anwendungen verwende, benötigt für einige lokale Tools sowie für Build und Deploy Prozesse unter Unix übliche Tools, wie die Bash, GNU Make, awk, sed und wie sie denn alle heissen. Ausserdem mache ich Gebrauch von einigen Eigenheiten des Dateisystems, wie symbolische Links, wie sie so nicht im Windows Dateisystem implementiert sind, bzw. nur umständlich erreicht werden können. Ausserdem setzt mein Framework LightTPD als Web Server voraus, da ich einige spezielle Module dieses hervorragenden Web Servers gerne verwende.

Nun haben aber nicht alle, die dieses Framework verwenden müssen Linux, Mac OS X oder ein anderes Betriebssystem, bei dem von Haus aus all diese schönen Dinge vorhanden sind. Nein, es gibt in der Tat noch Leute, die ein Windows bevorzugen und für die muss eine vernünftige Lösung her.

Nach einigem Überlegen bin ich auf die Idee gekommen, mein Setup unter Cygwin auszuprobieren. Cygwin ist eine Emulation der Linux API für Windows, die es - kurz gesagt - ermöglicht z.b. Linux Anwendungen auf Windows zu portieren. Mehr dazu bei Wikipedia. Cygwin bringt auch eine portierte Bash mit.

Nach Herunterladen der Distribution von der Cygwin Web Seite und der Installation von Cygwin inkl. der Entwicklungstools, war also das Fundament vorhanden. Wer mit einer Debian basierte Linux Distribution vertraut ist, wird das praktische 'apt-get' Tool kennen, mit dem man nachträglich Software installieren kann. Auch für Cygwin gibt es ein derartiges Tool - cyg-apt. Ich kann nur empfehlen, dieses Tool einzusetzen, erleichtert es doch die nachträgliche Installation von z.b. von PHP benötigten Libraries erheblich. cyg-apt ist in Python geschrieben, weshalb bei der Installation von Cygwin auch die Installation von Python berücksichtigt werden sollte.

Als nächstes habe ich mir die Quellen des aktuellen PHP (5.2) besorgt. Wenn man MySQL Support wünscht, wird ausserdem noch der Quellcode von MySQL benötigt.

Zunächst muss man also MySQL kompilieren - da wir unter Cygwin nur die Client Bibliotheken benötigen, werden auch nur diese compiliert:

./configure --prefix=/usr --without-server
make
make install

Als nächstes kann man dann PHP mit fastCGI Unterstützung compilieren. Man beachte hierbei, dass 'fastCGI' unter Windows zu Problemen führen kann. Falls es später tatsächlich zu Problemen kommt, kann man dann aber PHP immernoch als CGI Anwendung unter LightTPD verwenden. Eine PHP Configuration könnte z.b. folgendermassen aussehen:

'./configure' '--prefix=/usr' '--with-config-file-path=/etc' '--with-config-file-scan-dir=/etc/php.d' '--enable-force-cgi-redirect' '--disable-debug' '--enable-pic' '--disable-rpath' '--enable-inline-optimization' '--with-bz2' '--with-curl' '--with-freetype-dir=/usr' '--with-png-dir=/usr' '--with-gd' '--enable-gd-native-ttf' '--without-gdbm' '--with-gettext' '--with-ncurses' '--with-gmp' '--with-iconv' '--with-jpeg-dir=/usr' '--with-openssl' '--with-png' '--with-regex=system' '--with-xml' '--with-expat-dir=/usr' '--with-dom=shared,/usr' '--with-dom-xslt=/usr' '--with-dom-exslt=/usr' '--with-xmlrpc=shared' '--with-zlib' '--with-layout=GNU' '--enable-bcmath' '--enable-exif' '--enable-ftp' '--enable-sockets' '--enable-track-vars' '--enable-trans-sid' '--enable-wddx' '--with-pear=/opt/pear' '--with-mysql' '--with-mysqli=/usr/bin/mysql_config' '--enable-memory-limit' '--enable-bcmath' '--enable-calendar' '--enable-dio' '--enable-mcal' '--enable-mbstring=shared' '--enable-dbx' '--enable-mbstr-enc-trans' '--enable-mbregex' '--enable-fastcgi' '--enable-force-cgi-redirect'

Alle Bibliotheken, die PHP zusätzlich noch benötigt, kann man i.d.R. per 'cyg-apt' nachinstallieren.

Nachdem auch PHP compiliert und installiert wurde kann man sich nun die Quellen von LightTPD besorgen. Ein einfaches './configure --prefix=/usr' und 'make; make install' reicht hier in der Regel aus, um LightTPD mit den wichtigsten Modulen zu Compilieren und zu Installieren. Die Konfiguration für LightTPD findet man anschliessend unter '/etc/lighttpd/lighttpd.conf' und könnte wie folgt aussehen:

# default document-root
server.document-root = "/data/www/htdocs"

accesslog.filename = "/var/log/lighttpd/access.www.log"

server.port = 81

$SERVER["socket"] == "127.0.0.1:80" {
server.username = "nobody"
server.groupname = "nogroup"
server.errorlog = "/var/log/lighttpd/error.www.log"

fastcgi.server = ( ".php" =>
(( "host" => "127.0.0.1",
"port" => 1026,
#"socket" => "/tmp/php-fastcgi.socket",
"bin-path" => "/usr/bin/php",
"bin-environment" => (
"PHP_FCGI_CHILDREN" => "4",
"PHP_FCGI_MAX_REQUESTS" => "100"
),
"bin-copy-environment" => (
"PATH", "SHELL", "USER"
),
"broken-scriptfilename" => "enable"
))
)
# configure server
$HTTP["host"] == "localhost" {
simple-vhost.server-root = "/data/www/"
simple-vhost.default-host = "localhost"
simple-vhost.document-root = "/htdocs/host/"
}

server.document-root = "/data/www/htdocs/host/"
}

# index filenames index-file.names = ( "index.php", "index.html", "index.htm", "default.htm" )

# selecting modules
server.modules = ( "mod_rewrite", "mod_auth", "mod_access", "mod_accesslog", "mod_fastcgi", "mod_redirect", "mod_simple_vhost" )

# disable directory listings
server.dir-listing = "disable"

# mime types
mimetype.assign = (
".pdf" => "application/cation/pdf",
".ps" => "application/postscript",
".gz" => "application/x-gzip",
".pac" => "application/x-ns-proxy-autoconfig",
".swf" => "application/x-shockwave-flash",
".tar.gz" => "application/x-tgz",
".tgz" => "application/x-tgz",
".tar" => "application/x-tar",
".zip" => "application/zip",
".mp3" => "audio/mpeg",
".m3u" => "audio/x-mpegurl",
".wma" => "audio/x-ms-wma",
".ogg" => "application/ogg",
".wav" => "audio/x-wav",
".gif" => "image/gif",
".jpg" => "image/jpeg",
".jpeg" => "image/jpeg",
".png" => "image/png",
".xbm" => "image/x-xbitmap",
".xpm" => "image/x-xpixmap",
".xwd" => "image/x-xwindowdump",
".css" => "text/css",
".html" => "text/html",
".htm" => "text/html",
".js" => "text/javascript",
".dtd" => "text/xml",
".xml" => "text/xml",
".mpeg" => "video/mpeg",
".mpg" => "video/mpeg",
".mov" => "video/quicktime",
".qt" => "video/quicktime",
".avi" => "video/x-msvideo",
".asf" => "video/x-ms-asf",
".asx" => "video/x-ms-asf",
".bz2" => "application/x-bzip",
".tbz" => "application/x-bzip-compressed-tar",
".tar.bz2" => "application/x-bzip-compressed-tar"
)

Da unter Windows fastCGI nicht über Sockets funktioniert, muss es über TCP durch Angabe der Parameter Host und Port konfiguriert werden. Testweise kann man nun LightTPD folgendermassen starten:

/usr/sbin/lighttpd -f /etc/lighttpd/lighttpd.conf

Abschliessend soll man LightTPD noch als Windows NT Service installieren können. Hierfür benötigt man das Dienstprogramm 'cygrunsrv', das man ggf. per 'cyg-apt' nachinstallieren muss. Der Befehl zum einrichten von LightTPD als Service sollte nach meinen Recherchen dann wie folgt aussehen:

cygrunsrv --install lighty --path /usr/sbin/lighttpd --args "-D -f /etc/lighttpd/lighttpd.conf" --disp "cygwin - lightTPD"

Leider hat die Installation als Service bei mir noch nicht geklappt.

Nachdem nun also PHP und LightTPD installiert sind, fehlt nur noch die Datenbank - MySQL. Da für PHP schon mit den Client Bibliotheken compiliert wurde, reicht es aus, wenn über die MySQL Web Seite der MySQL Installer für Windows heruntergeladen wird. Darüber kann man dann MySQL komfortabel über den Setup Wizard installieren und mit dem Testen und Entwickeln loslegen.

Das hier vorgestellte Setup funktioniert übrigens nicht nur wunderbar für PHP, sondern z.b. auch für Ruby (on Rails), Python oder Perl.