HAProxy, Nginx, LXD und Let’s Encrypt

HAProxy, Nginx, LXD und Let’s Encrypt

In meinem letzten Beitrag habe ich beschrieben, wie man verschiedene Webserver, die in einem LXD Container laufen, von außen über einen Reverse-Proxy (in unserem Fall HAProxy) erreichbar machen kann. Diese Setup läuft aber nur über HTTP (Port 80) und damit über einen unverschlüsselte Verbindung. Heutzutage ist es unabdingbar, dass man seine Website auch verschlüsselt. Deswegen möchte ich heute das Setup erweitern, sodass die Webserver über eine verschlüsselte Verbindung erreichbar sind. HAProxy wird dabei SSL/TLS Termination Proxy agieren, d.h. wir müssen nur an einer Stelle alle unsere Zertifikate verwalten und nicht auf jedem einzelnen Webserver selbst. Der Vorteil ist, dass den Webservern Arbeit durch den Proxy abgenommen wird, allerdings muss man wissen, dass die Kommunikation zwischen HAProxy und den Webservern unverschlüsselt erfolgt. Dieses private Netz sollte als sicher angesehen werden. In unserem Fall ist das das Subnet von LXD, in dem sich die Container befinden. Folgende Grafik veranschaulicht den Prozess:

TLS / SSL Termination

Container überprüfen

Zuerst überprüfen wir, ob alle unsere Container laufen und eine IP haben. Das können wir mit dem bekannten lxc list Befehl machen:

Alle unsere Container sind online und haben eine IP-Adresse bekommen. Weiterhin sollten die DNS-Einträge unserer beiden Webserver auf die öffentliche IP des Servers zeigen. Dies können wir z.B. mit dem host-Befehl überprüfen:

Weiterleitung für HTTPS einrichten

Bisher wird nur Traffic, der auf Port 80 auf unserem Server ankommt an den HAProxy Container weitergeleitet. Für HTTPS brauchen wir aber noch eine Weiterleitung für Port 443. Diese können wir mit einer ähnlichen iptables Regel einrichten:

Diese Regel ist nach einem Neustart wieder weg. Um sie dauerhaft einzurichten, kann man z.B. das Paket iptables-persistent installieren.

HAProxy anpassen

Als nächsten müssen wir den HAProxy Konfiguration anpassen. Dazu loggen wir uns als root in dem Container ein:

Nun können wir die Konfigurationsdatei (/etc/haproxy/haproxy.cfg) öffnen (im HAProxy-Container) und anpassen.

Damit unser SSL Setup möglichst sicher ist, fügen wir folgende Zeilen im global Abschnitt hinzu. Ich habe Sie mit dem Mozilla SSL Configuration Generator erzeugt:

Im defaults Block fügen wir folgende Zeilen hinzu:

Nun sind einige Anpassungen im frontend www_frontend Abschnitt notwendig:

In in den Backend Abschnitten müssen wir keine Änderungen vornehmen.

Let’s Encrypt Zertifikate einrichten

Nun brauchen wir für die verschlüsselte Kommunikation noch ein Zertifikat für unsere Webserver. Let’s Encrypt bietet kostenfreie Zertifikate schon seit einigen Jahren an und ab diesem Jahr sogar Wildcard-Zertifikate.

Damit wir die Zertifikate einrichten können, brauchen wir den Let’s Encrypt Client, den wir wie folgt installieren (im HAProxy Container):

Wir generieren ein Zertifikat, welches für alle unsere Domains gültig ist:

Wenn alles geklappt hat, haben wir nun ein gültiges Zertifikat für unsere beiden Webserver. Jetzt müssen wir nur noch HAProxy die richtigen Zertifikate zur Verfügung stellen. Dazu müssen wir die Certificate Chain und den Private Key zusammenfügen, damit HAProxy etwas damit anfangen kann. Wir legen im ersten Schritt das Zielverzeichnis an und fügen dann die Zertifikate und den Key zusammen:

Zum Schluss starten wir den HAProxy neu:

Testen

Wir sind fast am Ziel und möchten unsere Domains noch testen, ob auch alles richtig konfiguriert wurde.  Zuerst rufen wir die Seiten in einem Webbrowser auf. Es sollte neben der Adresse ein grünes Schloss erscheinen (im Firefox). Weiterhin sollten wir noch einen SSL Server Test durchführen. Das Ergebnis lässt sich sehen:

SSL Test Result

Fazit

Mit wenigen Schritten haben wir ein Setup geschaffen, in dem wir mehrere Webseiten nach außen hin erreichbar machen können. Das Ganze lässt sich leicht erweitern und skalieren. Besonders angenehm finde ich die Verwaltung der Zertifikate an einer Stelle und nicht auf jedem Webserver einzeln. LXD und Let’s Encrypt, sowie HAProxy sind für mich eine der großen persönlichen Entdeckungen der letzten zwei Jahre.

Was sind für dich die größten Herausforderung bei der Bereitstellung von Webservern?

4 Gedanken zu „HAProxy, Nginx, LXD und Let’s Encrypt

  1. Hallo,

    gern gehe ich auf die Frage am Ende deines lesenswerten Artikels ein.

    Die größte Herausforderung besteht für mich darin, mir bereits bei der Bereitstellung eines Webservers, die notwendigen Gedanken für den folgenden Betrieb zu machen. Denn die meisten Probleme treten meiner Erfahrung nach nicht während der Bereitstellung sondern erst später im Betrieb auf.

    Hier gilt es Betriebsunterbrechungen aufgrund von Updates z.B. des PHP-Interpreters oder der Webanwendungen zu vermeiden und Probleme bei der automatischen Zertifikatsverlängerung rechtzeitig zu erkennen.

    Gruß
    Tronde

  2. Hi Tronde,

    das stimmt. Im Schulumfeld haben wir dieses Problem nicht so stark, dass die Dienste hauptsächlich außerhalb der Ferien genutzt werden 🙂

    Theoretisch kann man das aber auch mit LXD auffangen. Man macht einen Snapshot und kopiert diesen Snapshot als in einen neuen Container und führt die Updates durch. Wenn alles passt nimmt man die Kopie als neuen „Master“. So verringert man die Down-Time.

    Wir setzen weiterhin Check_mk auf allen unseren Servern ein. Dort kann man sich auch einen Check für die Zertifikate einbauen und bestimmen wie viel Tage man vorher informiert werden möchte. Das schöne an Let’s Encrypt ist ja auch, dass man die Erneuerung automatisieren kann.

    Gruß,
    Stephan

  3. Hallo Stephan,

    > Das schöne an Let’s Encrypt ist ja auch, dass man die Erneuerung automatisieren kann.

    Und hierbei muss man dafür sorgen, im Fehlerfall rechtzeitig informiert zu werden. In der Vergangenheit verwendete ich den Client acme-tiny, welcher plötzlich nicht mehr funktionierte und mit Ausnahmefehlern abstürzte. Dank Monitoring hatte ich noch genügend Zeit, um zu reagieren.

    Gruß
    Tronde

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.