SSD Nodes Learn 🎉 VPS ab $5.50/Monat
Anleitungen Matt ConnorVon Matt Connor · Aktualisiert 2026-08-21

CGNAT umgehen: Reverse-Tunnel mit einem VPS

CGNAT verhindert Portweiterleitung, weil Ihr Router keine öffentliche IP hat. Mit frp auf einem günstigen VPS bauen Sie den Tunnel nach außen auf und nutzen HTTPS.

Warum Portweiterleitung hinter CGNAT nicht funktioniert

Hinter CGNAT (Carrier-Grade Network Address Translation) wird die WAN-Adresse Ihres Routers mit anderen Teilnehmern geteilt. Ihnen ist daher keine öffentliche IP-Adresse zugeordnet, und es gibt keinen Port, den Sie weiterleiten können. Ein Reverse-Tunnel löst dieses Problem: Ein günstiger VPS stellt die öffentliche IP-Adresse bereit, Ihr Rechner zu Hause baut die ausgehende Verbindung zum VPS auf, und eingehende Anfragen werden über diese bereits geöffnete Verbindung zurück an den Heimrechner geleitet. Sie können die bereits vorhandene Hardware weiterverwenden. Sie mieten nur das, was Ihr ISP Ihnen nicht bereitstellt: eine routbare Adresse.

Jeder folgende Befehl ist mit dem Rechner gekennzeichnet, auf dem er ausgeführt wird. Sie benötigen zwei Rechner: den VPS mit einer öffentlichen IP-Adresse und den Heimrechner, auf dem der Dienst läuft, den Sie erreichen möchten.

So erkennen Sie, ob Sie tatsächlich hinter CGNAT stehen

Öffnen Sie die Administrationsoberfläche Ihres Routers und lesen Sie die dort angezeigte WAN-Adresse ab. Ermitteln Sie anschließend, welche Adresse das Internet von außen sieht.

# on the home box
curl -4 -s https://ifconfig.me; echo

Wenn beide Adressen übereinstimmen, haben Sie eine öffentliche IP-Adresse und benötigen nichts davon. Richten Sie die Portweiterleitung ein und lesen Sie nicht weiter. Liegt die WAN-Adresse des Routers innerhalb von 100.64.0.0/10, stehen Sie hinter CGNAT. Dieser Bereich ist der gemeinsam genutzte Adressraum nach RFC 6598 und genau für diesen Zweck reserviert. Einige ISPs verwenden auf der WAN-Seite stattdessen 10.0.0.0/8. Das ist dieselbe Situation unter einer anderen Bezeichnung.

Prüfen Sie dies, bevor Sie etwas mieten. Viele ISPs mit CGNAT stellen ein echtes IPv6-Präfix bereit. Wenn Ihr Gerät zu Hause eine globale IPv6-Adresse hat, können Sie die Firewall für diese Adresse öffnen und vollständig auf den Tunnel verzichten. Das funktioniert nicht mehr, sobald ein Besucher ein reines IPv4-Netzwerk verwendet. Deshalb landen die meisten Nutzer letztlich trotzdem hier.

So funktioniert ein VPS-Reverse-Tunnel, der von innen nach außen aufgebaut wird

CGNAT und gewöhnliche Heimrouter blockieren beide nicht angeforderte eingehende Verbindungen. Das gilt auch für Unternehmensfirewalls. Ausgehende Verbindungen blockiert keines dieser Systeme, weil Browser und Update-Clients den ganzen Tag ausgehende Verbindungen herstellen. Ein NAT-Gerät, das eine ausgehende TCP-Verbindung erkennt, erstellt dafür ein Mapping und lässt anschließend den Rückverkehr über diese Verbindung zu. Von außen kann niemand eine Verbindung zu Ihrem Heimserver starten. Deshalb baut der Heimserver die Verbindung auf, und der Tunnel überträgt den Datenverkehr über dieselbe Verbindung in die entgegengesetzte Richtung zurück.

Das ist der gesamte Mechanismus. Der Heimserver stellt über einen Port eine ausgehende Verbindung zum VPS her und hält sie offen. Der VPS nimmt öffentliche Anfragen entgegen und leitet sie über diese bestehende Verbindung weiter. Niemand versucht, Ihre private IP-Adresse zu erreichen. Das ist daher auch nicht erforderlich.

Daraus ergeben sich zwei nützliche Konsequenzen. Ihr DNS-Eintrag verweist auf den VPS und niemals auf Ihren Anschluss zu Hause. Ihre öffentliche Adresse ist jetzt die Adresse des VPS. Alles, was ein Beobachter über eine IP-Abfrage erfährt, bezieht sich daher auf einen gemieteten Server und nicht auf Ihren Heimanschluss.

Drei Möglichkeiten zum Aufbau

  1. ssh -R: Bereits auf beiden Seiten installiert und geeignet für einen einzelnen Dienst oder eine vorübergehende Demo. Es gibt kein Dashboard und keine nennenswerte Logik für die Wiederherstellung von Verbindungen.
  2. frp: Ein kleiner Go-Server (frps) und ein passender Client (frpc). Geeignet für einen dauerhaften Aufbau mit mehreren Diensten hinter einem Hostnamen. Der Hauptteil dieser Anleitung behandelt diese Variante.
  3. Ein Mesh-VPN: Tailscale oder ein WireGuard-Server, den Sie selbst betreiben. Geeignet, wenn Ihre eigenen Geräte einander privat erreichen sollen, statt etwas im öffentlichen Internet zu veröffentlichen.

Wählen Sie das Mesh, wenn Sie privaten Zugriff von Geräten wünschen, die Sie kontrollieren. Tailscale Serve und Funnel behandelt die Veröffentlichung aus einem Tailnet heraus. Ein selbst gehostetes WireGuard-VPN auf demselben VPS bietet Ihnen denselben Aufbau, ohne dass ein Koordinierungsserver eines Drittanbieters im Datenpfad liegt. Lesen Sie einen dieser Abschnitte und überspringen Sie den Rest dieser Seite. Alle folgenden Abschnitte setzen voraus, dass Sie einen öffentlichen HTTPS-Hostnamen wünschen, den jeder aufrufen kann.

Die Kurzfassung: ssh -R für einen Dienst

Angenommen, auf dem Heimserver läuft eine Anwendung auf 127.0.0.1:3000 und Sie haben bereits SSH-Zugriff auf den VPS.

# on the home box
ssh -N \
  -o ExitOnForwardFailure=yes \
  -o ServerAliveInterval=30 \
  -o ServerAliveCountMax=3 \
  -R 127.0.0.1:8080:127.0.0.1:3000 \
  tunnel@vps.example.com

-R 127.0.0.1:8080:127.0.0.1:3000 weist den sshd des VPS an, auf dem VPS einen eigenen 127.0.0.1:8080 zu öffnen und alle dort eingehenden Verbindungen an 127.0.0.1:3000 auf dem Heimserver weiterzuleiten. -N bedeutet, dass keine Shell gestartet wird. Die beiden Optionen ServerAlive sorgen dafür, dass SSH eine unterbrochene Verbindung nach etwa 90 Sekunden erkennt, statt an einer nicht mehr bestehenden Verbindung hängen zu bleiben.

Jetzt kommt der Teil, der häufig für Verwirrung sorgt. Der Listener ist an das Loopback-Interface gebunden. Deshalb schlägt curl http://vps.example.com:8080 von jedem anderen System aus fehl. sshd verwendet standardmäßig GatewayPorts no. Das bedeutet, dass ein Remote-Forward nur an das Loopback-Interface gebunden wird. Ändern Sie das nicht durch GatewayPorts yes. Lassen Sie den Forward am Loopback-Interface und setzen Sie nginx davor, wie beim weiter unten beschriebenen frp-Setup. Dann ist der öffentliche Port 443 mit einem Zertifikat erreichbar, während der Tunnel-Port nicht aus dem Internet erreichbar ist. Wenn Sie nicht sicher sind, welcher Prozess aktuell an welchem Interface lauscht, lohnt sich ein kurzer Überblick über Ports und Listener unter Linux.

Wenn der Port auf dem VPS bereits belegt ist, gibt SSH diese Meldung aus. ExitOnForwardFailure=yes sorgt dafür, dass SSH den Verbindungsversuch abbricht, statt eine Verbindung ohne funktionierenden Tunnel aufzubauen:

Warning: remote port forwarding failed for listen port 8080

Die häufigste Ursache ist eine vorherige Sitzung, die beendet wurde, ohne dass sshd dies erkannt hat. Setzen Sie ClientAliveInterval 30 und ClientAliveCountMax 3 in der /etc/ssh/sshd_config des VPS. Dadurch werden verwaiste Sitzungen bereinigt und die Ports freigegeben. Fassen Sie den gesamten Befehl mit Restart=always in einer systemd-Unit zusammen und verwenden Sie einen dedizierten Schlüssel. Alternativ können Sie autossh verwenden. Für mehr als einen Dienst sollten Sie an dieser Stelle aufhören und frp verwenden.

frp auf dem VPS installieren und auf einen Tag festlegen

frp wird als statische Go-Binärdatei veröffentlicht und ist nicht in den Ubuntu- oder Debian-Archiven enthalten. Sie laden daher eine Veröffentlichung herunter und prüfen sie selbst. Legen Sie die Version fest. Das Konfigurationsformat wurde mit v0.52.0 geändert. Seitdem wurden außerdem Optionsnamen verschoben. Ein veraltetes Tutorial liefert Ihnen daher Schlüssel, die Ihre Binärdatei nicht erkennt. Diese Anleitung verwendet v0.71.0, veröffentlicht am 14. August 2026.

# on the VPS
FRP_VERSION=0.71.0
ARCH=amd64   # use arm64 if `uname -m` prints aarch64
cd /tmp
curl -fsSLO "https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_linux_${ARCH}.tar.gz"
curl -fsSLO "https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_sha256_checksums.txt"
sha256sum --check --ignore-missing frp_sha256_checksums.txt

sha256sum sollte genau eine Zeile ausgeben:

frp_0.71.0_linux_amd64.tar.gz: OK

--ignore-missing wird benötigt, weil die Prüfsummendatei alle achtzehn Veröffentlichungsdateien abdeckt und Sie eine davon heruntergeladen haben. Ohne dieses Flag meldet sha256sum die übrigen siebzehn Dateien als fehlend und wird mit einem Exit-Status ungleich null beendet. Das sieht wie eine fehlgeschlagene Prüfung aus, obwohl kein Fehler vorliegt.

# on the VPS
tar xzf "frp_${FRP_VERSION}_linux_${ARCH}.tar.gz"
sudo install -m 755 "frp_${FRP_VERSION}_linux_${ARCH}/frps" /usr/local/bin/frps
sudo useradd --system --no-create-home --shell /usr/sbin/nologin frp
sudo install -d -m 750 -o root -g frp /etc/frp
frps --version

frps --version gibt 0.71.0 aus. Nur frps wird auf dem VPS verwendet. frpc wird auf dem Home-Server verwendet. Beide Binärdateien überall zu installieren, führt dazu, dass versehentlich ein Tunnelserver zu Hause ausgeführt wird.

Die VPS-Konfiguration: Token, erzwungenes TLS, Loopback-Listener

Generieren Sie zuerst ein Token. Es ist die einzige Schutzmaßnahme zwischen Ihrem Tunnel und jedem, der die VPS-Ports scannt.

# on the VPS
openssl rand -base64 32

Schreiben Sie diesen Wert in /etc/frp/frps.toml:

bindAddr = "0.0.0.0"
bindPort = 7000

# Every listener frp creates for a proxy, including the HTTP vhost, stays on loopback.
proxyBindAddr = "127.0.0.1"
vhostHTTPPort = 8080

auth.method = "token"
auth.token = "PASTE_THE_OPENSSL_OUTPUT_HERE"

transport.tls.force = true

webServer.addr = "127.0.0.1"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "PASTE_A_SECOND_SECRET_HERE"

log.level = "info"

Vier dieser Zeilen übernehmen die Sicherheitsfunktionen. Sehen Sie sie deshalb einzeln an.

auth.token muss auf dem Client mit auth.token übereinstimmen. Ohne diese Einstellung akzeptiert frps jeden Client, der Port 7000 findet. Dieser Client kann dann beliebige Dienste über Ihre VPS und Ihr Zertifikat veröffentlichen.

transport.tls.force = true weist jede Steuerungsverbindung zurück, die nicht TLS (Transport Layer Security) verwendet. Clients aktivieren TLS seit v0.50.0 standardmäßig. In der Praxis entsteht Ihnen dadurch kein Aufwand. Gleichzeitig wird verhindert, dass sich ein alter oder selbst erstellter Client unverschlüsselt verbindet, ohne dass Sie davon erfahren.

proxyBindAddr = "127.0.0.1" ist die Zeile, die in den meisten Anleitungen fehlt. Sie sorgt dafür, dass diese Konfiguration dauerhaft sicher betrieben werden kann. Die Einstellung verschiebt jeden Listener, den frp im Auftrag eines Proxys öffnet, auf die Loopback-Schnittstelle. Das gilt sowohl für den HTTP-vhost als auch für jedes remotePort, das ein Client anfordert. Das Internet kann diese Listener überhaupt nicht erreichen. Der einzige öffentlich erreichbare Zugang ist nginx auf Port 443, den Sie konfigurieren und kontrollieren.

webServer.addr = "127.0.0.1" hält das Dashboard von der öffentlichen Schnittstelle fern. Das Dashboard enthält eine vollständige Übersicht über Ihre privaten Dienste und deren Datenverkehr. Es ist nur durch ein HTTP-Basic-Auth-Passwort geschützt und gehört daher nicht auf 0.0.0.0.

Legen Sie den Eigentümer fest, damit das Token nicht für alle Benutzer lesbar ist. Prüfen Sie anschließend die Syntax, bevor Sie etwas starten:

# on the VPS
sudo chown root:frp /etc/frp/frps.toml
sudo chmod 640 /etc/frp/frps.toml
sudo -u frp frps verify -c /etc/frp/frps.toml

Eine gültige Datei gibt Folgendes aus:

frps: the configuration file /etc/frp/frps.toml syntax is ok

Ein Hinweis zum Format, der Ihnen eine Stunde Arbeit ersparen kann: frp wählt den Parser anhand der Dateierweiterung aus und unterstützt .toml, .yaml, .yml und .json. Alte .ini-Dateien werden weiterhin über einen Legacy-Konvertierungspfad geladen. INI ist jedoch veraltet, und neue Optionen werden nur für TOML dokumentiert. Wenn eine Anleitung einen Abschnitt [common] und server_addr = x.x.x.x zeigt, stammt sie aus der Zeit vor v0.52.0. Die dort verwendeten Schlüsselnamen stimmen dann nicht mit dem gerade installierten Binary überein.

frps als Dienst ohne Root-Rechte ausführen

bindPort ist 7000 und vhostHTTPPort ist 8080. Beide Ports liegen über 1024. frps benötigt daher weder root noch CAP_NET_BIND_SERVICE. Deshalb sollte der virtuelle Host nicht auf Port 80 gelegt werden. Nginx übernimmt stattdessen Port 80.

Erstellen Sie /etc/systemd/system/frps.service:

[Unit]
Description=frp reverse tunnel server
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=frp
Group=frp
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.toml
Restart=on-failure
RestartSec=5s
LimitNOFILE=65535
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ProtectKernelTunables=true

[Install]
WantedBy=multi-user.target
# on the VPS
sudo systemctl daemon-reload
sudo systemctl enable --now frps
sudo journalctl -u frps -n 20 --no-pager

Das Log sollte beide Listener anzeigen. Die Adressen sind dabei wichtiger als die Ports:

frps tcp listen on 0.0.0.0:7000
http service listen on 127.0.0.1:8080

ProtectSystem=strict stellt das gesamte Dateisystem für diesen Dienst auf schreibgeschützt. frps funktioniert damit, weil das Log standardmäßig in die Standardausgabe geschrieben wird und journald es erfasst. Wenn Sie log.to auf einen Dateipfad setzen, kann der Dienst zunächst nicht in diese Datei schreiben. Erst eine passende Zeile mit ReadWritePaths= ermöglicht das. Belassen Sie daher den Standardwert.

Firewall: einen Port öffnen, nicht einen Bereich

# on the VPS
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 7000/tcp
sudo ufw enable
sudo ufw status numbered

Vier Regeln, von denen eine nur für die Zertifikatserneuerung benötigt wird. 22 ist SSH. 80 leitet auf 443 um und beantwortet die ACME-Challenge (Automatic Certificate Management Environment). 443 stellt alle getunnelten Anwendungen bereit. 7000 ist der frp-Steuerungsport. Er ist der einzige Port, den ein Client erreichen können muss.

Anleitungen, die zum Öffnen eines Bereichs wie sudo ufw allow 20000:30000/tcp auffordern, beschreiben das andere Design. Dabei verwendet jeder Dienst seinen eigenen öffentlichen TCP-Port. Das ist hier nicht erforderlich, weil alle Verbindungen über 443 eingehen und frp sie anhand des Hostnamens weiterleitet. Wenn Sie später einen tatsächlich öffentlichen TCP-Port benötigen, setzen Sie proxyBindAddr wieder auf 0.0.0.0 und fügen Sie Einschränkungen hinzu, damit ein Client nur die von Ihnen angegebenen Ports verwenden kann:

allowPorts = [
  { start = 20000, end = 20010 }
]
maxPortsPerClient = 5

Die meisten Provider betreiben zusätzlich eine Netzwerk-Firewall im Control Panel, die von ufw auf dem Server getrennt ist. Eine Regel, die in sudo ufw status korrekt aussieht und bei der dennoch ein Timeout auftritt, wird dort normalerweise blockiert. Die ufw-Regeln, die ein VPS tatsächlich benötigt führt durch die Default-Deny-Konfiguration, von der dieser Abschnitt ausgeht.

HTTPS auf dem VPS mit einem echten Zertifikat terminieren

Legen Sie für home.example.com einen A-Record fest, der auf die öffentliche IP-Adresse des VPS zeigt. Nicht auf Ihr Haus. Ihr Haus hat keine Adresse, auf die Sie zeigen können. Genau das ist das Problem, das Sie lösen.

# on the VPS
sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginx

Erstellen Sie /etc/nginx/sites-available/home.example.com zunächst mit einem einfachen Block für Port 80. Dadurch hat certbot ein passendes server_name, mit dem es arbeiten kann:

server {
    listen 80;
    listen [::]:80;
    server_name home.example.com;
    location / { return 404; }
}
# on the VPS
sudo ln -s /etc/nginx/sites-available/home.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot certonly --nginx -d home.example.com

nginx -t gibt nginx: configuration file /etc/nginx/nginx.conf test is successful aus, wenn die Dateien syntaktisch korrekt sind. Führen Sie den Befehl vor jedem Reload aus. Wenn ein Reload fehlschlägt, lässt nginx die alte Konfiguration weiterlaufen. Eine fehlerhafte Änderung sieht dadurch wie eine Änderung aus, die keine Wirkung hatte.

WebSocket-Upgrades benötigen auf der http-Ebene eine Map. Fügen Sie sie in /etc/nginx/conf.d/upgrade.conf ein:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

Ersetzen Sie die Site-Datei nun durch die endgültige Version:

server {
    listen 80;
    listen [::]:80;
    server_name home.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name home.example.com;

    ssl_certificate     /etc/letsencrypt/live/home.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/home.example.com/privkey.pem;

    client_max_body_size 512m;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade           $http_upgrade;
        proxy_set_header Connection        $connection_upgrade;
        proxy_read_timeout 3600s;
    }
}

proxy_set_header Host $host; ist hier zwingend erforderlich. Der HTTP-vhost von frp routet anhand des Headers Host und gleicht ihn mit der Liste customDomains in der Client-Konfiguration ab. Fehlt dieser Header, sendet nginx Host: 127.0.0.1. frp findet keinen Proxy für diesen Namen, und Ihr Besucher erhält von frp einen einfachen 404-Fehler statt einer Seite der Anwendung. Jede Zeile eines nginx-Reverse-Proxy-Blocks erklärt beschreibt, welche Funktion die anderen Header haben.

# on the VPS
sudo nginx -t && sudo systemctl reload nginx
sudo certbot renew --dry-run

Der Testlauf bestätigt, dass die Erneuerung in neunzig Tagen funktionieren wird, wenn Sie sie nicht überwachen. Dafür muss Port 80 erreichbar sein. Deshalb ist diese ufw-Regel erforderlich.

Die Seite im Heimnetz: frpc als unprivilegierter Dienst

Installieren Sie frpc auf dem Rechner im Heimnetz genau wie zuvor frps: mit derselben Version und demselben Prüfsummenschritt. Legen Sie anschließend denselben Benutzer frp und dasselbe Verzeichnis /etc/frp an. Schreiben Sie /etc/frp/frpc.toml:

serverAddr = "vps.example.com"
serverPort = 7000

auth.method = "token"
auth.token = "PASTE_THE_SAME_TOKEN_HERE"

transport.tls.enable = true
loginFailExit = false

proxies = [
  { name = "home-app", type = "http", localIP = "127.0.0.1", localPort = 3000, customDomains = ["home.example.com"] }
]

Die Reihenfolge der Schlüssel ist in dieser Datei wichtig, und zwar nicht aus Gründen der Formatierung. TOML ordnet jeden Schlüssel nach einer Tabellenüberschrift dieser Tabelle zu. Eine globale Einstellung wie serverAddr, die unterhalb einer Proxy-Tabellenüberschrift steht, wird dadurch unbemerkt zu einer Proxy-Einstellung, die frp ignoriert. Wenn Sie die Proxy-Liste wie oben als Inline-Array schreiben, vermeiden Sie dieses Problem. Jeder globale Schlüssel bleibt dadurch eindeutig auf der obersten Ebene.

type = "http" leitet diesen Proxy über den Vhost-Listener weiter, anstatt einen eigenen öffentlichen TCP-Port zu beanspruchen. Deshalb blieb die Firewall bei vier Regeln. customDomains muss den Hostnamen enthalten, den nginx im Header Host weiterleitet. Daher ist der Wert home.example.com und niemals die IP-Adresse des VPS.

loginFailExit = false ist wichtiger, als es zunächst scheint. Der Standardwert ist true. Dadurch beendet sich frpc, wenn der erste Anmeldeversuch fehlschlägt. Auf einem Rechner im Heimnetz, der den Bootvorgang beendet, bevor die Verbindung zum ISP verfügbar ist, bleibt der Dienst dann beendet, bis Sie das Problem bemerken. Setzen Sie den Wert auf false. Dann versucht frpc die Verbindung weiter, bis der VPS antwortet.

Schreiben Sie /etc/systemd/system/frpc.service:

[Unit]
Description=frp reverse tunnel client
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=frp
Group=frp
ExecStart=/usr/local/bin/frpc -c /etc/frp/frpc.toml
Restart=always
RestartSec=10s
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true

[Install]
WantedBy=multi-user.target
# on the home box
sudo chown root:frp /etc/frp/frpc.toml
sudo chmod 640 /etc/frp/frpc.toml
sudo -u frp frpc verify -c /etc/frp/frpc.toml
sudo systemctl daemon-reload
sudo systemctl enable --now frpc
sudo journalctl -u frpc -n 20 --no-pager

Ein Client, der eine Verbindung hergestellt hat, protokolliert eine Lauf-ID:

login to server success, get run id [3a1f9c2b7d4e5f60]

Öffnen Sie https://home.example.com in einem Browser. Sie sollten die Anwendung erreichen, die zu Hause unter 127.0.0.1:3000 läuft. Restart=always auf dem Client ist beabsichtigt: Verbindungen im Heimnetz können abbrechen, und der Dienst soll ohne Ihr Eingreifen wieder verfügbar werden.

Dashboard nicht an der öffentlichen Schnittstelle bereitstellen

Mit webServer.addr = "127.0.0.1" antwortet das Dashboard nur auf dem VPS selbst. Greifen Sie von Ihrem Laptop über eine lokale Weiterleitung darauf zu, statt einen Port zu öffnen:

# on your laptop
ssh -N -L 7500:127.0.0.1:7500 you@vps.example.com

Öffnen Sie http://127.0.0.1:7500 und melden Sie sich mit webServer.user und webServer.password aus frps.toml an. Die Seite listet jeden verbundenen Client und die Traffic-Zähler für jeden Proxy auf. Damit lässt sich am schnellsten feststellen, ob die Systeme zu Hause gerade verbunden sind. Wenn Sie die SSH-Sitzung schließen, ist das Dashboard wieder nicht erreichbar.

Was der Tunnel nicht leistet

Lesen Sie diesen Abschnitt zweimal, denn hier entstehen die größten Risiken. Der Tunnel macht einen privaten Dienst aus dem öffentlichen Internet erreichbar. Er authentifiziert nicht die Personen, die darauf zugreifen. Sobald https://home.example.com aufgelöst wird, finden Scanner den Dienst innerhalb weniger Tage. Das gilt unabhängig davon, ob Sie den Namen jemandem mitgeteilt haben. Certificate-Transparency-Logs veröffentlichen jeden Hostnamen, für den Sie ein Zertifikat ausstellen. Der Name ist daher öffentlich, sobald certbot erfolgreich ausgeführt wurde.

Alles, was Sie veröffentlichen, muss eine eigene Authentifizierung bereitstellen. Verfügt die Anwendung über einen echten Login mit Rate-Limiting, ist das ausreichend. Verwendet der Login dagegen nur ein gemeinsames Passwort oder gibt es überhaupt keinen Login, schalten Sie auf dem VPS einen authentifizierenden Proxy davor. Ein oauth2-proxy vor der Anwendung ist dafür die übliche Lösung. Er wird zwischen nginx und den frp-vhost geschaltet, ohne dass Sie die beiden Tunnelenden ändern müssen.

Das Token in frps.toml schützt den Tunnel, nicht die Anwendungen. Es verhindert, dass ein Fremder einen eigenen Proxy auf Ihrem VPS registriert. Es schützt nicht vor einer Anfrage, die auf Port 443 für einen Hostnamen eintrifft, den Sie absichtlich veröffentlicht haben.

Zwei Gewohnheiten sind sinnvoll. Ändern Sie das Token, indem Sie beide Dateien bearbeiten und beide Dienste neu starten, denn es läuft nicht automatisch ab. Halten Sie außerdem frp aktuell. Dieses Binary ist Ihr öffentlich erreichbarer Zugangspunkt. Die Hinweise zu v0.71.0 nennen einen Server-Panic, die durch einen fehlerhaften Wert ausgelöst wird, den ein Client sendet. Diese Fehlerklasse sollte durch ein Update behoben werden, statt sie im laufenden Betrieb zu analysieren.

Failure modes, with the strings you will see

The client never connects. journalctl -u frpc repeats connect to server error: followed by a dial timeout. Nothing is reaching port 7000. Check ufw on the VPS, then the provider's network firewall in the control panel, then confirm the name resolves with getent hosts vps.example.com.

The token is wrong. The client says so in as many words:

login to the server failed: token in login doesn't match token from configuration

Copy the token again. A trailing newline, or a $ in an unquoted shell string that expanded to nothing, causes almost all of these. That is why the openssl rand -base64 32 output belongs inside quotes in the TOML file.

The tunnel is up but the browser gets a bare 404. frpc logged a successful login and the dashboard lists the proxy, yet the page returns 404 with none of the app's styling. That is frp reporting it has no proxy for this Host header. Test the vhost directly on the VPS, bypassing both nginx and TLS:

# on the VPS
curl -s -o /dev/null -w '%{http_code}\n' -H 'Host: home.example.com' http://127.0.0.1:8080/

A 404 from that command means customDomains is wrong. Any other code means the request never got the right Host from nginx.

502 from nginx. nginx is answering and frp is not. sudo ss -lntp | grep 8080 on the VPS should show frps listening on 127.0.0.1:8080. Empty output means frps is stopped, or vhostHTTPPort is unset in frps.toml.

The app thinks every visitor is local. Your app logs 127.0.0.1 for every request. frp sets X-Forwarded-For and nginx appends to it, so the real client address is in that header. Configure the app to trust it. Do not skip this if the app rate limits by IP address, because at the moment every visitor on the internet shares one bucket.

Long requests get cut at 60 seconds. Uploads or streaming responses stop partway through. That is nginx's default proxy_read_timeout, not the tunnel. The block above raises it to 3600s. client_max_body_size is the matching limit for upload size, and its default of 1 MB rejects larger bodies with a 413.

Everything works, then dies after a router reboot. Restart=always in the frpc unit plus loginFailExit = false covers this. Confirm with sudo systemctl is-enabled frpc, which must print enabled.

FAQ

Woher weiß ich, ob ich hinter CGNAT stecke?

Vergleichen Sie die WAN-Adresse auf der Administrationsseite Ihres Routers mit dem Ergebnis von curl -4 -s https://ifconfig.me aus demselben Netzwerk. Wenn die Adressen voneinander abweichen und die WAN-Adresse des Routers innerhalb von 100.64.0.0/10 liegt, verwendet Ihr ISP Carrier-Grade NAT. Dieser Bereich ist ein gemeinsam genutzter Adressraum gemäß RFC 6598 und für diesen Zweck vorgesehen. Einige ISPs verwenden stattdessen 10.0.0.0/8 auf der WAN-Seite. Das bedeutet dasselbe. Stimmen die beiden Adressen überein, haben Sie eine öffentliche IP-Adresse: Leiten Sie den Port weiter, und Sie sind fertig.

Benötige ich für einen Reverse Tunnel einen Domainnamen?

Für die hier beschriebene HTTPS-Konfiguration: ja. Ein Zertifikat wird für einen Hostnamen ausgestellt, und frp leitet Anfragen anhand des Host-Headers weiter. Daher müssen beide Seiten einen gemeinsamen Namen verwenden. Ein einfacher TCP-Proxy auf einem nummerierten Port funktioniert auch mit der nackten IP-Adresse des VPS und ganz ohne Domain. Dann haben Sie jedoch weder ein Zertifikat noch ein Routing anhand des Hostnamens. Ein öffentlicher Port kann dann genau einen Dienst bereitstellen.

Ist es sicher, frp auf einem öffentlichen VPS zu betreiben?

Es ist sicher, wenn nur der Steuerungsport erreichbar und dieser authentifiziert ist. Setzen Sie auth.token auf beiden Seiten auf einen zufälligen Wert und transport.tls.force = true auf dem Server. Setzen Sie anschließend proxyBindAddr = "127.0.0.1" so, dass nichts, was frp für einen Proxy öffnet, aus dem Internet erreichbar ist. Lassen Sie das Dashboard auf webServer.addr = "127.0.0.1" und greifen Sie über eine lokale SSH-Weiterleitung darauf zu. Aktualisieren Sie die Binärdatei, sobald neue Releases erscheinen, weil dieser Prozess auf Ihrer öffentlichen Adresse lauscht.

Warum kann niemand meinen weitergeleiteten ssh -R-Port erreichen?

sshd wird mit GatewayPorts no ausgeliefert. Daher bindet eine Remote-Weiterleitung nur an die Loopback-Schnittstelle des VPS. curl, das direkt auf dem VPS ausgeführt wird, funktioniert, während curl von einem anderen Ort aus mit einem Timeout endet. Die richtige Lösung besteht darin, die Weiterleitung auf Loopback zu belassen und nginx davor auf Port 443 zu setzen. Mit GatewayPorts yes veröffentlichen Sie einen einfachen Port ohne Zertifikat und ohne TLS. Das ist schlimmer als das ursprüngliche Problem.

Sollte ich frp oder ein Mesh-VPN wie Tailscale oder WireGuard verwenden?

Verwenden Sie ein Mesh-VPN, wenn nur Ihre eigenen Geräte Zugriff benötigen. Dann wird nichts veröffentlicht, und es gibt keinen öffentlichen Hostnamen, den jemand scannen kann. Verwenden Sie frp, wenn Sie eine öffentliche HTTPS-Adresse benötigen, die jeder Browser aufrufen kann, etwa für einen Webhook-Empfänger oder eine Seite, die Sie mit Personen teilen, die keinen VPN-Client installieren werden. Beide Lösungen können problemlos auf einem VPS nebeneinander betrieben werden, auf unterschiedlichen Ports und für unterschiedliche Aufgaben.

#frp#cgnat#nat#tunnel#reverse-proxy