FRP Reverse Tunnel: Heimdienste ohne Portfreigabe erreichbar machen
Du möchtest dein Home Assistant, deine Nextcloud oder ein anderes Projekt aus dem Heimnetz von unterwegs erreichen, aber dein Router lässt dich nicht? Dann ist ein FRP Reverse Tunnel eine richtig charmante Lösung. Statt Ports zu öffnen, baut ein kleiner Client bei dir zu Hause eine ausgehende Verbindung zu einem VPS auf. Über diesen Tunnel landen die Anfragen anschließend wieder in deinem Netz, ganz ohne Portfreigabe, DynDNS oder öffentliche IPv4-Adresse.
Ich betreibe genau dieses Setup produktiv: Ein Bekannter von mir sitzt hinter einem Anschluss ohne echte IPv4, sein Home Assistant ist trotzdem sauber per HTTPS erreichbar. Davor steht Traefik auf meinem VPS und kümmert sich um Zertifikate, Header und Geo-Blocking. In diesem Beitrag zeige ich dir, warum das funktioniert, wann es sinnvoll ist und wie du es mit Docker nachbaust. Alle Adressen, Domains und Tokens sind natürlich anonymisiert.
🤔 Das Problem: Kein offener Port, keine echte IPv4
Früher war die Sache einfach: Router-Oberfläche auf, Port 443 auf den Server weiterleiten, DynDNS eintragen, fertig. Das klappt heute immer seltener. Viele Kabel- und Glasfaseranbieter schalten neue Anschlüsse als DS-Lite. Du bekommst dann eine vollwertige IPv6, aber deine IPv4 teilst du dir per Carrier-Grade-NAT mit einem Haufen Nachbarn. Eine IPv4-Portfreigabe ist damit schlicht unmöglich, weil der Router die Verbindung nie zu sehen bekommt.
Ähnlich sieht es bei LTE- und 5G-Routern, vielen Starlink-Tarifen oder Gastzugängen aus. Und selbst wenn Portfreigaben technisch gingen: Nicht jeder möchte bei Freunden oder der Familie im Router herumschrauben oder einen Dienst direkt ins Internet hängen.
Natürlich könntest du bei DS-Lite einfach über IPv6 freigeben. Dann stehst du aber vor dem nächsten Problem: Im Hotel-WLAN, im Firmennetz oder bei manchem Mobilfunktarif gibt es nur IPv4. Dein Dienst wäre also genau dann nicht erreichbar, wenn du ihn brauchst. Ein Reverse Tunnel dreht die Richtung einfach um.
🚇 So funktioniert ein FRP Reverse Tunnel
frp (Fast Reverse Proxy) ist ein schlankes Open-Source-Projekt in Go und besteht aus zwei Teilen: frps ist der Server und läuft auf einem VPS mit öffentlicher Adresse. frpc ist der Client und läuft irgendwo im Heimnetz, zum Beispiel auf einem Raspberry Pi, einem NAS oder einer kleinen VM.
Der Trick: frpc verbindet sich von innen nach außen zum VPS. Ausgehende Verbindungen lässt praktisch jeder Router durch, egal ob DS-Lite, CGNAT oder LTE. Über diese stehende Verbindung meldet frpc an, welche Dienste es bereitstellt. frps öffnet daraufhin einen Port auf dem VPS. Alles, was dort ankommt, wird durch den Tunnel nach Hause geschickt. Davor setze ich Traefik, damit nur sauberes HTTPS den Weg ins Heimnetz findet.

Ein paar Punkte, die mir an diesem Aufbau besonders gefallen:
- Keine Portfreigabe zu Hause: Im Router bleibt alles zu. Es gibt weder DynDNS noch eine Weiterleitung.
- Kein VPN ins Heimnetz: Der VPS sieht nur den einen Dienst, den du freigibst. Ein kompromittierter VPS hat keine Route in dein restliches LAN.
- Volle Kontrolle am Eingang: Zertifikate, Security-Header, Geo-Blocking, CrowdSec oder Rate-Limits laufen zentral in Traefik auf dem VPS.
- Funktioniert mit IPv4 und IPv6: Der VPS hat beides. Deine Besucher kommen also immer an, auch wenn dein Heimanschluss nur IPv6 kann.
- WebSockets inklusive: frp leitet im TCP-Modus einfach die Bytes durch. Live-Updates in Home Assistant funktionieren ohne Zusatzaufwand.
⚖️ Und warum nicht einfach VPN oder Cloudflare Tunnel?
Berechtigte Frage! Für den Zugriff nur durch dich selbst ist ein VPN wie WireGuard oder Tailscale oft die bessere Wahl. Dann muss aber jedes Gerät, das zugreifen soll, den VPN-Client installiert haben. Für die Companion-App der ganzen Familie oder einen Dienst, den auch andere nutzen sollen, ist das schnell unpraktisch.
Cloudflare Tunnel funktioniert vom Prinzip her ähnlich und ist bequem. Dort endet TLS allerdings bei Cloudflare. Der Anbieter sieht deinen Verkehr also im Klartext, und du bist an seine Regeln gebunden. Mit frp und einem eigenen VPS bleibt alles bei dir. Der Preis dafür ist ein kleiner VPS für ein paar Euro im Monat und etwas Einrichtungsarbeit, die wir jetzt gemeinsam erledigen.
🧩 Voraussetzungen
Bevor es losgeht, brauchst du natürlich eine funktionierende Docker-Umgebung, und zwar an beiden Enden: auf dem VPS und auf einem Gerät im Heimnetz.
Wenn du Docker noch nicht installiert hast, findest du hier eine Schritt-für-Schritt-Anleitung, wie du das auf Ubuntu mit einem Script erledigst:
Außerdem gehe ich davon aus, dass auf dem VPS bereits Traefik mit einem Zertifikats-Resolver läuft und eine Domain auf die IP des VPS zeigt. In meinen Beispielen ist das ha.example.de und der VPS hat die IP 203.0.113.10. Sobald Docker läuft, kann es direkt weitergehen.
🖥️ Schritt 1: Den FRP-Server auf dem VPS einrichten
Wir starten auf dem VPS. Als Erstes brauchst du ein langes, zufälliges Token. Damit weisen sich Client und Server gegenseitig aus. Bitte nimm hier nicht geheim123, denn wer das Token kennt, kann eigene Tunnel auf deinem Server anmelden!
openssl rand -hex 32
Verzeichnis und frps.toml anlegen
mkdir -p /home/docker-container/frps cd /home/docker-container/frps nano frps.toml
In die frps.toml kommt folgender Inhalt. Mit allowPorts legst du fest, welche Ports ein Client überhaupt belegen darf. Das ist eine kleine, aber feine zusätzliche Bremse.
# Port, auf dem frps auf eingehende Tunnel von frpc wartet
bindPort = 7000
# Gemeinsames Geheimnis zwischen Server und Client
auth.method = "token"
auth.token = "HIER_DEIN_LANGES_ZUFAELLIGES_TOKEN"
# Clients ohne TLS gar nicht erst annehmen
transport.tls.force = true
# Clients dürfen nur diesen Remote-Port belegen
allowPorts = [
{ single = 8123 }
]
Die Verbindung zwischen frpc und frps ist seit Version 0.50 standardmäßig per TLS verschlüsselt. Mit transport.tls.force lehnt der Server Clients ab, die das abgeschaltet haben.
Die docker-compose.yaml für frps
Jetzt kommt der entscheidende Kniff: Veröffentlicht wird nur der Tunnel-Port 7000. Port 8123, über den der Dienst aus dem Tunnel herauskommt, bleibt im Docker-Netzwerk. Damit Traefik ihn erreicht, hängt frps zusätzlich im Netzwerk deines Traefik-Containers. Der Name traefik_proxy ist ein Beispiel, trag dort den Namen deines vorhandenen Netzwerks ein.
services:
frps:
image: fatedier/frps:v0.71.1
container_name: frps
restart: unless-stopped
command: -c /etc/frp/frps.toml
ports:
# Nur der Tunnel-Port wird veröffentlicht. Port 8123 bleibt intern!
- "7000:7000"
volumes:
- ./frps.toml:/etc/frp/frps.toml:ro
networks:
frps_net:
ipv4_address: 172.27.84.10
traefik_proxy: {}
networks:
frps_net:
name: frps.dockernetwork.local
driver: bridge
ipam:
config:
- subnet: 172.27.84.0/24
gateway: 172.27.84.1
ip_range: 172.27.84.128/25
traefik_proxy:
# Name des Docker-Netzwerks, in dem dein Traefik hängt
external: true
Starten und kurz ins Log schauen. Dort sollte frps started successfully auftauchen:
docker compose up -d docker logs frps
Kleiner Hinweis aus der Praxis: Betreibst du frps stattdessen mit network_mode: host, lauscht der Remote-Port 8123 standardmäßig auf allen Interfaces. Dann ergänze in der frps.toml unbedingt proxyBindAddr = "127.0.0.1". Sonst hängt dein Home Assistant unverschlüsselt und ohne Traefik direkt am Internet, und nur noch die Firewall steht dazwischen.
Firewall: Nur Port 7000 freigeben
Auf dem VPS muss lediglich der Tunnel-Port erreichbar sein. Mit UFW sieht das so aus:
sudo ufw allow 7000/tcp comment 'FRP Tunnel' sudo ufw status | grep 7000
Wie du UFW grundsätzlich sauber einrichtest und warum Docker-Ports dabei gerne mal an der Firewall vorbeilaufen, habe ich hier ausführlich beschrieben:
🔀 Schritt 2: Traefik als Türsteher
Traefik nimmt die HTTPS-Anfragen für ha.example.de entgegen, terminiert TLS und reicht sie an frps weiter. Ich nutze dafür eine Datei im Dynamic-Config-Ordner von Traefik, etwa dynamic/ha-tunnel.yml. Als Zertifikat kommt bei mir ein Wildcard-Zertifikat per DNS-Challenge zum Einsatz, so teilen sich alle Subdomains ein Zertifikat.
Router und Service für den Tunnel
http:
routers:
ha-tunnel:
rule: "Host(`ha.example.de`)"
entryPoints:
- websecure
middlewares:
- ha-tunnel-headers
service: ha-tunnel
tls:
certResolver: cloudflare
domains:
- main: "example.de"
sans:
- "*.example.de"
middlewares:
ha-tunnel-headers:
headers:
stsSeconds: 31536000
customResponseHeaders:
X-Frame-Options: "SAMEORIGIN"
services:
ha-tunnel:
loadBalancer:
passHostHeader: true
servers:
# Containername von frps + Remote-Port aus der frpc.toml
- url: "http://frps:8123"
Hier kannst du nach Herzenslust weitere Middlewares einhängen. Bei meinem produktiven Setup filtert zum Beispiel ein Geo-Blocking-Plugin alles außerhalb von Deutschland heraus, und CrowdSec sperrt auffällige IPs. Das passiert alles auf dem VPS, bevor auch nur ein Paket durch den Tunnel geht.
🏠 Schritt 3: Der FRP-Client im Heimnetz
Weiter geht es zu Hause. Der Client braucht nichts weiter als Docker und eine Netzwerkverbindung zu Home Assistant. Ob er auf einem Pi, einer VM oder dem NAS läuft, ist egal.
Verzeichnis und frpc.toml anlegen
mkdir -p /opt/docker/frpc cd /opt/docker/frpc nano frpc.toml
# Öffentliche Adresse deines VPS serverAddr = "203.0.113.10" serverPort = 7000 # Exakt dasselbe Token wie auf dem Server auth.method = "token" auth.token = "HIER_DEIN_LANGES_ZUFAELLIGES_TOKEN" # Beim ersten Start nicht aufgeben, wenn der VPS gerade nicht erreichbar ist loginFailExit = false [[proxies]] name = "homeassistant" type = "tcp" # Home Assistant im Heimnetz localIP = "192.168.178.50" localPort = 8123 # Unter diesem Port taucht der Dienst auf dem VPS auf (nur intern) remotePort = 8123
localIP und localPort zeigen auf deinen Dienst im Heimnetz. remotePort ist der Port, unter dem er auf dem VPS erscheint, und muss zu allowPorts und zur Traefik-URL passen.
Die docker-compose.yaml für frpc
services:
frpc:
image: fatedier/frpc:v0.71.1
container_name: frpc
restart: unless-stopped
command: -c /etc/frp/frpc.toml
volumes:
- ./frpc.toml:/etc/frp/frpc.toml:ro
networks:
frpc_net:
ipv4_address: 172.23.141.10
networks:
frpc_net:
name: frpc.dockernetwork.local
driver: bridge
ipam:
config:
- subnet: 172.23.141.0/24
gateway: 172.23.141.1
ip_range: 172.23.141.128/25
Ein Port-Mapping brauchst du beim Client nicht. Er baut ausschließlich ausgehende Verbindungen auf. Genau deshalb ist ihm DS-Lite völlig egal.
docker compose up -d docker logs -f frpc
⚙️ Schritt 4: Home Assistant den Proxy erlauben
Wenn du jetzt https://ha.example.de aufrufst, wirst du bei Home Assistant vermutlich ein 400: Bad Request sehen. Das ist kein Fehler im Tunnel, sondern Absicht: Home Assistant akzeptiert Anfragen über einen Reverse Proxy nur, wenn du ihm das ausdrücklich erlaubst.
Für Home Assistant kommt die Anfrage von der IP des Rechners, auf dem frpc läuft. Diese IP trägst du in der configuration.yaml als vertrauenswürdigen Proxy ein:
http:
use_x_forwarded_for: true
trusted_proxies:
# IP des Rechners im Heimnetz, auf dem frpc läuft
- 192.168.178.60
Traefik setzt den Header X-Forwarded-For mit der echten Besucher-IP, und frp reicht ihn im TCP-Modus unverändert durch. So siehst du in Home Assistant die richtigen Adressen, und die eingebaute IP-Sperre bei falschen Logins trifft den Angreifer und nicht deinen eigenen Proxy. Danach Home Assistant einmal neu starten, und die Anmeldeseite sollte erscheinen.
🔍 Prüfen, ob der Tunnel steht
Im Log des Clients sieht ein erfolgreicher Verbindungsaufbau so aus:
[I] [client/service.go:335] try to connect to server... [I] [client/service.go:355] login to server success, get run id [3eaf4db10c2cbb33] [I] [proxy/proxy_manager.go:183] proxy added: [homeassistant] [I] [client/control.go:174] [homeassistant] start proxy success
Spannend finde ich das Verhalten bei der nächtlichen Zwangstrennung. So sieht das im Server-Log bei meinem produktiven Setup aus: Der Anschluss bekommt um kurz nach drei Uhr eine neue IP, frpc meldet sich sofort wieder an, und frps baut den Proxy neu auf. Zwischen Anmeldung und fertigem Proxy liegen gerade mal 20 Millisekunden, und eingreifen musste niemand.
03:23:20.486 [I] client login info: ip [198.51.100.23:62152] version [0.71.1] os [linux] arch [amd64] 03:23:20.486 [I] replaced by client [3eaf4db10c2cbb33] (control ID 6) 03:23:20.487 [I] [homeassistant] proxy closing 03:23:20.488 [I] client exit success 03:23:20.506 [I] [homeassistant] tcp proxy listen port [8123] 03:23:20.506 [I] new proxy [homeassistant] type [tcp] success
Zum Schluss prüfst du noch, dass auf dem VPS wirklich nur der Tunnel-Port veröffentlicht ist und die Seite von außen per HTTPS antwortet:
# Auf dem VPS: Tunnel-Port offen, 8123 nicht nach außen veröffentlicht?
docker ps --filter name=frps --format "{{.Names}}: {{.Ports}}"
# Von außen (z. B. vom Smartphone-Hotspot):
curl -sI https://ha.example.de | head -n 1
Bei docker ps sollte nur 0.0.0.0:7000->7000/tcp auftauchen, der Port 8123 dagegen nicht. Beim curl erwartest du ein HTTP/2 200 oder eine Weiterleitung von Home Assistant.
🛡️ Sicherheit: Worauf du achten solltest
Ein Tunnel macht einen Dienst öffentlich erreichbar, genauso wie eine Portfreigabe. Er versteckt ihn nicht. Deshalb gehören ein paar Dinge einfach dazu:
- Token geheim halten: Lang, zufällig und nur in den beiden TOML-Dateien. Wer es hat, kann eigene Tunnel anmelden.
allowPortsbegrenzt den Schaden zusätzlich. - Remote-Port nie direkt veröffentlichen: Nur 7000 ist offen. Der Dienst selbst ist ausschließlich über Traefik mit TLS erreichbar.
- Dienst selbst absichern: In Home Assistant gehört Multi-Faktor-Authentifizierung aktiviert. Der Tunnel ersetzt kein gutes Passwort.
- Versionen aktuell halten: frpc und frps sollten möglichst dieselbe Version nutzen. Aktualisiere am besten beide Seiten zusammen.
- Denk an den Flaschenhals: Der gesamte Verkehr läuft über den VPS. Für Home Assistant ist das kein Thema, für große Downloads oder Videostreams zählen Bandbreite und Traffic-Kontingent des VPS.
✅ Fazit
Ein FRP Reverse Tunnel ist für mich die pragmatische Antwort auf einen Internetanschluss, der keine Portfreigaben mehr zulässt. Ob DS-Lite, CGNAT oder ein Router, an dem du nichts ändern darfst: Solange der Client nach draußen telefonieren kann, ist dein Dienst erreichbar. Und das Beste daran ist, dass du am Eingang mit Traefik die volle Kontrolle behältst, ohne gleich das ganze Heimnetz per VPN an den VPS zu hängen.
Bei meinem Bekannten läuft das Setup seit Wochen völlig unauffällig. Die einzige Spur der täglichen Zwangstrennung sind ein paar Zeilen im Log. Genau so mag ich Infrastruktur: langweilig und zuverlässig!
👥 Techniverse Community
Lust auf Austausch rund um Docker, Selfhosting und andere smarte IT-Lösungen?
In der Techniverse Community triffst du Gleichgesinnte, kannst Fragen stellen oder einfach nerdigen Talk genießen. 🚀
👉 Jetzt der Gruppe auf Matrix beitreten
~ Direkte Raumadresse: #community:techniverse.net
👉 Für lockere Gespräche abseits der Kernthemen komm in den Talkraum
~ Direkte Raumadresse: #talk:techniverse.net
Ich freue mich, wenn du dabei bist!




