Reverse Proxy in OPNsense einrichten

Kategorien: tutorial

Ein Reverse-Proxy kann verschiedene Aufgaben übernehmen. In diesem Fall soll er nur verschiedene Server in der DMZ unter einer IP-Adresse mit verschiedenen Domainnamen im Internet sichtbar machen.

Ausgangssituation

In meiner DMZ stehen ein paar Server, auf die ich aus dem Internet zugreifen möchte. Da ich nur eine externe IP-Adresse habe, unterscheiden sich die Server in ihrem Domainnamen. Mit nginx kann meinen Reverse Proxy einrichten, der genau das kann. Unter meiner OpenBSD-Firewall war das eine rechte simple Konfiguration.

In OPNsense ist das leider nicht so. Die Konfiguration verteilt sich über mehrere Karteireiter, die noch dazu Untermenus (ich habe keine Ahnung, wie ich diese dämlichen Dreiecke, die den Reiternamen ändern sonst nennen sollte) verteilen.

Karteireiter-Untermenus

Einrichtung

Zuerst muss man das Plugin hinzufügen.

nginx-Plugin installieren

Jetzt gibt es unter “Services” einen neuen Eintrag “Nginx” mit Untermenus. (Eventuell muss man die Seite neu laden, damit die Einträge aktualisiert werden.)

Services-Menu “nginx”

Das Plugin muss man mit dem Auswahlkopf aktivieren. Danach das Speichern nicht vergessen.

Upstream-Server

Die Basis sind die Server in der DMZ, an die der HTTP-Verkehr weitergeleitet werden soll. Den Server fügt man, zumindest in der aktuellen Version des Plugins, über den vierten Reiter mit einem Klick auf den ‘+’-Knopf hinzu. Die Werte sind relativ klar verständlich, auch wenn die Dokumentation fehlt.

Upstream Server anlegen

“Description” ist ein Name, mit dem der Name bei der weiteren Konfiguration angesprochen. Sinnvoll ist ein Name, bei dem man später automatisch weiß, was gemeint ist. “Server” ist die Adresse, unter der der Server von der Firewall aus erreichbar ist. Ich habe hier die IP-Adresse verwendet. Ob ein per DNS auflösbarer Name funktioniert habe ich nicht ausprobiert. “Port” ist der Port unter dem der Server in der DMZ, die HTTP-Anfragen erwartet. Der letzte Parameter, den man setzen muss, ist die “Server Priority”. Hier kann man in unserem Fall einfach 1 eintragen. Die Priorität benötigt man für eine Lastverteilung auf mehrere Upstream-Server

Spoiler-Alert! Obwohl ich alles richtig konfiguriert hatte, wie ich inzwischen weiß, hat meine Firewall keine nginx-Konfiguration für meine Upstream-Server angelegt. Ich konnte aus dem Browser keine Verbindung zu meinem Upstream-Server aufbauen. Funktionieren die Regeln nicht? Reagiert der Server in der DMZ nicht? Ich habe einen Tag gesucht. Einloggen per SSH brachte dann die Lösung. Ein sudo nginx -T zeigte meinen konfigurierten Upstream-Server nicht an. Die Konfiguration aus dem GUI landete nicht in der Konfiguration des nginx. Ein Klick auf den Aktualisieren-Knopf im Karteireiter schrieb die Konfiguration.

Aktualisieren-Knopf im Karteireiter

Seitdem drücke ich immer nach Änderungen auf den Aktualisieren-Knopf in den Karteireitern.

Der Aktualisieren-Knopf in der Titel-Zeile scheint die Konfiguration nicht zu schreiben. Er löst wohl nur das erneute Laden der Konfiguration des nginx-Servers aus.

Server-Gruppe anlegen

Auch wenn wir keine Lastverteilung einrichten wollen, benötigen wir eine Server-Gruppe. Die Server-Gruppe heißt “Upstream” im GUI. Da ich mehrere Stunden danach gesucht habe, folgt hier (Spoiler-Alert! Wer selber suchen will, bitte nicht weiter lesen!) die Lösung: Man muss auf das kleine Dreieck neben “Upstream” klicken.

Karteireiter “Upstream” auswählen

Jetzt kann man die Server-Gruppe mit einem Klick auf den ‘+’-Knopf hinzugefügt werden. Die Auswahl der Konfigurationswerte ist diesmal einfach. Man muss nur einen aussagekräftigen Namen für die “Description” eintragen und den Upstream-Server in “Server Entries” auswählen. Da wir keine Lastverteilung verwenden, ist der Algorithmus wurst. Ich habe mich entschieden, vorerst einmal die Verbindungen zum Upstream-Server unverschlüsselt durchzuführen. Im Produktivbetrieb werde ich eine Ende-zu-Ende-Verschlüsselung umsetzen, das ist sicherer und belastet die Firewall-Hardware weniger. Es erschwert aber den Test und die Zertifikate müssen auf den Upstream-Server übertragen werden.

Server-Gruppe anlegen

Nach dem Speichern aktualisieren der Konfiguration nicht vergessen (siehe oben).

Pfad anlegen

Jetzt möchte man den extern sichtbaren Server anlegen. Vielleicht ist es deshalb ganz gut, dass das GUI den Karteireiter “HTTP(S)” nennt, obwohl eigentlich eine “Location” angelegt wird. Damit legt man den Pfad, den der externe Nutzer angeben muss. Das ist so kompliziert, weil der Reverse-Proxy mehrere Pfade eines Hosts auf verschiedene Upstream-Server weiterleiten kann. Das muss auch so sein, damit unter anderem das Let’s-Encrypt-Plugin seine Zertifikate mit dem HTTP-01-Verfahren beziehen kann.

Legen wir also eine Location an. Richtig! ‘+’-Knopf klicken.

Location anlegen

In der Abbildung sieht man schon, ich habe einige Felder nicht dargestellt. Der Dialog ist sehr lang und bietet eine Menge an Möglichkeiten. Ich habe mich erst einmal auf das beschränkt, was ich brauche.

Zu “Description” sage ich jetzt nichts mehr. Das “URL Pattern” kann man nutzen, um die angebotenen Pfade einzuschränken. Ich habe hier einmal /myservice angegeben. Ein externer Nutzer kann dann nur auf https://server.example.org/myservice und nicht auf https://server.example.org zugreifen. Allerdings müssen wir dazu noch den Server im nächsten Schritt anlegen.

“Match Type” und “URL Rewriting” lassen wir in den Voreinstellungen. Das kann man für Anpassungen des Pfads verwenden.

“Upstream Servers” meint unsere Server-Gruppe, in der nur ein Server ist, weil wir keine Lastverteilung nutzen.

“Force HTTPS” zu setzen finde ich noch recht wichtig, weil dann ein externer Nutzer, der die unverschlüsselte Seite ansteuert automatisch auf die verschlüsselte weitergeleitet wird.

HTTP-Server anlegen

Zum Abschluss müssen wir noch den extern sichtbaren Server anlegen. Der versteckt sich hinter dem Dreieck auf dem “HTTP(S)"-Karteireiter und heißt “HTTP Server”.

HTTP Server auswählen

Mit der ‘+’-Knopf legen wir unseren Server an.

HTTP-Server anlegen

Die wichtigen Parameter sind “Server Name” (hätte keiner gedacht – oder?), “Locations”, “TLS Certificate”, “CA Certificate” und “HTTPS Only”. Bei “Locations” kann man mehrere Pfade angeben. Wir haben hier nur einen. Das könnte oft ausreichen. Der Reverse-Proxy hat aber auch ein paar schon vordefiniert. So gibt es den .well-known/acme-challenge/ schon. Ich hatte schon Angst, ich würde mir mit meinem Reverse-Proxy die Let’s-Encrypt-Zertifikate zerschießen. Das “TLS Certicate” und das “CA Certificate” wählt ihr einfach passend zum Servernamen aus. Ich denke das richtige CA-Zertifikat ist wichtig, sonst stimmt die ausgelieferte Zertifikatskette nicht und das mögen manche Clients nicht. Wer bei “TLS Certificate” nichts passendes findet muss vielleicht noch die Einrichtung von Let’s-Encrypt-Zertifikaten nachholen.

Der “HTTPS Only”-Parameter ist mir nicht klar. Wir hatten schon bei der Location “HTTPS Force” gesetzt. Nach meinen Experimenten, wird die 302-Redirect-Regel aber nur erzeugt, wenn beide Parameter gesetzt sind. Ist halt so.

Aktualisieren nicht vergessen, sonst gibt es den myserver.example.org nicht in der Konfiguration des nginx und ihr sucht euch einen Wolf.

Fazit

Das nginx-Plugin läuft! Ich war allerdings schon so weit, dass ich überlegt habe den Reverse-Proxy mit dem HAProxy-Plugin aufzubauen. Das ist aber noch abschreckender. Das Problem ist die Dokumentation des nginx-Plugins. Prinzipiell funktioniert es recht einfach, aber von den Aktualisieren-Knöpfen habe ich nirgends etwas gelesen. Ich war echt so weit das Experiment abzubrechen und wieder meine OpenBSD-Firewall einzuschalten. Jetzt gebe ich dem Ganzen noch eine Chance. Ich denke, dass die Dokumentation dieses Plugins, das komplette Produkt OPNsense abwertet. Im Nachhinein bin ich aber begeistert, wenn ich das Ergebnis betrachte. Die erzeugte nginx-Konfiguration ist schon sehr ordentlich.

Das könnte Sie auch interessieren