Linux VPN hinter Reverse-Proxy

Linux Betriebssystem

s-g

Member
Themenstarter
Registriert
27 Mai 2011
Beiträge
837
Hallo Zusammen,

ist zwar nicht ganz Foren-Nah, aber einen Versuch ist's wert :)

Ziel: Ich würde gerne via TCP über Port 443 eine Verbindung zu meinem VPN-Server aufbauen können.
Der Server läuft lokal hinter meinem Router.
TCP und Port 443 sind ein muss, da der auch restriktiv abgeriegelten Netzwerken freigegeben ist (im Gegensatz zu UDP und 1194 o.ä.).

Problem: Hinter Port 443 läuft ein nginx Reverseproxy (und dahinter Web-Services). Der VPN Traffic müsste darüber geroutet werden.

Meine Idee war, den TCP-Traffic über das Stream-Modul an den VPN-Server weiterzuleiten. Config wie folgt:

Code:
stream {
    upstream backend {
        set $upstream_app openvpnsg;
        set $upstream_port 443;
        proxy_pass $upstream_app:$upstream_port;
        }
    server {
        listen 443 so_keealive=on;
        server_name vpns.*;

        proxy_connect_timeout 300s;
        proxy_timeout 300s;

        proxy_pass backend;
    }
}

Das erzeugt aber nur einen TCP packet size error.
Macht mir da die SSL-Termination einen strich durch die Rechnung (SSL ist für alle anderen Server aktiviert)? Funktioniert das überhaupt grundsätzlich?
Bis jetzt hab ich nur Vorschläge zu Configurationen gefunden, bei denen der 443 exklusiv für VPN zu Verfügung steht...

Grüße
Alex
 
KI Hilfestellung:

Dein Ansatz ist grundsätzlich korrekt, aber das Problem könnte tatsächlich an der SSL-Termination liegen. Wenn dein Nginx-Server aktuell SSL für Port 443 konfiguriert hat, dann versucht er, den VPN-Traffic als HTTPS zu interpretieren, was zu den „TCP packet size errors“ führt. OpenVPN über Port 443 zu routen, während gleichzeitig HTTPS über den gleichen Port bereitgestellt wird, ist eine Herausforderung, die man auf mehrere Arten angehen kann.

Hier sind ein paar Lösungsmöglichkeiten:

### Lösung 1: Verschiedene Subdomains für VPN und HTTPS nutzen
Falls du auf deinem Netzwerk die Kontrolle über DNS hast, könntest du versuchen, den Nginx-Server so zu konfigurieren, dass er basierend auf der Subdomain unterschiedliche Dienste auf Port 443 anbietet.

Beispiel:
- `vpn.example.com` für den VPN-Traffic.
- `www.example.com` oder andere Subdomains für den regulären HTTPS-Traffic.

Nginx-Konfiguration:

```nginx
stream {
upstream vpn_backend {
server 127.0.0.1:1194; # Dein OpenVPN Server-Port
}

upstream https_backend {
server 127.0.0.1:8443; # Upstream-Port für HTTPS
}

server {
listen 443;
ssl_preread on;

# Wenn SNI `vpn.example.com` ist, leite auf VPN weiter
if ($ssl_preread_server_name = "vpn.example.com") {
proxy_pass vpn_backend;
}

# Andernfalls leite auf den HTTPS-Dienst weiter
proxy_pass https_backend;
}
}
```

Hier wird `ssl_preread` verwendet, um die Server-Name-Indikation (SNI) im TLS-Handshake zu prüfen und basierend auf dem Servernamen (hier `vpn.example.com`) den Traffic an den OpenVPN-Server weiterzuleiten.

### Lösung 2: OpenVPN über einen alternativen Port bereitstellen
Falls es möglich ist, könntest du auch OpenVPN auf einem anderen Port laufen lassen, der ebenfalls in restriktiven Netzwerken freigegeben ist. Manche Netzwerke blockieren Port 1194 für UDP, aber es gibt andere Ports (z. B. 443 über TCP), die häufiger offen sind.

Falls du nicht zwingend Port 443 benötigst, könnte dies eine praktikable Alternative sein.

### Lösung 3: SSL-Terminierung am VPN-Server (OpenVPN)
Eine andere Möglichkeit wäre, SSL direkt am OpenVPN-Server zu terminieren und dann Nginx nur als einfachen Proxy zu verwenden. Das erfordert jedoch, dass der OpenVPN-Server SSL-Verbindungen direkt annehmen kann. Das könnte wie folgt aussehen:

- Nginx lauscht auf 443 und leitet TCP-Traffic an den VPN-Server weiter.
- OpenVPN nimmt dann die SSL-Verbindungen an.

Falls du jedoch HTTPS und OpenVPN auf derselben IP und demselben Port betreiben willst, bleibt die beste Option, die Server-Name-Indikation (SNI) zu nutzen, wie in Lösung 1 beschrieben.

### Zusammenfassung
Die Nutzung von `ssl_preread` mit SNI-basierter Weiterleitung dürfte die sauberste Lösung für deinen Fall sein, da du sowohl Web- als auch VPN-Traffic über denselben Port (443) routen möchtest.
 
Bei packet size error denke ich immer an MTU/PMTU. Vielleicht mal damit rum probieren?

Kann ich das via nginx beeinflussen? Dachte das wäre Sache vom Socket/Netwerkadapter. Da passt alles, beliebige anderer Ports ohne nginx dahinter funktioniert einwandfrei.

KI Hilfestellung:

[...]

Ähnlich wie Lösung 1 war meine Idee, allerdings mit server_name Modul anstelle ssl_preread. Lösung 2 funktioniert, fällt wegen anderem Port aber raus.
Meine Config dem Vorschlag 1 entsprechend angepasst:

Code:
stream {
    upstream backend_vpn {
        set $upstream_app openvpn;
        set $upstream_port 443;
        proxy_pass $upstream_app:$upstream_port;
        }
    upstream backend_https {
        set $upstream_app nginx;
        set $upstream_port 443;
        proxy_pass $upstream_app:$upstream_port;
        }
    server {
        listen 443;
        ssl_preread on;

        if ($ssl_preread_server_name = "vpn....de") {
                proxy_pass backend_vpn;
        }
        proxy_pass backend_https;
    }
}

Anmerkung zu den Adressen: Da sich nginx, VPN-Server etc. in einer Dock-Umgebung befinden nutze ich die container-names.

Das Ergebnis ist leider das Gleiche wie mit der alten Config.

Was mich aber wundert: Da mehrere Services über den Reverseproxy bedient werden habe mangels einer besseren Idee den nginx-Container als Empfänger für den "nicht-VPN-Traffic" eingetragen. Ich hätte erwartet, dass die anderen Dienste nicht mehr erreichbar sind (da Zikrelschluss), die funktionieren aber noch...
Die VPN-Config ist direkt in der nginx.conf eingebunden, die anderen Dienste im http Block.
Config verwende ich größtenteils die Standard des LinuxServer.io SWAG-Containers
 
Wie wäre es denn erstmal mit einem Diagram, aus dem die Netzwerktopologie ersichtlich wird? Eventuell könnte man nach der IP des VPN-Clients filtern.
 
Die Client-IPs sind unbekannt, da von außerhalb des Netzwerkes.
Die aktuelle Netzwerktopologie:
Bildschirmfoto vom 2024-11-01 11-35-58.png

Danke für die Portsharing Idee! Klingt vielversprechend, darauf bin ich noch nicht gekommen.
Nach kurzem googlen hab ich das Konzept angepasst und einen haproxy-container vor nginx und openvpn geschalten, config von hier übernommen:

Topologie;
Bildschirmfoto vom 2024-11-01 13-34-34.png

Das gute: Sowohl Zugriff auf den VPN als auch auf nginx funktionieren :) ... jedenfalls auf den öffentlichen service.
Problem: Es laufen noch einige private Services, die auf Zugriffe aus dem lokalen Netzwerk beschränkt sind. Da alle Anfragen an nginx mit der IP des haproxy Container ankommen lässt sich das nicht mehr unterscheiden.
Eigentlich wollte ich haproxy deswegen im transparent mode betreiben, das scheint in der Docker-Umgebung aber nicht so einfach zu sein.
sslh wäre eventuell noch eine Option, damit muss ich mich noch nicht beschäftigen.
Mich wundert nur etwas, dass das multiplexen mit haproxy funktioniert, mit nginx aber nicht. Aber den Fehler in meiner Config (außer den Tippfehler) habe ich noch nicht gefunden.
 
Alternativ könntest du dir noch Traefik anschauen, anstatt haproxy+nginx und könntest beides dadurch ersetzen. Ich meine, damit müsste deine Config auch möglich sein. Aber ausprobiert habe ich es nie. Damit könntest du vermutlich auch die IPs "heile" behalten.
 
Du musst im haproxy config die "XForwarded for" Direktive setzen:
Dies muss allerdings auch im NGINX konfiguriert werden, er schaut normalerweilse nicht nach xforward.
 
  • Like
Reaktionen: s-g
Vor einem Umstieg von nginx auf einen anderen Reverseproxy schrecke ich noch etwas zurück. nginx ist sicher genug konfiguriert, dass ich mich traue den ans Internet zu hängen. Bei einem neuen Reverseproxy wäre das erstmal eine ganze Ecke Arbeit.

Aber ich habe eine Lösung :)

Port 443 hängt wieder direkt an nginx.
Port 80 benötige ich nur für die HTTP-01 challenge. Also hängt haproxy jetzt hinter Port 80 und routed http Traffic zu nginx und alles andere zu OpenVPN.
Bildschirmfoto vom 2024-11-01 16-49-37.png

Port 80 ist auch überall offen, das Risiko, dass verschlüsselter Traffic gefiltert wird vermutlich etwas höher, aber ohne weitere Maskierung (die mir viel zu aufwändig ist) kann das auch auf 443 passieren.

Danke an alle!
 
@qwali : Zu spät gesehen, danke für den Tipp! Versuche ich, wenn ich mit Port 80 auf Probleme stoße.

@schoerg : Wäre auch valide, aber den haproxy Container einzurichten war einfacher, als mich mit der API zur automatischen Zertifikatserneuerung auseinanderzusetzen :)
 
  • ok1.de
  • ok2.de
  • thinkstore24.de
  • Preiswerte-IT - Gebrauchte Lenovo Notebooks kaufen

Werbung

Zurück
Oben