Benutzer-Werkzeuge

Webseiten-Werkzeuge


haproxy

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Vorhergehende Überarbeitung
haproxy [2025/04/21 10:59]
haproxy [2025/11/19 10:14] (aktuell)
jango [Kompilieren]
Zeile 1: Zeile 1:
 +HAProxy ist eine kostenlose Open-Source-Software, die einen Hochverfügbarkeits-Load-Balancer (Layer 4 im [[osi|OSI]] Modell) und Reverse-[[proxy|Proxy]] für TCP- und HTTP-basierte Anwendungen bereitstellt, die Anforderungen auf mehrere Server verteilen. 
  
 +=====Installation=====
 +
 +  * Service Ubuntu: /lib/systemd/system/haproxy.service
 +  * Service RHEL: /etc/systemd/system/haproxy.service
 +
 +<box red>In den meissten Distributionen installiert der Paketmanager eine veraltete Version (1.8)</box>
 +
 +<box red>[[SELinux]] deaktivieren oder den Dienst freigeben</box>
 +<code>
 +apt install haproxy
 +</code>
 +
 +Hauptconfig unter: 
 +
 +<code>
 +/etc/haproxy/haproxy.cfg
 +</code>
 +
 +Konfiguration prüfen (vor einem Restart/Reload)
 +
 +<code>
 +sudo haproxy -c -f /etc/haproxy/haproxy.cfg
 +</code>
 +
 +====Kompilieren====
 +
 +Von der [[https://www.haproxy.org/download/|offiziellen Homepage]] kann man aktuellere Pakete herunterladen.
 +
 +<code>
 +sudo dnf install gcc pcre-devel tar make wget openssl-devel systemd-devel -y
 +
 +wget http://www.haproxy.org/download/2.8/src/haproxy-2.8.3.tar.gz
 +
 +tar -xvzf haproxy-2.8.3.tar.gz
 +cd haproxy-2.8.3
 +make TARGET=linux-glibc USE_OPENSSL=1 USE_PCRE=1 USE_ZLIB=1 USE_SYSTEMD=1
 +sudo make install
 +
 +sudo cp haproxy /usr/sbin/haproxy
 +sudo mkdir -p /etc/haproxy
 +
 +# Wahrscheinlich nicht funktional, besser from scratch erstellen
 +# cp examples/basic-config-edge.cfg /etc/haproxy/haproxy.cfg
 +</code>
 +
 +Create a service file /etc/systemd/system/haproxy.service
 +
 +<code>
 +[Unit]
 +Description=HAProxy Load Balancer
 +After=network.target
 +
 +[Service]
 +ExecStart=/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -Ws
 +ExecReload=/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c -q
 +ExecReload=/bin/kill -USR2 $MAINPID
 +Restart=always
 +User=root
 +Group=root
 +
 +[Install]
 +WantedBy=multi-user.target
 +</code>
 +
 +<code>
 +sudo systemctl daemon-reexec
 +sudo systemctl daemon-reload
 +sudo systemctl enable haproxy
 +sudo systemctl start haproxy
 +</code>
 +
 +<code>
 +# Fix not needed
 +setcap 'cap_net_bind_service=+ep' /usr/sbin/haproxy
 +</code>
 +
 +===HALog===
 +
 +<code>
 +make admin/halog/halog
 +</code>
 +====Manueller Start====
 +
 +<code>
 +haproxy -f /etc/haproxy/haproxy.cfg [-Ws]
 +haproxy -db -f /etc/haproxy/haproxy.cfg
 +</code>
 +=====Konfiguration=====
 +
 +See also [[https://www.haproxy.com/documentation/haproxy-configuration-tutorials/|HAProxy configuration tutorials]]
 +====Global====
 +
 +  * [[https://www.haproxy.com/documentation/haproxy-configuration-tutorials/proxying-essentials/configuration-basics/global/|HAProxy Globals]]
 +  * [[https://www.haproxy.com/documentation/haproxy-configuration-manual/latest/#3|Keywords in global section]]
 +
 +Der globale Abschnitt befindet sich oben in Ihrer Konfigurationsdatei. Er definiert Anweisungen auf Prozessebene, beispielsweise die maximale Anzahl zulässiger Verbindungen, den Speicherort der Protokolle und den Benutzer und die Gruppe, unter der der Prozess ausgeführt werden soll. Das folgende Beispiel zeigt nur einige der verfügbaren Optionen:
 +
 +<code>
 +global
 +  maxconn 60000
 +  log 127.0.0.1 local0
 +  log 127.0.0.1 local1 notice
 +  user  haproxy
 +  group haproxy
 +  chroot /var/empty
 +</code>
 +
 +<box green>local0 und local1 loggen in /dev/log. journalctl -u haproxy -f</box>
 +
 +
 +====Defaults====
 +
 +  * [[https://www.haproxy.com/documentation/haproxy-configuration-tutorials/proxying-essentials/configuration-basics/defaults/|HAProxy Defaults]]
 +
 +In einem Abschnitt "defaults" werden allgemeine Einstellungen gespeichert, die von den nachfolgenden Frontend- und Backend-Abschnitten übernommen werden. Er kann auch lange Konfigurationen durch Reduzierung doppelter Zeilen verkürzen. Beispiel für eine Standardkonfiguration: Durch Hinzufügen von Standardeinstellungen zur Konfiguration können Sie Einstellungen definieren, die gegebenenfalls von allen darunter liegenden Abschnitten übernommen werden. Beispielsweise ist "mode" sowohl auf ein Frontend als auch auf ein Backend anwendbar, "balance" hingegen nur auf Backends. Nicht alle Anweisungen können in "defaults" aufgenommen werden, z.B. die Zeilen "bind" und "server".
 +
 +<code>
 +defaults
 +  mode http
 +  balance roundrobin
 +  timeout connect 5s 
 +  timeout client  30s 
 +  timeout server  30s 
 +
 +# Inherits mode
 +frontend website
 +  bind *:80
 +  default_backend web_servers
 +
 +# Inherits mode and balance
 +backend web_servers
 +  server s1 192.168.1.25:80
 +  server s2 192.168.1.26:80
 +</code>
 +
 +^Timeout^Beschreibung^
 +|timeout connect|Wie lange HAProxy maximal auf den TCP-Verbindungsaufbau zum Backend wartet. Wenn der Server/SYN-ACK langsam ist, fliegt der Connect nach 5s raus.|
 +|timeout client|Inaktivitäts-Timeout zwischen Client <-> HAProxy (während Request und Response). D. h. wenn vom Client 30 s lang kein Byte kommt/geht, wird abgebrochen (-> oft 408).|
 +|timeout server|Inaktivitäts-Timeout zwischen HAProxy <-> Backend. Wenn der Server nach 30 s keine Daten schickt (z. B. bis zum ersten Byte der Antwort oder zwischen Response-Chunks), bricht HAProxy ab.|
 +====Frontend====
 +
 +Ein "frontend" Abschnitt ([[https://www.haproxy.com/documentation/haproxy-configuration-tutorials/proxying-essentials/configuration-basics/frontends/|HAProxy Frontend]]) definiert die IP-Adressen und Ports, mit denen Clients eine Verbindung herstellen können. Sie können beliebig viele Frontend-Abschnitte hinzufügen, um verschiedene Websites oder Anwendungen im Internet verfügbar zu machen.
 +
 +<code>
 +frontend foo.com
 +  mode http
 +  bind 192.168.1.5:80
 +  default_backend foo_servers
 +
 +frontend db.foo.com
 +  mode tcp
 +  bind 192.168.1.15:3306
 +  default_backend db_servers
 +</code>
 +
 +===HTTPS Termination===
 +
 +Das Pem Zertifikat muss Cert und Privkey beinhalten!
 +
 +<code bash>
 +certbot certonly --standalone -d vpn.zarat.at
 +certbot certonly --standalone -d sip.zarat.at
 +
 +bash -c 'cat /etc/letsencrypt/live/vpn.zarat.at/fullchain.pem /etc/letsencrypt/live/vpn.zarat.at/privkey.pem > /etc/ssl/private/vpn.zarat.at.pem'
 +bash -c 'cat /etc/letsencrypt/live/sip.zarat.at/fullchain.pem /etc/letsencrypt/live/sip.zarat.at/privkey.pem > /etc/ssl/private/sip.zarat.at.pem'
 +</code>
 +
 +<code bash>
 +frontend https_termination
 +  mode tcp
 +  bind *:443 ssl crt /etc/ssl/private/
 +  use_backend vpn if { req.hdr(host) -i vpn.zarat.at }
 +  use_backend sip if { req.ssl_sni -i sip.zarat.at }
 +</code>
 +
 +===Redirect HTTP to HTTPS===
 +
 +<code>
 +frontend mywebsite
 +    mode http
 +    bind :80
 +    bind :443 ssl crt /etc/ssl/certs/ssl.pem
 +    http-request redirect scheme https if !{ ssl_fc }
 +    default_backend servers
 +</code>
 +====Backend====
 +
 +Ein "backend" Abschnitt ([[https://www.haproxy.com/documentation/haproxy-configuration-tutorials/proxying-essentials/configuration-basics/backends/|HAProxy Backend]]) definiert einen Serverpool, an den der Load Balancer Anfragen weiterleitet. Sie können beliebig viele Backend-Abschnitte hinzufügen. Jedes Backend-Schlüsselwort wird durch eine Bezeichnung, z. B. "web_servers", von anderen unterschieden.
 +
 +<code>
 +frontend foo_and_bar
 +  mode http
 +  bind *:80
 +  use_backend foo_servers if { req.hdr(host) -i foo.com }
 +  use_backend bar_servers if { req.hdr(host) -i bar.com  }
 +
 +backend foo_servers
 +  mode http
 +  balance roundrobin
 +  server foo1 192.168.1.25:80 check
 +  server foo2 192.168.1.26:80 check
 +  server foo3 192.168.1.27:80 check
 +
 +backend bar_servers
 +  mode http
 +  balance roundrobin
 +  server bar1 192.168.1.35:80 check
 +  server bar2 192.168.1.36:80 check
 +  server bar3 192.168.1.37:80 check
 +</code>
 +
 +=====Stats=====
 +HAProxy hat ein Web Frontend zum Überwachen der Statistiken.
 +
 +<code>
 +frontend stats
 +  mode http
 +  bind *:8404
 +  stats enable
 +  stats refresh 10s
 +  stats uri /stats
 +  stats show-modules
 +</code>
 +
 +<code>
 +http://<server>:8404/stats
 +</code>
 +
 +=====Logging=====
 +
 +  * [[https://www.haproxy.com/blog/introduction-to-haproxy-logging|Introduction to HAProxy Logging: A Practical Guide]]
 +
 +Im Glogals Bereich kann man das HAProxy Logging konfigurieren. Standard nutzt HAProxy syslog nach /dev/log. journalctl -u haproxy -f
 +<code>
 +global
 +        log /dev/log local0
 +        log /dev/log local1 notice
 +</code>
 +
 +^Zeile^Bedeutung^
 +|log /dev/log local0 info|sendet an lokalen Syslog-Socket|
 +|log 127.0.0.1:514 local0 info|sendet per UDP|
 +|log stdout format raw|schreibt auf STDOUT|
 +
 +Wenn man direkt in eine Datei loggen will muss man das über einen [[Syslog]] Daemon konfigurieren. [[https://unix.stackexchange.com/questions/260940/does-haproxy-support-logging-to-a-file|Unix StackExchange]]
 +
 +====via Syslog====
 +
 +In /etc/rsyslog.d/haproxy.conf (neu anlegen):
 +
 +<code>
 +# HAProxy Logs (So landen die Logs in /var/log/syslog und der Custom Datei!!)
 +# local0.*    /var/log/haproxy.log
 +# local1.*    /var/log/haproxy-admin.log
 +
 +# besser so landen sie nur in der Custom Logdatei
 +# Nur HAProxy via local0 in eigene Datei
 +if ($syslogfacility-text == "local0" and ($programname == "haproxy" or $app-name == "haproxy")) then {
 +  action(type="omfile" file="/var/log/haproxy/haproxy.log")
 +  stop
 +}
 +# optional: local1.notice für haproxy
 +if ($syslogfacility-text == "local1" and ($programname == "haproxy" or $app-name == "haproxy") and prifilt("*.notice")) then {
 +  action(type="omfile" file="/var/log/haproxy/haproxy.log")
 +  stop
 +}
 +</code>
 +
 +<code>
 +# neu starten
 +sudo systemctl restart rsyslog
 +sudo systemctl restart haproxy
 +</code>
 +
 +Jetzt findest man Logs in:
 +
 +  * /var/log/haproxy.log
 +  * /var/log/haproxy-admin.log
 +
 +====via StdOut====
 +
 +<code>
 +global
 +    log stdout format raw local0
 +</code>
 +
 +Theoretisch kann man den Prozess dann so starten das er Stdout in eine Datei umleitet. (sketchy)
 +
 +<code>
 +haproxy -f /etc/haproxy/haproxy.cfg >> /var/log/haproxy.log 2>&1
 +</code>
 +====Application Logging====
 +
 +Im Frontend
 +<code>
 +frontend test-frontend
 +        log-format "Client: %ci:%cp -> %f (%fi:%fp) => %b/%s %TR/%Tw/%Tc/%Tr/%Tt %ST %B \"%r\""
 +</code>
 +
 +Legende (siehe auch [[https://www.haproxy.com/blog/haproxy-log-customization|hier]])
 +
 +Addressen und Verbindungsinfo
 +^ Variable ^ Bedeutung ^ Beispiel ^
 +| %ci | Client IP (die IP des Benutzers, der sich verbindet) | 10.2.1.8 |
 +| %cp | Client Port | 54321 |
 +| %fi | Local IP (Interface am HAProxy) | 172.21.1.166 |
 +| %fp | Local Port (Port am HAProxy) | 443 |
 +| %f  | Name des Frontends (aus deiner Config) | https-frontend-wildcard |
 +| %b  | Name des Backends, an das weitergeleitet wurde | http-backend-ton |
 +| %s  | Server innerhalb des Backends (oder <NOSRV> wenn keins gewählt wurde) | 172.22.0.42 |
 +
 +Zeitmessungen
 +^ Variable ^ Bedeutung ^ Typischer Wert ^
 +| %TR | Zeit bis Request vollständig empfangen ist (vom Client zu HAProxy) | 0 ms |
 +| %Tw | Zeit, die HAProxy auf einen freien Server-Slot wartet (Queue-Wartezeit) | 0 ms |
 +| %Tc | Zeit für TCP-Connect zum Backend | 1–10 ms |
 +| %Tr | Zeit vom Connect bis zum ersten Byte der Antwort (Time to First Byte) | 20 ms – 2000 ms |
 +| %Tt | Gesamtzeit der Transaktion (vom Connect bis letztes Byte) | 600 ms – 26000 ms |
 +
 +HTTP Infos
 +^ Variable ^ Bedeutung ^ Beispiel ^
 +| %ST | HTTP-Statuscode, den HAProxy dem Client geschickt hat | 200, 408, 504 |
 +| %B  | Anzahl Bytes, die an den Client gesendet wurden | 276 |
 +| %r  | HTTP-Request-Zeile | POST /fsc/fscasp/content/tmp/web.telemetry HTTP/2.0 |
 +
 +Erweiterte/optionale Felder
 +^ Variable ^ Bedeutung ^ Beispiel ^
 +| %tsc | Termination-State-Code – zeigt, wer die Verbindung beendet hat und warum | SD, sD, cD, cT, sT |
 +| %HR / %HS | Header-Zähler (empfangene / gesendete Header) | – |
 +| %ac / %fc / %bc | Aktive Verbindungen (Frontend, Backend, Total) | Diese Variablen zeigen die Zahl der aktuell aktiven Verbindungen: %ac = Frontend Connections, %fc = Backend Connections, %bc = Gesamt. |
 +
 +Erläuterung zu %tsc
 +^ Beispiel ^ Bedeutung ^
 +| SD | Server hat die Verbindung sauber beendet (Server Done). Normalfall nach erfolgreicher Antwort. |
 +| sD | Server hat geschlossen, bevor die vollständige Antwort gesendet war. |
 +| cD | Client hat die Verbindung sauber beendet (Client Done). Normal, wenn der Client z. B. Keep-Alive beendet. |
 +| cT | Client-Timeout: Client hat zu lange nichts mehr gesendet -> HAProxy hat abgebrochen. |
 +| sT | Server-Timeout: Server hat zu lange nichts mehr geliefert -> HAProxy hat abgebrochen. |
 +
 +
 +=====High Availability=====
 +
 +HAProxy bietet das High Availability Modul nur in der kostenpflichtigen Enterprise Version. Alternativ kann man [[keepalived]] verwenden. Keepalived implementiert [[VRRP]], das selbe Protokoll das vom HA Modul verwendet wird.
 +
 +
 +=====Health Check=====
 +
 +<code>
 +frontend smtp-frontend
 +        bind *:25
 +        mode tcp
 +        default_backend smtp-backend
 +
 +backend smtp-backend
 +        mode tcp
 +        description Das Mailrelay Backend
 +        option tcp-check
 +        tcp-check connect port 25
 +        tcp-check send string "helo test.domain"
 +        tcp-check expect rstring ^220
 +        balance roundrobin
 +        server vtsv-postfix4 172.21.0.187:25 check 
 +</code>
 +=====Agent Check=====
 +
 +<box red>Untested</box>
 +
 +<code>
 +frontend smtp-frontend
 +        bind *:25
 +        mode tcp
 +        default_backend smtp-backend
 +
 +backend smtp-backend
 +        mode tcp
 +        description Das Mailrelay Backend
 +        balance roundrobin
 +        server vtsv-postfix4 172.21.0.187:25 check agent-check agent-port 12345 inter 1000
 +</code>
 +
 +Auf dem Backend ein kleines Bash Script.
 +
 +<code bash>
 +#!/bin/bash
 +if ss -tulpn | grep -q "0.0.0.0:25"; then
 +  echo "200"
 +else
 +  echo "500"
 +fi
 +</code>
 +
 +As a Service
 +
 +<code>
 +sudo nano /etc/systemd/system/agent-check.service
 +</code>
 +
 +<code>
 +[Unit]
 +Description=HAProxy Agent Check Listener
 +After=network.target
 +
 +[Service]
 +ExecStart=/usr/bin/socat TCP-LISTEN:12345,reuseaddr,fork EXEC:/home/manuel/agent.sh
 +Restart=always
 +User=manuel
 +WorkingDirectory=/home/manuel
 +
 +[Install]
 +WantedBy=multi-user.target
 +</code>
 +
 +<code>
 +sudo systemctl daemon-reexec
 +sudo systemctl daemon-reload
 +sudo systemctl enable agent-check.service
 +sudo systemctl start agent-check.service
 +</code>
 +
 +=====Proxy Protocol=====
 +
 +HAProxy implementiert das [[https://www.haproxy.com/blog/use-the-proxy-protocol-to-preserve-a-clients-ip-address|Proxy-Protocol]] womit die originale Client-IP an das Backend weitergereicht werden kann. [[https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt|Spezifikation]]. 
 +
 +Möchte man das proxy-protocol im Frontend empfangen verwendet man die Option accept-proxy, möchte man es an das Backend sendet verwendet man send-proxy.
 +
 +Siehe [[https://serverfault.com/questions/1193486/how-to-configure-health-check-for-postfix-behind-haproxy-when-using-the-proxy-pr]]
 +=====ACL=====
 +
 +ACL geben true oder false zurück. Die ACL kann dann in jeder Zeile angewendet werden die ein conditional if or unless statement abfragt. Siehe [[https://www.haproxy.com/documentation/haproxy-configuration-tutorials/proxying-essentials/custom-rules/acls/|ACL Dokumentation]]
 +
 +<code>
 +frontend www
 +   bind :80
 +   acl images_url path_beg -i /images/
 +   use_backend static_assets if images_url
 +</code>
 +
 +=====Fetches=====
 +
 +[[https://www.haproxy.com/documentation/haproxy-configuration-tutorials/proxying-essentials/custom-rules/fetches/|Fetch Dokumentation]]
 +
 +Eine Funktion, die Informationen über die aktuelle Anfrage, die aktuelle Antwort, die Verbindung oder den internen Zustand des Load Balancers zurückgibt. 
 +
 +<code>
 +frontend www
 +  bind :80
 +  http-request deny if { path /api/bad/ }
 +</code>
 +
 +<code>
 +frontend www
 +  bind :80
 +  http-request set-var(txn.http_version) req.ver
 +  http-response add-header Via "%[var(txn.http_version)] %[hostname]"
 +</code>
 +=====Persistence=====
 +
 +====Stick Table====
 +
 +Siehe [[https://www.haproxy.com/documentation/haproxy-configuration-tutorials/proxying-essentials/custom-rules/stick-tables/|Stick Table Dokumentation]]
 +
 +<code>
 +# Track src IP, max 1Mill entries expire after 30m
 +backend app_servers
 +    stick-table type ip size 1m expire 30m
 +    stick on src
 +    server app1 192.168.1.10:80 check
 +    server app2 192.168.1.11:80 check
 +</code>
 +
 +=====Links=====
 +
 +  * [[https://docs.haproxy.org/|Offizielle Dokumentation]]
 +  * [[https://discourse.haproxy.org/t/haproxy-email-preserve-client-ip/5699/4]]
 +  * [[https://www.haproxy.com/documentation/haproxy-configuration-tutorials/proxying-essentials/client-ip-preservation/transparent-proxying/]]
 +  * [[https://www.linuxbabe.com/mail-server/smtp-imap-proxy-with-haproxy-debian-ubuntu-centos]]
 +  * [[https://www.haproxy.com/blog/efficient-smtp-relay-infrastructure-with-postfix-and-load-balancers|Untested]]