
HAProxy - Route HTTP-Anfragen auf verschiedene Applikationen
- Gerrit Lükens
- Server , Infrastruktur
- 13. Mai 2024
Table Of Contents
HAProxy ist ein freier, schneller und zuverlässiger reverse-proxy, mit welchem man TCP- und HTTP-Verkehr umleiten kann. Es kann als Alternative zu z.B. nginx benutzt werden, um mehrere Web-Server hinter einer IP und Ports 80/443 zu betreiben, in dem man die Anfragen über Sub-Domains zuordnet.
Anwendungsbeispiel
Installation und Konfiguration
Falls HAProxy nicht auf dem System installiert ist, kann man es über den Paketmanager installieren:
sudo apt install haproxy
Danach findet man die Konfigurationsdatei unter /etc/haproxy/haproxy.cfg. Hier muss man zwei Sektionen anlegen backend and frontend. Zwei Beispiele für eine Backend-Konfiguration, eine für HTTP und eine für HTTPS, werden im Folgenden gezeigt und können zusammen benutzt werden:
backend myservice-http
mode http
balance roundrobin
server myservice 127.0.0.1:81 check
backend myservice-https
mode tcp
balance roundrobin
option ssl-hello-chk
server myservice 127.0.0.1:444 check
Die zugehörigen Frontend-Blöcke sehen dann wie folgt aus:
frontend http
mode http
# bind all incoming traffic on port 80 for ipv6 and ipv4
bind :::80
bind :80
# use_backend [identifier] if { [acl] }
use_backend myservice-http if { hdr(host) -i subdomain.website.de }
frontend https
mode tcp
# bind all incoming traffic on port 443 for ipv6 and ipv4
bind :::443
bind :443
# instructs HAProxy to wait five seconds before closing the connection unless its a ssl connection
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
# use_backend [identifier] if { [acl] }
use_backend myservice-https if { req_ssl_sni -i subdomain.website.de }
Um Veränderungen testen zu können, ohne sie direkt anzuwenden, kann man folgenden Befehl nutzen:
/usr/sbin/haproxy -c -V -f /etc/haproxy/haproxy.cfg
Nach der Überprüfung muss haproxy noch neugestartet werden, um die Änderungen zu übernehmen:
sudo systemctl restart haproxy
SSL-Terminierung
Mit der oben stehenden Konfiguration wird der eingehende TLS-Verkehr verschlüsselt an das entsprechende Backend weitergereicht. HAProxy bietet auch die Möglichkeit die Terminierung des TLS-Verkehrs zu übernehmen (Quelle) .
Dazu muss man im https-Frontend die bind-Direktive verändern:
bind :443 ssl crt /path/to/cert.pem
Dabei muss die Zertifikats-Datei, hier cert.pem, sowohl die domain.cer als auch die domain.key enthalten. Diese Dateien werden von der CA bereitgestellt wie z.B Lets Encrypt oder ZeroSSL . Dazu muss der Inhalt der Dateien einfach zusammen kopiert werden, z.B. über:
cat domain.cer domain.key > cert.pem
Weiterhin muss man darauf achten, dass es sich durch die SSL-Terminierung nun um HTTP-Verkehr handelt. Daher muss zum Filtern der Domains jetzt hdr(host) anstatt req_ssl_sni verwendet werden. Eine Konfiguration könnte also wie folgt aussehen:
frontend https
mode http
bind :::443 ssl crt /path/to/cert.pem
bind :443 ssl crt /path/to/cert.pem
use_backend myservice-https if { hdr(host) -i subdomain.website.de }
Mixed-Mode Terminierung
In der Konfiguration zur SSL-Terminierung wird jeglicher eingehender TLS-Verkehr terminiert. Möchte man nur einen Teil des Verkehrs terminieren und einen anderen Teil direkt an ein Backend weiterleiten, muss dies vor dem “Terminierungs”-Frontend passieren. Dazu wird ein weiteres Frontend neben http und https benötigt:
frontend ssl_passthrough
mode tcp
bind :::443
bind :443
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
use_backend myservice-https if { req_ssl_sni -i subdomain.website.de }
default_backend bk_tcp_to_https
backend bk_tcp_to_https
mode tcp
server haproxy-https 127.0.0.1:8080 check
frontend https
mode http
bind :8080 ssl crt /path/to/cert.pem
use_backend myservice-https if { hdr(host) -i subdomain.website.de }
Hier wird jetzt der TLS-Verkehr auf Port 443 zunächst an das ssl_passthrough geleitet. Hier werden nun alle Domains, für die TLS nicht terminiert werden soll, auf ihr entsprechendes Backend geleitet. Jeglicher Verkehr der nicht umgeleitet wird, wird über die default_backend-Direktive zurück an HAProxy geleitet, dort TLS terminiert und entsprechend weitergeleitet.


