Die Artikelreihe zum Thema “Trennung von Webanwendungen untereinander”, die mit fastcgi, suphp und zwei Artikeln über das klassische suexec begann, findet heute ihren
vorläufigen Abschluss mit dem Setup, für das ich mich letztendlich entschieden habe.
Da auf dem von mir angepeilten Zielsystem nur eine Handvoll Präsenzen mit ähnlich wenigen verschiedenen
Webanwendungen ins Hosting kommen wird, könnte ich mich für eine Lösung entscheiden, deren Skalierungsverhalten sie
für “richtiges” Hosting uninteressant macht. Jede Webapplikation bekommt einen eigenen apache, der gleich
unter einer nicht priviligierten uid gestartet wird und auf einem hohen Port von 127.0.0.1 Verbindungen annimmt. Das
Mapping auf die “offizielle” IP und Port 80 übernimmt ein zentraler “normaler” apache als
reverse proxy.
Das ganze Verfahren unter Debian stable mit apache2 zu implementieren war verhältnismäßig einfach. Ich habe mich
bemüht, die Arbeit der Debian-Maintainer so weit wie möglich zu nutzen, da mir das Packaging von apache2
außerordentlich gut gefällt. Also sind ein patch gegen apache2ctl, ein kompletter Rewrite von a2[en|dis][mod|site] und ein severely patched initscript dabei rausgekommen, mit deren Hilfe das Management
der vielen verschiedenen Apaches einfach geworden ist.
Auf dem Zielsystem setzen wir das Verfahren wie folgt ein:
- Jeder Apache bekommt einen eigenen Unix-User (user-appname) mit
eigenem Homedirectory.
- In diesem Homedirectory kann der User nicht schreiben, die Dateien dort gehören user:user-webapps
- unter /home/user-appname/apache wird eine abgespeckte
Apache-Konfiguration hinterlegt, in der auch konfiguriert ist, dass der apache untr dem Account user-appname laufen und auf einem hohen Port unter 127.0.0.1 horchen soll.
- Die Applikation liegt in /home/user-appname/applikation.
- Apache-Module lassen sich mit dem erweiterten a2enmod einfach
lokal aktivieren.
- Der Apache lässt sich dann mit dem erweiterten Initscript einach unabhängig von den anderen apaches starten. Als
Unterscheidung dient der Pfad zur apache.conf.
- Über ~/.apache2-local lässt sich kontrollieren, ob /etc/init.d/apache2-local beim booten die lokalen Apaches wieder starten
soll.
- Der “Haupt-Apache” wird per ProxyPass und ProxyPassReverse so konfiguriert, dass Zugriffe auf den entsprechenden
Namensraum zum “richtigen” User-apache weitergereicht werden.
Auf diese Weise ist sichergestellt, dass die Webapplikationen getrennt voneinander laufen. Per Rechtevergabe im
Dateisystem kann man nun erreichen, dass eine Webapplikation nur dort lesen und schreiben kann, wo es unbedingt
notwendig ist. Die apache-Konfiguration kann entsprechend abgespeckt sein.
Diese Lösung hat natürlich auch ein
paar Nachteile:
- Die Skalierungseigenschaften sind exorbitant schlecht
- Logauswertung macht man geschickterweise im “Haupt-Apache”, weil die “Kind-Apaches” und
damit auch die Webanwendungen ausschließlich 127.0.0.1 als Client-IP sehen. Die wenigsten Webanwendungen können mit
X-Forwarded-For etwas anfangen.
Weitere Nachteile sind mir in den paar Wochen, die das Setup auf dem Zielsystem so bereits in Verwendung ist, noch
nicht aufgefallen.
Update
Dank Anders’ Hinweis habe ich nun mod_rpaf gefunden, das man auf dem “inneren” Apache installiert,
und ihm eine Liste von “guten” Proxies mitgibt. Wenn ein Request von diesem Proxy reinkommt, übernimmt
mod_rpaf die Adresse aus dem X-Forwarded-For-Header, und die Applikation merkt nicht, dass ein Reverse Proxy im Spiel
ist. Auch die Logs sehen so aus als wäre kein Reverse Proxy davor. Hübsch - besonders, da das mod_rpaf in Debian
gleich so konfiguriert daherkommt, dass 127.0.0.1 ein “guter” proxy ist. Sehr fein.
Update
Wenn die Applikation Cookies benutzt, ist zu beachten, dass die Applikation ihre Cookies mit einer Domain versieht, und
zwar in der Regel mit 127.0.0.1:x, weil der Applikations-Apache nicht weiß, unter welchem Domainnamen der Server
letztendlich läuft. Das hat mich mit meinem Blog einige Tage Debuggingarbeit gekostet, und ohne die Hilfe von Garvin,
Isotopp, Rince und anderem wäre das niemals erfolgreich gewesen.
Die Lösung ist in der Konfiguration des Reverse Proxy:
ProxyPassReverseCookieDomain 127.0.0.1:1312 blog.zugschlus.de
ProxyPassReverseCookieDomain 127.0.0.1 blog.zugschlus.de
Der doppelte ProxyPassReverseCookieDomain ist nötig, weil aus irgendwelchen gründen manche Cookies mit und manche
ohne Portnummer gesendet werden.
<p>Marc beschreibt eine Methode Webapplikationen über mehrere Apache-Instanzen sicher voneinander zu trennen - auch wenn man nur eine IP zur Verfügung hat. <br /> Die entsprechenden Patches, Skripte und eine Beschreibung gibt es in seinem Weblog. Ganz ohne Nachteile geht es nicht, vor allem skaliert diese Lösung nicht gut, aber für es gibt sicher genug Anwendungsmöglichkeiten. </p> Comment (1)
Tracked: Feb 18, 23:00