Startseite

Apache HTTP Server als Loadbalancer verwenden

Hier erkläre ich, wie man den Apache HTTP Server (Version 2.4) als Loadbalancer für eigene Internet Dienste verwendet und wie man damit HTTPS Unterstützung hinzufügt.

Diese Anleitung passt zu Debian und Ubuntu Linux. Bei anderen Betriebssystemen ist die Vorgehensweise prinzipiell identisch, allerdings könnten die Kommandos zum Neustarten der Dienste anders heißen und die Konfigurationsdateien liegen womöglich in anderen Verzeichnissen.

Begriffe:

Testumgebung einrichten

Virtuelle Netzwerk-Interface

Ich gehe davon aus, dass nicht jeder Leser drei Server zur Verfügung hat. Deswegen beginnen wir damit, deinem Computer drei IP-Adressen zu geben. Damit kann er die Aufgaben von drei Servern übernehmen.

Bei Desktop Computern macht man das normalerweise in der Systemsteuerung der grafischen Oberfläche. Bei Servern sind die Netzwerkkarten stattdessen häufig in der Datei /etc/network/interfaces konfiguriert, zum Beispiel so:

# IP-Adresse für den Loadbalancer
auto eth0
iface eth0 inet static
address 192.168.2.41
netmask 255.255.255.0
gateway 192.168.2.1

# IP-Adresse für Node 1
auto eth0:0
iface eth0:0 inet static
address 192.168.2.201
netmask 255.255.255.0

# IP-Adresse für Node 2
auto eth0:1
iface eth0:1 inet static
address 192.168.2.202
netmask 255.255.255.0
Die Anleitung dazu findet man im Debian Manual. Aktiviere die Änderungen mit dem Befehl
systemctl restart networking

Apache HTTP Server

Installiere den Apache HTTP Server und aktiviere einige optionale Module durch folgende Befehle:
apt-get install apache2
a2enmod slotmem_shm headers rewrite substitute proxy proxy_balancer proxy_http lbmethod_byrequests ssl
systemctl restart apache2

Teste den Apache HTTP Server, indem du folgende URL mit einem Web-Browser aufrufst: http://192.168.2.41:80/index.html. Es erscheint die Standardseite mit dem Titel "Apache2 Debian Default Page".

In einer realen Anwendung würden die Nodes des Clusters spezielle Anwendungsprogramme mit Webinterface ausführen, zum Beispiel in Java oder PHP programmiert. Wir simulieren diese mit zwei einfachen statischen Webseiten. Füge dazu in die Datei /etc/apache2/ports.conf folgende Zeilen ein:

Listen 192.168.2.201:8080
Listen 192.168.2.202:8080
Dadurch wird der Apache Server angewiesen, HTTP Anfragen auf diesen beiden zusätzlichen IP-Adressen und Port 8080 anzunehmen. Als Nächstes konfigurierst du zwei virtuelle Hosts (Webserver), um festzulegen, welche Webseiten diese ausliefern sollen. Erstelle dazu die neue Datei /etc/apache2/sites-available/nodes.conf mit folgendem Inhalt:
<VirtualHost 192.168.2.201:8080>
        ServerName node1
        DocumentRoot /var/www/node1
        LogLevel warn
        CustomLog ${APACHE_LOG_DIR}/access-node1.log combined
        ErrorLog ${APACHE_LOG_DIR}/error-node1.log
</VirtualHost>

<VirtualHost 192.168.2.202:8080>
        ServerName node2
        DocumentRoot /var/www/node2
        LogLevel warn
        CustomLog ${APACHE_LOG_DIR}/access-node2.log combined
        ErrorLog ${APACHE_LOG_DIR}/error-node2.log
</VirtualHost>
Erstelle die neue Datei /var/www/node1/index.html mit folgendem Inhalt:
<html>
  <body>
    Hello Node 1
  </body>
</html>
Erstelle die neue Datei /var/www/node2/index.html mit folgendem Inhalt:
<html>
  <body>
    Hello Node 2
  </body>
</html>
Aktiviere die Änderungen mit den Befehlen
a2ensite nodes
systemctl restart apache2

Du hast auf deinem Computer nun drei Webserver eingerichtet:

Loadbalancer

Nach der obigen Vorbereitung können wir zum eigentlichen Thema dieses Artikels kommen: Wir fügen zum Apache HTTP Server einen Loadbalancer hinzu. Dieser wird Anfragen aus dem Internet auf die beiden Nodes verteilen.

Füge dazu in die Datei /etc/apache2/ports.conf folgende Zeile ein:

Listen 192.168.2.41:8080
Erstelle die neue Datei /etc/apache2/sites-enabled/loadbalancer.conf mit folgendem Inhalt:
<VirtualHost 192.168.2.41:8080>
        ServerName loadbalancer

        <Proxy balancer://cluster>
                BalancerMember http://192.168.2.201:8080
                BalancerMember http://192.168.2.202:8080
                ProxySet lbmethod=byrequests
        </Proxy>

        ProxyPass / balancer://cluster/
        ProxyPassReverse / balancer://cluster/

        LogLevel warn
        CustomLog ${APACHE_LOG_DIR}/access-loadbalancer.log combined
        ErrorLog ${APACHE_LOG_DIR}/error-loadbalancer.log
</VirtualHost>
Hier wird ein Cluster mit zwei Nodes definiert. Die Methode "byrequests" sorgt dafür, dass die Anfragen abwechselnd auf die Server des Clusters verteilt werden. Es gibt auch andere Methoden, die nach Aktivierung der entsprechenden Module nutzbar sind:

Aktiviere die Änderung mit der Befehlsfolge:

a2ensite loadbalancer
systemctl restart apache2

Nun kannst du die URL des Loadbalancers http://192.168.2.41:8080/index.html aufrufen. Lade die Seite durch die Tastenkombination Strg-F5 mehrmals neu. Du wirst sehen, dass die Anfrage manchmal von Node 1 und manchmal von Node 2 beantwortet wird.

Man kann die URL Pfade ausnutzen, um gezielt einzelne Nodes anzusprechen. Füge dazu folgende Zeilen oberhalb von "ProxyPass / balancer://cluster/" ein:

        ProxyPass /node1/ http://192.168.2.201:8080/
        ProxyPassReverse /node1/ http://192.168.2.201:8080/

        ProxyPass /node2/ http://192.168.2.202:8080/
        ProxyPassReverse /node2/ http://192.168.2.202:8080/
Aktiviere die Änderung mit dem Befehl systemctl restart apache2. Du kannst nun im Web Browser http://192.168.2.41:8080/node1/index.html aufrufen, damit der Proxy deine Anfragen immer an Node 1 weiter leitet. Entsprechend führt http://192.168.2.41:8080/node2/index.html immer zu Node 2.

Man kann auch einzelne Dateien zu anderen Servern umleiten. Zum Beispiel:

        ProxyPass /stefan.html http://stefanfrings.de/index.html
        ProxyPassReverse /stefan.html http://stefanfrings.de/index.html
Aktiviere die Änderung mit dem Befehl systemctl restart apache2. Du kannst nun im Web Browser http://192.168.2.41:8080/stefan.html aufrufen. Diese Anfrage leitet der Proxy nach http://stefanfrings.de/index.html (meiner Homepage) um.

Textersetzungen

Manchmal muss der Inhalt einer Webseite wegen der Umleitung durch den Proxy modifiziert werden, insbesondere wenn sie Links mit der IP-Adresse der Node enthalten. Dies kann man mit dem Substitute Modul realisieren. Füge dazu folgendes in die Datei /etc/apache2/sites-enabled/loadbalancer.conf ein:
        RequestHeader unset Accept-Encoding
        FilterDeclare MySubstitute
        FilterProvider MySubstitute SUBSTITUTE "%{CONTENT_TYPE} =~ m|^text/html|"
        FilterProvider MySubstitute SUBSTITUTE "%{CONTENT_TYPE} =~ m|^.*/xml|"
        FilterChain +MySubstitute
        SubstituteMaxLineLength 10m
        Substitute "s|Hello|Willkommen bei|n"
        Substitute "s|Node|Knoten|n"
        Substitute "s|192.168.2.201:8080|192.168.2.41:8080|n"
        Substitute "s|192.168.2.202:8080|192.168.2.41:8080|n"
Aktiviere die Änderung durch den Befehl systemctl restart apache2. Öffne im Web-Browser die URL http://192.168.2.41:8080/index.html und drücke Strg-F5 um eventuell den Cache zu aktualisieren. Du siehst dann, dass der Text "Hello Node x" in "Willkommen bei Knoten x" geändert wurde.

Damit das Substitue Modul den Inhalt der Webseite durchsuchen und modifizieren kann, muss durch "RequestHeader unset Accept-Encoding" eventuell unterstützte Kompression deaktiviert werden. Die Beschränkung auf bestimmte Content-Types (in diesem Fall HTML und XML Dateien) stellt sicher, dass der Apache HTTP Server nicht versucht, Bilder, Videos oder andere Binärdateien zu modifizieren.

Mit SubstituteMaxLineLength legt man die maximale Länge der Zeilen fest, in denen Text ersetzt werden soll. Längere Zeilen werden übergangen. Diesen Parameter gibt es erst ab Apache 2.4.11.

Beispiel mit regulärem Ausdruck:

        Substitute "s|(test/.*)\.aspx?|$1.php|"
Hier wird "test/irgendwas.aspx" durch "test/irgendwas.php" ersetzt. Das $1 bezieht sich auf den Teil, den die erste Klammer vom regulären Ausdruck gefunden hat.

Sticky Sessions

Manche Web Anwendungen erfordern, dass ein Benutzer stets auf dem selben Server landet, weil die Sitzungsdaten nicht zwischen den Servern synchronisiert werden. Dies erreicht man durch Sticky Sessions. Ändere die Konfigurationsdatei /etc/apache2/sites-enabled/loadbalancer.conf so ab:
<VirtualHost 192.168.2.41:8080>
        ServerName loadbalancer

        Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED

        <Proxy balancer://cluster>
                BalancerMember http://192.168.2.201:8080 route=1
                BalancerMember http://192.168.2.202:8080 route=2
                ProxySet lbmethod=byrequests
                ProxySet stickysession=ROUTEID
        </Proxy>

        ProxyPass / balancer://cluster/
        ProxyPassReverse / balancer://cluster/

        LogLevel warn
        CustomLog ${APACHE_LOG_DIR}/access-loadbalancer.log combined
        ErrorLog ${APACHE_LOG_DIR}/error-loadbalancer.log
</VirtualHost>
Die "Header" Anweisung sorgt dafür, daß der Apache HTTP Server einen zusätzlichen HTTP Header für ein Cookie mit Namen "ROUTEID" hinzufügt. Alternativ kann dies auch durch die programmierte Anwendung auf der Node erledigt werden. Wenn dieses Cookie existiert, verwendet der Loadbalancer immer die darin benannte Node.

Nach dem Befehl systemctl restart apache2 kannst du es ausprobieren, indem du im Web Browser die URL des Loadbalancers http://192.168.2.41:8080/index.html aufrufst. Lade die Seite durch die Tastenkombination Strg-F5 mehrmals neu, um zu sehen, dass nun stets von der selbe Node antwortet.

Sollte der festgelegte Node ausfallen, erkennt der Apache dies nach einigen Sekunden und wechselt selbstständig auf eine andere Node.

Loadbalancer mit SSL

Man kann das SSL Modul des Apache HTTP Server benutzen, um Verschlüsselung hinzuzufügen. Intern laufen die Nodes weiterhin unverschlüsselt mit dem HTTP Protokoll, aber nach außen wird verschlüsseltes HTTPS genutzt. Die HTTPS Implementierung des Apache Servers ist sehr effizient und es gibt eine große Anzahl von Konfigurationsmöglichkeiten.

Füge in die Datei /etc/apache2/ports.conf einen Listener für diese Schnittstelle ein:

Listen 192.168.2.41:8443
Erstelle oder kaufe ein SSL Zertifikat:
cd /etc/apache2
mkdir certificate
cd certificate
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout test.key -out test.crt

Erstelle eine neue Datei /etc/apache2/sites-available/sslproxy.conf mit folgendem Inhalt:

<VirtualHost 192.168.2.41:8443>
        ServerName sslproxy

        <Proxy balancer://cluster>
                BalancerMember http://192.168.2.201:8080
                BalancerMember http://192.168.2.202:8080
                ProxySet lbmethod=byrequests
        </Proxy>
   
        SSLProxyEngine on
        ProxyPass / balancer://cluster/
        ProxyPassReverse / balancer://cluster/

        SSLEngine on
        SSLCertificateFile /etc/apache2/certificate/test.crt
        SSLCertificateKeyFile /etc/apache2/certificate/test.key

        LogLevel warn
        CustomLog ${APACHE_LOG_DIR}/access-sslproxy.log combined
        ErrorLog ${APACHE_LOG_DIR}/error-sslproxy.log
</VirtualHost>
Aktiviere die Änderungen durch die Befehlsfolge:
a2ensite sslproxy
systemctl restart apache2

Teste die Konfiguration indem du im Web Browser die URL https://192.168.2.41:8443/index.html aufrufst. Der Proxy wird die Anfrage wieder an einen der beiden Nodes weiter leiten.

Wenn du das Zertifikat selbst erstellt hast, wird der Browser warnen, dass dieses Zertifikat unsicher sei. Bestätige die Warnung und lege eine Ausnahmeregel an, um die Webseite aufrufen zu können.

Die deutsche Dokumentation des Apache HTTP Servers findest du hier.