Trennung von Webapplikationen mit Extrainstanzen des Apache
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.
Dieser Artikel entstand ursprünglich im Jahr 2006. Fünf Jahre später hat auch Debian es geschafft, mehrere apache-Instanzen "ordentlich" zu unterstützen, und ganz ohne gepatchte Scripts. Diese überarbeitete Version dieses Artikels beschreibt die Vorgehensweise unter dem in 2011 aktuellen Debian squeeze.
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. Debian hat meine Patches natürlich nicht 1:1 übernommen, aber inzwischen geht es auch ohne gepatchte scripts.
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.
- Diese Konfiguration wird nach /etc/apache2-user verlinkt
- Ein spezielles Initscript /etc/init.d/apache2-user wird aus /usr/share/doc/apache2.2-common/examples/secondary-init-script (z.B. mit /usr/share/doc/apache2.2-common/examples/setup-instance) erzeugt
- Mit insserv apache2-user wird das Initscript aktiviert und an der passenden Stelle in die dependency-based Bootreihenfolge eingehängt
- 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 einfach unabhängig von den anderen apaches starten.
- 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, zum Beispiel den exorbitanten Speicherbedarf duch die wirlich vielen apache-Prozesse im Speicher und die Tatsache, dass manche Webapplikationen sich herausgefordert fühlen, wenn plötzlich Portnummern in den URLs stehen und der Client mit anderen URIs kommt als man selbst weggeschickt hat. Weitere Nachteile sind mir in den fünf Jahren, die das Setup auf dem Zielsystem so bereits in Verwendung ist, bis heute nicht aufgefallen.
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:
Der doppelte ProxyPassReverseCookieDomain ist nötig, weil aus irgendwelchen gründen manche Cookies mit und manche ohne Portnummer gesendet werden.ProxyPassReverseCookieDomain 127.0.0.1:1312 blog.zugschlus.de ProxyPassReverseCookieDomain 127.0.0.1 blog.zugschlus.de
Comments
Display comments as Linear | Threaded