phpmyadmin sicher(er) zur Verfügung stellen

Möchte man phpmyadmin mehreren Domains zur Verfügung stellen, so bietet sich dafür das Debian-Paket „phpmyadmin“ an:

1
apt-get install phpmyadmin

Danach kann man unter /etc/phpmyadmin/apache.conf eine config finden, die man per

1
ln -s /etc/phpmyadmin/apache.conf /etc/apache2/conf.d/phpmyadmin.conf

in das Apache-Verzeichnis einbindet.

Jetzt muss an hier aber noch ein wenig gefeilt werden, denn so stellt man phpmyadmin grundsätzlich auch über HTTP – also unverschlüsselt – zur Verfügung. Administriert jetzt jemand über ein öffentliches Netzwerk seine Datenbank (immer an den DAU denken, auch wenn es sich erst mal vollkommen an den Haaren herbeigezogen anhört), hat man ruck-zuck ein Problem.

Deshalb leite ich grundsätzlich alle HTTP-Anfragen an phpmyadmin einfach nach HTTPS weiter. Dazu öffnet man die /etc/phpmyadmin/apache.conf und fügt ganz oben folgenden Text ein:

1
2
3
4
5
6
7
8
9
<IfModule mod_rewrite.c>
        <IfModule mod_ssl.c>
                <Location ~ "/phpmyadmin(/|$)">
                        RewriteEngine on
                        RewriteCond %{HTTPS} off
                        RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI}
                </Location>
        </IfModule>
</IfModule>

Jetzt wird jeder Besucher von http://domain.de/phpmyadmin zu https://domain.de/phpmyadmin umgeleitet, was phpmyadmin ein ganzes Stück sicherer macht. Trotzdem ist zu überlegen, ob man die Software nicht lieber zusätzlich mit einem .htaccess-Schutz versieht. Wie das geht, erfährt man unter anderem bei SELFHTML.

SoftAP oder: „Wie verwende ich meine WLAN-Karte als Router?“

Windows 7 verfügt über eine Fähigkeit, über die nur wenige Bescheid wissen: Mit zwei einfachen Befehlen verwandelt man jede aktuelle WLAN-Karte in einen (sehr einfachen) Router, über den Clients per ICS (Internet Connection Sharing) auch die Internetverbindung mitbenutzen kann. Der sogenannte SoftAP enthält dabei auch einen DHCP-Server, sodass man sich um die manuelle Vergabe von passenden IP-Adressen keine Sorge machen muss.

Hier nun die Vorgehensweise:

  1. Das Startmenü öffnen
  2. cmd tippen – Rechsklick -> als Administrator ausführen
  3. netsh wlan set hostednetwork mode=allow ssid="mynet" key="mynetpassword" keyUsage=persistent
  4. netsh wlan start hostednetwork
  5. Netzwerk & Freigabecenter -> Adaptereinstellungen -> Rechtsklick auf den Adapter, der die Verbindung zum Internet herstellt -> Eigenschaften
  6. Registerkarte „Freigabe“
  7. Häkchen bei „Anderen Benutzern im Netzwerk gestatten…“ setzen und den neu geschaffenen virtuellen Adapter als Heimnetzverbindung auswählen

Ggf. nach einem Neustart der Internetverbindung steht diese dann über WLAN zur Verfügung. Dazu wählen sich die Clients einfach in das neu geschaffene Netz ein (dieses erscheint nicht als Ad-Hoc-Netz sondern als reguläres WLAN).

Aussschalten kann man den SoftAP natürlich auch:

netsh wlan stop hostednetwork

Für Windows vor Windows 7 steht mit Connectify für rund 35 Euro eine Lösung zur Verfügung und unter Linux gibt es wie hier im Ubuntu-Wiki beschrieben die Möglichkeit, solch ein Netz via hostapd aufzubauen.

Passwörter aus dem Windows Credential Manager auslesen

Eine ganz nützliches Programm, über das ich vor kurzem beim Umzug auf einen neuen Laptop gestoßen bin, möchte ich dem geneigten Leser nicht vorenthalten: Network Password Recovery. Damit kann man Passwörter, die im Windows Credential Manager gespeichert sind (z.B. Remote-Anmeldeinformationen im LAN oder das Passwort für die Windows Live ID), auslesen.

Mithilfe dieses Tools konnte ich 2 Passwörter für LAN-PCs wiederherstellen und mir so eine Passwortänderung auf diesen Maschinen ersparen. Die Software wird kostenlos von Nirsoft (u.a. bekannt für das Kommandozeilenutility NirCmd) zum Download angeboten und ist nur rund 500kB groß. Probleme bereiten dem Tool nur das Heimnetzgruppen-Passwort und Passwörter aus virtualapp/digital (hier ist zudem nicht ganz klar, wozu diese dienen). Für meine Zwecke war es also perfekt 🙂

Nodejs-Server via Apache-Reverse-Proxy und Monit

Um einen Nodejs-Server aufzusetzen braucht es nicht viel. Eigentlich nur die Binaries und eine JS-Datei mit dem eigentlichen Server. Doch wenn man den Server dauerhaft und bequem zugreifbar betreiben möchte, sind ein paar mehr Schritte notwendig.

Zunächst wird Nodejs und der Paketmanager npm installiert:

1
apt-get install nodejs npm

Danach richten wir den Proxy ein, sonst wäre ein Aufruf nur über einen Nicht-Standard-Port (80 ist ja schon vom Apachen belegt) möglich. In der Regel verwendet Nodejs hier Port 3000, aber das ist je nach Script unterschiedlich. Wir aktiviren also zunächst den Passthrough-Modus:

1
2
a2enmod proxy
a2enmod proxy_http

Für die eigentliche Einrichtung kann jetzt ein eigener VHost (z.B. eine Subdomain) angelegt werden, oder – wie in meinem Beispiel – ein Unterverzeichnis hergenommen werden.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<VirtualHost ip:80>
	ServerName   myhost.com:80
	ServerAlias  www.myhost.com
	UseCanonicalName Off
	DocumentRoot /var/www/vhosts/myhost/httpdocs
	ErrorLog  /var/www/vhosts/myhost/statistics/logs/error_log
 
	...
 
	<Directory /var/www/vhosts/myhost/httpdocs>
		Options -Includes +ExecCGI
	</Directory>
 
	<Proxy *>
  		Order deny,allow
  		Allow from all
	</Proxy>
 
	<Location /mynodejspath>
  		ProxyPass http://localhost:3000
  		ProxyPassReverse http://localhost:3000
	</Location>
</VirtualHost>

Würde man nun nodejs manuell starten, könnte man schon per http://myhost.com/mynodejspath darauf zugreifen. Da Nodejs aber noch ein wenig fehleranfällig ist und dann gern mal sang- und klanglos abtritt, benutze ich monit zur Überwachung und ggf. zum Neustart des Servers (der Nodejs-App).

1
apt-get install monit

Als Startscript verwende ich ein Standard-init.d-Script, sodass ich auch beim Systemstart problemlos den Nodejs-Server mitstarten lassen kann. Dabei ist zu beachten, dass ich auf Benutzer „root“ prüfe und den Nodejs-Server ggf. über einen extra User starte. Andere Nutzer starten die Nodejs-App mit diesem Script als sie selbst.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/bin/bash
DIR=/var/www/vhosts/myhost/httpdocs/mynodejspath
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
NODE_PATH=/usr/lib/node_modules
NODE=/usr/bin/node
 
test -x $NODE || exit 0
 
function start_app {
  if [ $(whoami) = "root" ]
  then
    NODE_ENV=production nohup sudo -u nodejsusername "$NODE" "$DIR/app.js" 1>>"$DIR/logs/node.log" 2>&1 &
    echo $! > "$DIR/pids/node.pid"
  else
    NODE_ENV=production nohup "$NODE" "$DIR/app.js" 1>>"$DIR/logs/node.log" 2>&1 &
    echo $! > "$DIR/pids/node.pid"
  fi
}
 
function stop_app {
  kill `cat $DIR/pids/node.pid`
}
 
case $1 in
   start)
      start_app ;;
    stop)
      stop_app ;;
    restart)
      stop_app
      start_app
      ;;
    *)
      echo "usage: myapp {start|stop|restart}" ;;
esac
exit 0

Die Verzeichnisse „pids“ und „logs“ müssen unter dem App-Pfad noch angelegt werden. Danach kommt das Monit-Script nach /etc/monit/noderc:

1
2
3
4
5
6
7
8
9
10
#!monit
set logfile /var/log/monit.log
 
check process nodejs with pidfile "/var/www/vhosts/myhost/httpdocs/mynodejspath/pids/node.pid"
    start program = "/etc/init.d/myapp start"
    stop program  = "/etc/init.d/myapp stop"
    if failed port 3000 protocol HTTP
        request /
        with timeout 10 seconds
        then restart

… und ein Starter-init.d Script nach /etc/init.d/monit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash
 
case $1 in
   start)
      monit -d 60 -c /etc/monit/noderc
      ;;
    stop)
      killall monit
      ;;
    restart)
      stop_app
      start_app
      ;;
    *)
      echo "usage: monit {start|stop|restart}" ;;
esac
exit 0

Ein Symlink nach rc2.d komplettiert die Automatisierung:

1
2
cd /etc/rc2.d/
ln -s ../init.d/monit S99monit

 

Somit haben wir viele Probleme gelöst:

  • Nodejs startet mit dem Server
  • Es wird überwacht und falls notwendig neu gestartet
  • Der Jeweilige Besitzer (und root) können es manuell neu starten
  • Es läuft mit eingeschränkten Userrechten
  • Es ist über Port 80 zugreifbar
  • und wir haben wieder etwas gelernt 😉

Lange Zend DB-Queries bringen PHP/Apache zum Absturz

Beim Programmieren einer Anwendung mit Zend und IBM DB2 bin ich auf ein Phänomen gestoßen, das zunächst unerklärlich schien. Führte ich einen langen Query aus (in diesem Fall sollte ein längerer XML-String in ein XML-Datenfeld der IBM DB2 Express-C geschrieben werden), so stürzte Apache ohne Fehlermeldung ab. In den Logs tauchte nur „restarting“ auf, sonst nichts.

Nach etwas Recherche stellte sich heraus, dass wohl eine fehlerhafte Implementierung der PCRE-Erweiterung Schuld an dem Desaster ist. Ist Backtracking auf einen zu hohen Wert eingestellt, so konsumiert PCRE (Zend Framework benutzt preg_match(), um SQL-Queries auf Korrektheit zu prüfen) den gesamten Stack, wodurch der Prozess sang- und klanglos abgeschossen wird.

Eine Erklärung zu PCRE-Backtracking gibt es hier: http://www.regular-expressions.info/catastrophic.html.

Für PHP ist die Lösung relativ simpel, der voreingestellte Wert von 100.000 für pcre.backtrack_limit und pcre.recursion_limit muss (entgegen einiger Aussagen in diversen Bugreports und Tutorials) heruntergesetzt werden. In meiner PHP.ini sieht das zurzeit folgendermaßen aus:

1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
[Pcre]
;PCRE library backtracking limit.
; http://php.net/pcre.backtrack-limit
pcre.backtrack_limit=1000
 
;PCRE library recursion limit.
;Please note that if you set this value to a high number you may consume all
;the available process stack and eventually crash PHP (due to reaching the
;stack size limit imposed by the Operating System).
; http://php.net/pcre.recursion-limit
pcre.recursion_limit=1000

Damit laufen meine Queries (~1800 Zeichen pro Query) anstandslos durch. Bei Bedarf kann dieser Wert auch weiter abgesenkt werden, auf 500 zum Beispiel. Da die PCRE-Funktion einen Aufwand von O(2^n) hat, bringt auch diese relativ kleine Änderung wieder recht viel.

Gitlab aufsetzen unter Debian/Ubuntu mit Apache

github.com ist ein großartiges Tool für Open Source Projekte auf der ganzen Welt. Es stellt einfachen Zugriff auf das git-Versionierungssystem zur Verfügung, ohne dass man sich um die Befehle für das Erstellen und Warten eines solchen Repos Gedanken machen müsste.

Das ist toll, allerdings hat github einen Nachteil: für private Repositories – also solche, bei denen der Code nicht der ganzen Welt zur Verfügung steht – werden (relativ hohe) Gebühren fällig. Somit ist dieses Tool für kommerzielle Zwecke nur bedingt geeignet, falls man nicht die „Plans“ (github: Plans & Pricing) in Anspruch nehmen möchte.

Lange Zeit gab es keine Softwarelösung, die man sich auf dem eigenen Server installieren konnte, und die ähnlichen Komfort wie github zu bieten hatte. Doch seit einiger Zeit etabliert sich eine solche Lösung: Gitlab. Das Tool steht github kaum noch in etwas nach und kann kostenfrei auf (fast) jedem Rootserver betrieben werden:

  • Ubuntu Linux
  • Debian/GNU Linux
  • Fedora
  • CentOs
  • RedHat.

Zur Installation reichen je nach Komplexität der Installation einige wenige Schritte aus, mehr Komfort gibt es – wie immer – mit mehr Schritten. Doch zunächst das Basis-Setup:

Wer ein paar Basis-Programme nicht installiert hat, muss dies zuerst nachholen:

1
sudo apt-get install wget git git-core build-essential libyaml-dev

Als Nächstes laden wir das Installscript von gitlab herunter und installieren es, was uns viel Arbeit erspart. Es ist dabei von Vorteil, noch kein RubyOnRails installiert zu haben (falls Ruby schon installiert ist, muss es zwingend Ruby 1.9.2 oder besser sein). Ansonsten muss das Script angepasst werden, die Befehle sind relativ selbsterklärend. Hier nun die Variante mit Script (Download-Adresse aktualisiert 19.10.2012):

1
2
3
wget https://raw.github.com/gitlabhq/gitlab-recipes/master/install/debian_ubuntu.sh
chmod +x debian_ubuntu.sh
./debian_ubuntu.sh

Alternativ sind Schritte 1-4 dieser Anleitung auszuführen.

Nun setzen wir die Komponenten für den Ruby-Server auf:

1
2
3
4
5
6
7
sudo gem install charlock_holmes
sudo pip install pygments
sudo gem install bundler
cd /home/gitlab
sudo -H -u gitlab git clone git://github.com/gitlabhq/gitlabhq.git gitlab
cd gitlab
sudo -u gitlab cp config/gitlab.yml.example config/gitlab.yml
1
2
3
sudo -u gitlab cp config/database.yml.sqlite config/database.yml
ODER
sudo -u gitlab cp config/database.yml.example config/database.yml

Nachdem die Datenbank-Konfiguration kopiert wurde, müssen bei MySQL die Verbindungsparameter angepasst werden. SQLite läuft sofort „out of the box“.

Im folgenden Schritt initialisieren und konfigurieren wir Gitlab für den Ruby-Server, anschließend testen wir die Umgebung:

1
2
3
sudo -u gitlab -H bundle install --without development test --deployment
sudo -u gitlab bundle exec rake gitlab:app:setup RAILS_ENV=production
sudo -u gitlab bundle exec rake gitlab:app:status RAILS_ENV=production
1
2
3
4
5
6
7
8
9
10
11
12
Starting diagnostic
config/database.yml............exists
config/gitlab.yml............exists
/home/git/repositories/............exists
/home/git/repositories/ is writable?............YES
remote: Counting objects: 603, done.
remote: Compressing objects: 100% (466/466), done.
remote: Total 603 (delta 174), reused 0 (delta 0)
Receiving objects: 100% (603/603), 53.29 KiB, done.
Resolving deltas: 100% (174/174), done.
Can clone gitolite-admin?............YES
UMASK for .gitolite.rc is 0007? ............YES

Der Output des Testbefehls sollte keine „failed“- oder „no“- Einträge haben. Falls alle Zeichen auf „grün“ stehen können wir den Server starten.

1
2
sudo -u gitlab bundle exec rails s -e production -d
./resque.sh

Der Server läuft nun und ist über Port 3000 bereits zugreifbar (nicht wundern, der erste Seitenaufruf dauert ziemlich lange). Wem das reicht, der ist bereits fertig.

Ich selbst mag meine Web-Anwendungen alle über HTTP(S) abrufen, so auch gitlab. Dazu nutze ich nicht die vom Tutorial vorgeschlagene Variante nginx + Unicorn sondern Passenger für Apache (weil Apache bei mir für alle Webanwendungen genutzt wird und Unicorn viel zu umständlich für kleine bis mittlere Installationen ist):

1
2
gem install passenger
passenger-install-apache2-module

Bei der Installation einfach den Anweisungen folgen, es sind ja nicht viele. Danach kann ein VirtualHost für gitlab angelegt werden, wichtig dabei: DocumentRoot muss auf das „public“-Verzeichnis von gitlab zeigen! Schon kann man z.B. über http(s)://gitlab.yourdomain.com auf gitlab zugreifen und loslegen.

Wichtig: Passenger ersetzt quasi den Deploy-Prozess von gits bundle exec, d.h. der Server auf dem Port 3000 muss dann nicht mehr laufen. Wenn man die Wartezeit für den ersten Besucher von gitlab nach dem Serverstart verkürzen will kann man den Apache wie folgt konfigurieren:

1
2
3
4
5
6
7
8
9
PassengerPreStart https://git.yourdomain.com/
 
<VirtualHost ip:443 >
        ServerName git.yourdomain.com
        UseCanonicalName Off
        DocumentRoot /home/gitlab/gitlab/public
 
        PassengerMinInstances 1
        ...

Als optionalen Schritt kann man nun noch ein Shell-Script für init.d schreiben, damit man resque nach einem Neustart nicht immer von Hand aufrufen muss:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#! /bin/bash
### BEGIN INIT INFO
# Provides:          gitlab
# Required-Start:    $local_fs $remote_fs $network $syslog redis-server
# Required-Stop:     $local_fs $remote_fs $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: resque service for gitlab
# Description:       resque service for gitlab
### END INIT INFO
 
NAME=resque
DESC="resque service"
RESQUE_PID=/home/gitlab/gitlab/tmp/pids/resque_worker.pid
 
case "$1" in
  start)
        CD_TO_APP_DIR="cd /home/gitlab/gitlab"
        START_RESQUE_PROCESS="./resque.sh"
 
        echo -n "Starting $DESC: "
        if [ `whoami` = root ]; then
          sudo -u gitlab sh -l -c "$CD_TO_APP_DIR > /dev/null 2>&1 && $START_RESQUE_PROCESS"
        else
          $CD_TO_APP_DIR > /dev/null 2>&1 && $START_RESQUE_PROCESS
        fi
        echo "$NAME."
        ;;
  stop)
        echo -n "Stopping $DESC: "
        kill -QUIT `cat $RESQUE_PID`
        echo "$NAME."
        ;;
  restart)
        echo -n "Restarting $DESC: "
        kill -USR2 `cat $RESQUE_PID`
        echo "$NAME."
        ;;
  reload)
        echo -n "Reloading $DESC configuration: "
        kill -HUP `cat $RESQUE_PID`
        echo "$NAME."
        ;;
  *)
        echo "Usage: $NAME {start|stop|restart|reload}" >&2
        exit 1
        ;;
esac
 
exit 0

Diese Datei speichern wir unter /etc/init.d/resque und machen es mit

1
sudo chmod +x /etc/init.d/resque

ausführbar. Danach noch einen symbolischen Link nach /etc/rc2.d/ anlegen

1
2
cd /etc/rc2.d
ln -s /etc/init.d/resque S99resque

Fertig.

Achtung: Das von Gitlab angelegte Admin-Passwort ist immer gleich, d.h. es ist zu empfehlen, sich einen eigenen Account mit Administrationsrechten anzulegen und den Admin-Account dann zu blocken, oder das Passwort des Admin-Accounts zu ändern.

Einzelne Datenbank/Tabelle aus MySQL-Dump wiederherstellen

Auf meinem Rootserver läuft jeden Tag ein Backup mit fwbackups, welches meine Dateien und Datenbanken mittels externem Script sichert und, ebenfalls mit Hilfe eines externen Scripts, auf einen FTP-Backupspace lädt. Das ist – einmal eingerichtet – sehr komfortabel. Möchte ich nun aber an die Daten heran und nur eine Datenbank oder Tabelle zurückspielen so müsste ich eigentlich einen zweiten MySQL-Server starten, das Backup einspielen und dann nur das gewünschte exportieren. Das wäre extrem umständlich, daher habe ich nach einem einfacheren Weg gesucht und ihn auch gefunden:

Nur eine Datenbank zurücksichern:

sed -n '/^-- Current Database: `dbname`/,/^-- Current Database: `/p' dumpfile > dbname.sql 2>error

Nur eine Tabelle zurücksichern:

sed -n -e '/CREATE TABLE.*mytable/,/CREATE TABLE/p' mysql.dump > mytable.dump

Hat man mehrere Tabellen, die ähnlich heißen sollte man Backquotes für die Namen verwenden.

 
Danke an uloBasEI von stackoverflow.com und Prabhat Kumar von adminlinux.blogspot.com für diese Tipps.

//Update: Danke an Kai Hessing, der mich per Mail aufmerksam gemacht hat, dass es mit obriger SQL-Anweisung ein Problem gibt, wenn die Tabelle vor der Rücksicherung schon existiert. Also dann entweder die Tabelle erst löschen oder folgendes Kommando benutzen:

sed -n -e '/DROP TABLE.*MYTABLE/,/UNLOCK TABLES/p' $BACKUPDIR/$FILE > $BACKUPDIR/$FILE.mytable

10 falsche Vorstellungen über PHP

Ich mag PHP. Habe es schon immer gemocht, seit ich in meiner Schulzeit von HTML(3)-Markup – was ich davor für Programmieren hielt – zu echten Programmiersprachen gewechselt bin. PHP ist einfach zu erlernen, bietet viel Komfort und, unter Beachtung verschiedener Voraussetzungen, eine hohe Performance bei Nutzung relativ weniger Systemressourcen. Zudem ist es (fast) überall im Web verfügbar, egal ob beim Free-Hoster mit Werbefinanzierung oder auf dem 800-Euro-pro-Monat-Rootserver.

Hartnäckig halten sich allerdings zahlreiche Gerüchte über PHP, von schlechter Performace (sehr häufig) über Bedenken wegen fehlender Objektorientierung bis zur Angst, dass Zend aufgrund seiner Vormachtstellung im Development von PHP die Sprache vollständig kontrolliert. Manuel Lemos hat dazu auf phpclasses.org einen sehr guten Artikel verfasst, den sich jeder Interessierte mal zu Gemüte führen sollte. Sogar als erfahrener Developer kann man dort noch das ein oder andere, das man vielleicht noch nicht wusste, erfahren. Oder wussten Sie, dass man mit PHP Windows-Dienste erstellen kann?

„Can’t connect to X11 window server“-Error

Als ich letztens eine Serverwartungs-GUI über mein VNC lassen wollte bekam ich auf einmal eine komische Fehlermeldung:

Can't connect to X11 window server using ':1.0' as the value of the DISPLAY variable.

Nach etwas googeln hat mir dann stress_junkie vom Forum linuxquestions.org die Erklärung (inklusive Lösung) geliefert:

If the Java program is running under your own account then the problem comes from DISPLAY being incorrectly defined. Try this:

export DISPLAY=“:0.0″

If a different user account is running the program then the user account that „owns“ the console must add permission for others to display on „their“ X display. Try this:

xhost +local:all

If the program is being used on a different computer, say 192.168.3.5 then try this:
Code:

xhost +inet:192.168.3.5

Ich wollte die GUI nämlich über einen anderen User laufen lassen. Nachdem ich bei diesem den Befehl xhost +local:all ausgeführt hatte, konnte ich zurück zum ausführenden User wechseln und das Programm problemlos starten. Denn nun hatte es die Berechtigung, das X11 window des xterm-Besitzers benutzen zu dürfen.

Hosting absichern: Apache2 mit ITK-MPM

Für Multiuser-Environments wie eine Hosting-Umgebung stellt sich spätestens ab einer gewissen Userzahl die Frage nach der Absicherung bzw. Abschottung der einzelnen User voneinander. Dafür gibt es verschiedene Varianten, die allesamt unterschiedliche Vor- und Nachteile haben.

Stuart Herbert hat sich dankenswerter Weise schon vorher die Mühe gemacht, die 5 gängigsten Varianten (suphp, mpm-peruser, mpm-itk, PHP + FastCGI und suexec + PHP + FastCGI) einem Vergleich zu unterziehen. Zwar sind die durchgeführten Performance-Tests mit Vorsicht zu genießen (sie spiegeln in keiner Weise ein realitätsnahes Szenario wieder und übersteigern die Performanceverluste erheblich), aber die Artikel vermitteln dennoch ein sehr gutes Bild der jeweiligen Verfahren und ihrer Stärken und Schwächen.

Ich habe mich für meinen Server schlussendlich für mpm-itk entschieden, da es sehr flexibel ist, alle Vorteile von mod_php weiterhin genutzt werden können und der zusätzliche Speicher- und CPU-Bedarf nicht ganz so extrem ist wie bei mpm-peruser. Zudem setzt die Sicherung im Gegensatz zu den fcgi-Varianten hier bereits im Apachen – also an der richtigen Stelle – an. Die Performance-Einbußen sind, anders als der Test es vermuten lassen würde, im Praxisbetrieb sehr moderat.

Um Apache2 mit ITK-MPM einzurichten bedarf es – vorausgesetzt Apache2 ist bereits installiert – unter Ubuntu/Debian nur eines kurzen Befehls:

apt-get install apache2-mpm-itk

Ein vermutlich vorhandenes anderes MPM (Multi-Processing Module) (standardmäßig dürfte das apache2-mpm-prefork sein) wird bei der Installation automatisch entfernt. Es kann also immer nur ein MPM gleichzeitig tätig sein, was ja auch logisch ist.

Nach dem automatisch durchgeführten Apache-Neustart ist das Modul sofort einsatzbereit. Um Gebrauch davon zu machen fügt man in den VirtualHost-Eintrag folgendes ein:

<VirtualHost *:80>
  ServerName www.example.com
  ...
 
  <IfModule mpm_itk_module>
    AssignUserId username groupname
    MaxClientsVHost 50
    NiceValue 10
  </IfModule>
</VirtualHost>

Alle Angaben sind optional. Wird kein Username zugewiesen läuft die jeweilige Domain unter dem Standard-User und der Standard-Gruppe (normalerweise www-data). Der MaxClients-Eintrag ermöglicht es (wie der Name schon sagt), die maximale Anzahl Clients für diesen spezifischen VHost festzulegen. Mit dem nice-Parameter kann man schlussendlich die Prozesspriorität pro VHost regeln (negative Werte = Priorität niedriger als normal).

Update: Es ist wichtig, jedem vHost auch wirklich eine User-Id zuzuordnen. Anderenfalls wird die Id von Apache genommen, was idR dann root ist („Note that if you do not assign a user ID, the default one from Apache will be used.“ lautet der lapidare Hinweis auf der Projektwebsite).