Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| 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, | ||
| + | =====Installation===== | ||
| + | |||
| + | * Service Ubuntu: / | ||
| + | * Service RHEL: / | ||
| + | |||
| + | <box red>In den meissten Distributionen installiert der Paketmanager eine veraltete Version (1.8)</ | ||
| + | |||
| + | <box red> | ||
| + | < | ||
| + | apt install haproxy | ||
| + | </ | ||
| + | |||
| + | Hauptconfig unter: | ||
| + | |||
| + | < | ||
| + | / | ||
| + | </ | ||
| + | |||
| + | Konfiguration prüfen (vor einem Restart/ | ||
| + | |||
| + | < | ||
| + | sudo haproxy -c -f / | ||
| + | </ | ||
| + | |||
| + | ====Kompilieren==== | ||
| + | |||
| + | Von der [[https:// | ||
| + | |||
| + | < | ||
| + | sudo dnf install gcc pcre-devel tar make wget openssl-devel systemd-devel -y | ||
| + | |||
| + | wget http:// | ||
| + | |||
| + | 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 / | ||
| + | sudo mkdir -p / | ||
| + | |||
| + | # Wahrscheinlich nicht funktional, besser from scratch erstellen | ||
| + | # cp examples/ | ||
| + | </ | ||
| + | |||
| + | Create a service file / | ||
| + | |||
| + | < | ||
| + | [Unit] | ||
| + | Description=HAProxy Load Balancer | ||
| + | After=network.target | ||
| + | |||
| + | [Service] | ||
| + | ExecStart=/ | ||
| + | ExecReload=/ | ||
| + | ExecReload=/ | ||
| + | Restart=always | ||
| + | User=root | ||
| + | Group=root | ||
| + | |||
| + | [Install] | ||
| + | WantedBy=multi-user.target | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | sudo systemctl daemon-reexec | ||
| + | sudo systemctl daemon-reload | ||
| + | sudo systemctl enable haproxy | ||
| + | sudo systemctl start haproxy | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | # Fix not needed | ||
| + | setcap ' | ||
| + | </ | ||
| + | |||
| + | ===HALog=== | ||
| + | |||
| + | < | ||
| + | make admin/ | ||
| + | </ | ||
| + | ====Manueller Start==== | ||
| + | |||
| + | < | ||
| + | haproxy -f / | ||
| + | haproxy -db -f / | ||
| + | </ | ||
| + | =====Konfiguration===== | ||
| + | |||
| + | See also [[https:// | ||
| + | ====Global==== | ||
| + | |||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | |||
| + | Der globale Abschnitt befindet sich oben in Ihrer Konfigurationsdatei. Er definiert Anweisungen auf Prozessebene, | ||
| + | |||
| + | < | ||
| + | global | ||
| + | maxconn 60000 | ||
| + | log 127.0.0.1 local0 | ||
| + | log 127.0.0.1 local1 notice | ||
| + | user haproxy | ||
| + | group haproxy | ||
| + | chroot /var/empty | ||
| + | </ | ||
| + | |||
| + | <box green> | ||
| + | |||
| + | |||
| + | ====Defaults==== | ||
| + | |||
| + | * [[https:// | ||
| + | |||
| + | In einem Abschnitt " | ||
| + | |||
| + | < | ||
| + | defaults | ||
| + | mode http | ||
| + | balance roundrobin | ||
| + | timeout connect 5s | ||
| + | timeout client | ||
| + | timeout server | ||
| + | |||
| + | # Inherits mode | ||
| + | frontend website | ||
| + | bind *:80 | ||
| + | default_backend web_servers | ||
| + | |||
| + | # Inherits mode and balance | ||
| + | backend web_servers | ||
| + | server s1 192.168.1.25: | ||
| + | server s2 192.168.1.26: | ||
| + | </ | ||
| + | |||
| + | ^Timeout^Beschreibung^ | ||
| + | |timeout connect|Wie lange HAProxy maximal auf den TCP-Verbindungsaufbau zum Backend wartet. Wenn der Server/ | ||
| + | |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), | ||
| + | ====Frontend==== | ||
| + | |||
| + | Ein " | ||
| + | |||
| + | < | ||
| + | frontend foo.com | ||
| + | mode http | ||
| + | bind 192.168.1.5: | ||
| + | default_backend foo_servers | ||
| + | |||
| + | frontend db.foo.com | ||
| + | mode tcp | ||
| + | bind 192.168.1.15: | ||
| + | default_backend db_servers | ||
| + | </ | ||
| + | |||
| + | ===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 / | ||
| + | bash -c 'cat / | ||
| + | </ | ||
| + | |||
| + | <code bash> | ||
| + | frontend https_termination | ||
| + | mode tcp | ||
| + | bind *:443 ssl crt / | ||
| + | use_backend vpn if { req.hdr(host) -i vpn.zarat.at } | ||
| + | use_backend sip if { req.ssl_sni -i sip.zarat.at } | ||
| + | </ | ||
| + | |||
| + | ===Redirect HTTP to HTTPS=== | ||
| + | |||
| + | < | ||
| + | frontend mywebsite | ||
| + | mode http | ||
| + | bind :80 | ||
| + | bind :443 ssl crt / | ||
| + | http-request redirect scheme https if !{ ssl_fc } | ||
| + | default_backend servers | ||
| + | </ | ||
| + | ====Backend==== | ||
| + | |||
| + | Ein " | ||
| + | |||
| + | < | ||
| + | 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: | ||
| + | server foo2 192.168.1.26: | ||
| + | server foo3 192.168.1.27: | ||
| + | |||
| + | backend bar_servers | ||
| + | mode http | ||
| + | balance roundrobin | ||
| + | server bar1 192.168.1.35: | ||
| + | server bar2 192.168.1.36: | ||
| + | server bar3 192.168.1.37: | ||
| + | </ | ||
| + | |||
| + | =====Stats===== | ||
| + | HAProxy hat ein Web Frontend zum Überwachen der Statistiken. | ||
| + | |||
| + | < | ||
| + | frontend stats | ||
| + | mode http | ||
| + | bind *:8404 | ||
| + | stats enable | ||
| + | stats refresh 10s | ||
| + | stats uri /stats | ||
| + | stats show-modules | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | http://< | ||
| + | </ | ||
| + | |||
| + | =====Logging===== | ||
| + | |||
| + | * [[https:// | ||
| + | |||
| + | Im Glogals Bereich kann man das HAProxy Logging konfigurieren. Standard nutzt HAProxy syslog nach /dev/log. journalctl -u haproxy -f | ||
| + | < | ||
| + | global | ||
| + | log /dev/log local0 | ||
| + | log /dev/log local1 notice | ||
| + | </ | ||
| + | |||
| + | ^Zeile^Bedeutung^ | ||
| + | |log /dev/log local0 info|sendet an lokalen Syslog-Socket| | ||
| + | |log 127.0.0.1: | ||
| + | |log stdout format raw|schreibt auf STDOUT| | ||
| + | |||
| + | Wenn man direkt in eine Datei loggen will muss man das über einen [[Syslog]] Daemon konfigurieren. [[https:// | ||
| + | |||
| + | ====via Syslog==== | ||
| + | |||
| + | In / | ||
| + | |||
| + | < | ||
| + | # HAProxy Logs (So landen die Logs in / | ||
| + | # local0.* | ||
| + | # local1.* | ||
| + | |||
| + | # besser so landen sie nur in der Custom Logdatei | ||
| + | # Nur HAProxy via local0 in eigene Datei | ||
| + | if ($syslogfacility-text == " | ||
| + | action(type=" | ||
| + | stop | ||
| + | } | ||
| + | # optional: local1.notice für haproxy | ||
| + | if ($syslogfacility-text == " | ||
| + | action(type=" | ||
| + | stop | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | # neu starten | ||
| + | sudo systemctl restart rsyslog | ||
| + | sudo systemctl restart haproxy | ||
| + | </ | ||
| + | |||
| + | Jetzt findest man Logs in: | ||
| + | |||
| + | * / | ||
| + | * / | ||
| + | |||
| + | ====via StdOut==== | ||
| + | |||
| + | < | ||
| + | global | ||
| + | log stdout format raw local0 | ||
| + | </ | ||
| + | |||
| + | Theoretisch kann man den Prozess dann so starten das er Stdout in eine Datei umleitet. (sketchy) | ||
| + | |||
| + | < | ||
| + | haproxy -f / | ||
| + | </ | ||
| + | ====Application Logging==== | ||
| + | |||
| + | Im Frontend | ||
| + | < | ||
| + | frontend test-frontend | ||
| + | log-format " | ||
| + | </ | ||
| + | |||
| + | Legende (siehe auch [[https:// | ||
| + | |||
| + | 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 < | ||
| + | |||
| + | 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, | ||
| + | | %B | Anzahl Bytes, die an den Client gesendet wurden | 276 | | ||
| + | | %r | HTTP-Request-Zeile | POST / | ||
| + | |||
| + | Erweiterte/ | ||
| + | ^ 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: | ||
| + | |||
| + | Erläuterung zu %tsc | ||
| + | ^ Beispiel ^ Bedeutung ^ | ||
| + | | SD | Server hat die Verbindung sauber beendet (Server Done). Normalfall nach erfolgreicher Antwort. | | ||
| + | | sD | Server hat geschlossen, | ||
| + | | cD | Client hat die Verbindung sauber beendet (Client Done). Normal, wenn der Client z. B. Keep-Alive beendet. | | ||
| + | | cT | Client-Timeout: | ||
| + | | sT | Server-Timeout: | ||
| + | |||
| + | |||
| + | =====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===== | ||
| + | |||
| + | < | ||
| + | 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: | ||
| + | </ | ||
| + | =====Agent Check===== | ||
| + | |||
| + | <box red> | ||
| + | |||
| + | < | ||
| + | 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: | ||
| + | </ | ||
| + | |||
| + | Auf dem Backend ein kleines Bash Script. | ||
| + | |||
| + | <code bash> | ||
| + | #!/bin/bash | ||
| + | if ss -tulpn | grep -q " | ||
| + | echo " | ||
| + | else | ||
| + | echo " | ||
| + | fi | ||
| + | </ | ||
| + | |||
| + | As a Service | ||
| + | |||
| + | < | ||
| + | sudo nano / | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | [Unit] | ||
| + | Description=HAProxy Agent Check Listener | ||
| + | After=network.target | ||
| + | |||
| + | [Service] | ||
| + | ExecStart=/ | ||
| + | Restart=always | ||
| + | User=manuel | ||
| + | WorkingDirectory=/ | ||
| + | |||
| + | [Install] | ||
| + | WantedBy=multi-user.target | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | sudo systemctl daemon-reexec | ||
| + | sudo systemctl daemon-reload | ||
| + | sudo systemctl enable agent-check.service | ||
| + | sudo systemctl start agent-check.service | ||
| + | </ | ||
| + | |||
| + | =====Proxy Protocol===== | ||
| + | |||
| + | HAProxy implementiert das [[https:// | ||
| + | |||
| + | Möchte man das proxy-protocol im Frontend empfangen verwendet man die Option accept-proxy, | ||
| + | |||
| + | Siehe [[https:// | ||
| + | =====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:// | ||
| + | |||
| + | < | ||
| + | frontend www | ||
| + | bind :80 | ||
| + | acl images_url path_beg -i /images/ | ||
| + | | ||
| + | </ | ||
| + | |||
| + | =====Fetches===== | ||
| + | |||
| + | [[https:// | ||
| + | |||
| + | Eine Funktion, die Informationen über die aktuelle Anfrage, die aktuelle Antwort, die Verbindung oder den internen Zustand des Load Balancers zurückgibt. | ||
| + | |||
| + | < | ||
| + | frontend www | ||
| + | bind :80 | ||
| + | http-request deny if { path /api/bad/ } | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | frontend www | ||
| + | bind :80 | ||
| + | http-request set-var(txn.http_version) req.ver | ||
| + | http-response add-header Via " | ||
| + | </ | ||
| + | =====Persistence===== | ||
| + | |||
| + | ====Stick Table==== | ||
| + | |||
| + | Siehe [[https:// | ||
| + | |||
| + | < | ||
| + | # 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: | ||
| + | server app2 192.168.1.11: | ||
| + | </ | ||
| + | |||
| + | =====Links===== | ||
| + | |||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||