Firewall & Proxy 19. August 2026 • 15 Min. Lesezeit

OPNsense: HAProxy als Reverse Proxy mit Let's Encrypt SSL-Offloading & SNI / ACL-Routing

Anstatt Web-Ports (80/443) blind auf einzelne Webserver oder Docker-Container weiterzuleiten, bietet ein zentraler HAProxy auf der OPNsense entscheidende Vorteile: Automatisches SSL-Offloading via Let's Encrypt, DDoS-Schutz, zentrale Zugriffskontrollen sowie domainbasiertes Routing (Layer 7 HTTP oder Layer 4 TCP-Passthrough).

1. Benötigte OPNsense Plugins installieren

  1. Navigiere zu System > Firmware > Plugins.
  2. Suche nach os-haproxy und klicke auf das +-Symbol.
  3. Suche nach os-acme-client (für automatisierte Let's Encrypt Zertifikate) und installiere es ebenfalls.
  4. Lade die Weboberfläche neu, damit die neuen Menüpunkte unter Services erscheinen.

2. Let's Encrypt Zertifikat erstellen (ACME Client)

  1. Unter Services > ACME Client > Accounts deine E-Mail-Adresse für den Let's Encrypt Account hinterlegen und registrieren.
  2. Unter Challenge Types: Wähle HTTP-01 (nutzt den integrierten ACME-Server auf Port 43580) oder DNS-01 (über API für Wildcard-Zertifikate).
  3. Unter Certificates: Neues Zertifikat anlegen, Domainnamen eintragen (z. B. example.com, www.example.com) und den Challenge-Typ zuweisen.
  4. Klicke auf Issue, um das Zertifikat erstmalig abzurufen.

3. HAProxy: Real Server anlegen

Ein Real Server repräsentiert das Backend-Ziel (z. B. deinen Webserver-Cluster, Docker-Container oder einen sekundären Reverse Proxy wie NPM):

  • Gehe zu Services > HAProxy > Settings > Real Servers > Klicke auf +.
  • Beispiel 1 (Interner App-Server Node A):
    • Name: RS_Docker_Node01
    • FQDN or IP: 10.10.10.20
    • Port: 8080
  • Beispiel 2 (Sekundärer Proxy / Nginx Proxy Manager):
    • Name: RS_NPM_Passthrough
    • FQDN or IP: 10.10.10.30
    • Port: 443 (empfängt verschlüsselten TCP-Traffic)

4. Backend Pools konfigurieren

Backend Pools gruppieren Server und steuern das Load-Balancing sowie Health Checks:

  • Pool für Web-Cluster (Layer 7 HTTP):
    • Name: BE_Web_Cluster
    • Mode: HTTP (Layer 7)
    • Servers: RS_Docker_Node01 (und weitere Cluster-Nodes)
    • Balancing Algorithm: Round robin
    • Health Checking: HTTP (z. B. Methode OPTIONS oder GET auf /health.php).
  • Pool für NPM / TCP-Fallback (Layer 4 TCP):
    • Name: BE_NPM_Passthrough
    • Mode: TCP (Layer 4)
    • Servers: RS_NPM_Passthrough

5. Rules & Conditions (SNI- & Domain-Routing)

Um im TCP-Modus nach Domainnamen zu trennen, werten wir den SNI-Header (Server Name Indication) des TLS-Handshakes aus:

  1. Unter Rules > Conditions:
    • Name: c_sni_hauptdomain
    • Condition type: Custom condition (req_ssl_sni) oder SSL / TLS Server Name Indication matches
    • Value: example.com (sowie optional www.example.com)
  2. Unter Rules:
    • Name: r_route_hauptdomain
    • Select conditions: c_sni_hauptdomain
    • Execute function: Use specified Backend PoolBE_Local_SSL_Terminator (leitet an den internen SSL-Terminator weiter).

6. Port 80 HTTP-Redirect & ACME-Challenge Routing

Damit ACME HTTP-01 Challenges funktionieren und normaler Web-Traffic auf HTTPS gezwungen wird:

  • Frontend (Port 80):
    • Listen Addresses: 192.0.2.1:80, [2001:db8::1]:80
    • Mode: HTTP
    • Rules:
      1. redirect_acme_challenges (greift bei path_beg -i /.well-known/acme-challenge/ → leitet an acme_challenge_backend auf Port 43580).
      2. r_redirect_https (greift bei normalem HTTP-Traffic → http-request redirect scheme https).

7. Frontend HTTPS & der kritische TCP-Inspection-Delay Fallstrick

Wenn HAProxy im TCP-Modus (Layer 4) läuft, um z. B. bestimmte Domains lokal zu terminieren und alle anderen Subdomains verschlüsselt an NPM weiterzugeben, tritt häufig folgendes Problem auf: HAProxy entscheidet zu schnell, bevor der Browser den TLS-Handshake mit der SNI geschickt hat, und schickt allen Traffic fälschlicherweise ans Default-Backend.

Die Lösung via Optionsweiterleitung:

  1. Öffne dein öffentliches Frontend (Public Services > HTTPS_Frontend).
  2. Listen Addresses: 192.0.2.1:443, [2001:db8::1]:443.
  3. Mode: TCP.
  4. Default Backend: BE_NPM_Passthrough (Fallback für alle Subdomains).
  5. Rules: r_route_hauptdomain.
  6. Scrolle ganz nach unten zu Erweiterte Einstellungen > Optionsweiterleitung und trage ein:
    tcp-request inspect-delay 5s
    tcp-request content accept if { req_ssl_hello_type 1 }

Diese beiden Zeilen zwingen HAProxy dazu, bis zu 5 Sekunden auf das ClientHello-Paket zu warten. Sobald das Paket da ist, wird die SNI ausgelesen, die ACL matcht zuverlässig und das Routing greift pixelgenau.

8. Interner SSL-Terminator (Layer 7 Loopback)

Für Domains, die direkt von der OPNsense entschlüsselt und per Round-Robin auf Backend-Server verteilt werden sollen:

  • Public Service anlegen:
    • Name: FE_Internal_SSL_Terminator
    • Listen Addresses: 127.0.0.1:8443
    • Mode: HTTP / HTTPS (SSL Offloading)
    • Certificates: Das zuvor erstellte Let's Encrypt Zertifikat auswählen.
    • Default Backend: BE_Web_Cluster

Klicke abschließend auf Apply. Eingehende Anfragen auf der Hauptdomain werden nun sauber lokal entschlüsselt und gebalanced, während beliebige Subdomains transparent als TCP-Stream an den nachgelagerten Proxy durchgereicht werden.

💡 Support & Consulting: Du benötigst Unterstützung bei der Einrichtung deiner Infrastruktur? 👉 tessmann-digital.de