5 Min. Lesezeit

Split-Horizon im Homelab: Intern direkt, extern durch den Tunnel

Der Cloudflare Tunnel läuft – aber warum wandert mein Traffic zuhause erst raus nach Frankfurt und wieder zurück? Split-Horizon DNS macht Schluss damit: intern direkt, extern durch den Tunnel, überall gültiges SSL. Mit AdGuard, NPM und einem Wildcard-Zertifikat.
Diagramm: Interner Zugriff direkt über AdGuard und NPM, externer Zugriff über den Cloudflare Tunnel – mit Wildcard-Zertifikat für *.s3nf-net.com

Wer meinen Beitrag zum Cloudflare Tunnel gelesen hat, weiß: Der Tunnel ist bei mir inzwischen Standard. Kein offener Port, automatisches HTTPS, Zugriff von überall. Läuft.

Aber eine Sache hat mich noch gestört. Wenn ich zuhause im LAN sitze und dienst.s3nf-net.com aufrufe, wandert die Anfrage erst raus ins Internet, durch Cloudflare, durch den Tunnel – und landet dann wieder zwei Meter neben mir auf dem Server. Das ist ungefähr so, als würde ich meinem Nachbarn einen Brief schreiben und ihn über ein Verteilzentrum in Frankfurt schicken. Kommt an, klar. Aber warum eigentlich?

Die Lösung heißt Split-Horizon DNS: Dieselbe Domain wird intern anders aufgelöst als extern. Zuhause geht der Traffic direkt an meinen Proxy, unterwegs weiterhin durch den Tunnel. Und das Beste: beides mit gültigem SSL-Zertifikat, ohne eine einzige Zertifikatswarnung.

Genau das bauen wir heute – mit AdGuard Home, dem Nginx Proxy Manager (NPM) und dem bestehenden Cloudflare Tunnel.

Das Ziel des Setups

Bevor wir loslegen, kurz das große Bild:

  • Intern: AdGuard leitet Anfragen direkt an den NPM weiter – kein Umweg übers Internet.
  • Extern: Der Cloudflare Tunnel bringt Anfragen sicher von außen ins Netz.
  • SSL: Alle Verbindungen – intern wie extern – sind gültig verschlüsselt, ohne Zertifikatsfehler.
  • Zentral: NPM kümmert sich automatisch um ein Wildcard-Zertifikat für *.s3nf-net.com.

Ein Zertifikat, zwei Wege, null Warnmeldungen. Klingt gut? Dann los.

Schritt 1: Port 80 freiräumen (AdGuard)

Erste Hürde: AdGuard läuft bei mir im Docker-Host-Netzwerk und belegt standardmäßig Port 80. Den brauchen wir aber zwingend für den NPM.

Also erstmal den AdGuard-Container stoppen:

docker stop <adguard-container-name>

Dann die AdGuardHome.yaml auf dem Host-System öffnen (z. B. mit nano), den Block http: suchen und den bind_port ändern:

http:
  bind_host: 0.0.0.0
  bind_port: 8080  # <-- Vorher 80

Speichern, Container wieder starten (docker start ...) – fertig.

Ergebnis: AdGuard ist ab sofort unter 10.1.0.253:8080 erreichbar, und Port 80 ist frei. Wichtig: Das betrifft nur das Webinterface von AdGuard. Die DNS-Auflösung auf Port 53 läuft davon völlig unbeeindruckt weiter.

Schritt 2: Nginx Proxy Manager vorbereiten

Jetzt darf der NPM die Standard-Webports übernehmen. In der docker-compose.yml des NPM müssen die Ports 80 und 443 an den Host durchgereicht werden:

ports:
  - '80:80'
  - '443:443'
  - '81:81' # Admin-Interface

Container starten bzw. updaten – und der NPM sitzt ab jetzt als zentraler Türsteher vor allen Diensten.

Schritt 3: Cloudflare API-Token erstellen

Jetzt wird's interessant. Der NPM soll sich selbstständig ein Wildcard-Zertifikat von Let's Encrypt holen. Das Problem: Für die klassische HTTP-Challenge müsste Port 80 ins Internet freigegeben werden – und genau das wollen wir ja nicht (deshalb haben wir überhaupt einen Tunnel).

Die Lösung: die DNS Challenge. Dabei weist der NPM den Domain-Besitz über einen DNS-Eintrag nach statt über einen erreichbaren Webserver. Dafür braucht er allerdings die Berechtigung, DNS-Einträge bei Cloudflare zu setzen – sprich: einen API-Token.

  1. Ins reguläre Cloudflare Dashboard einloggen (dash.cloudflare.com)
  2. Oben rechts aufs Profil → My ProfileAPI Tokens
  3. Create Token klicken und das Template Edit zone DNS wählen
  4. Unter Zone Resources: Include → Specific zone → deine Domain auswählen
  5. Token generieren und den angezeigten Code kopieren

Achtung: Der Token wird nur ein einziges Mal angezeigt. Also direkt kopieren und sicher ablegen – ich packe sowas in meinen Passwort-Manager.

Schritt 4: Wildcard-Zertifikat im NPM anlegen

Zurück im NPM (Weboberfläche auf Port 81):

  1. SSL CertificatesAdd SSL CertificateLet's Encrypt
  2. Bei Domain Names zuerst *.s3nf-net.com eintragen, Enter drücken, dann zusätzlich s3nf-net.com eintragen
  3. Use a DNS Challenge aktivieren
  4. Cloudflare als Provider wählen
  5. Im Textfeld den Platzhalter beim API-Token durch den kopierten Token aus Schritt 3 ersetzen
  6. Nutzungsbedingungen zustimmen und Save klicken

Jetzt kurz Kaffee holen – nach ca. 30–60 Sekunden liegt das Wildcard-Zertifikat im NPM. Ab sofort ist jede Subdomain automatisch abgedeckt, und der NPM kümmert sich selbstständig um die Verlängerung. Nie wieder manuell Zertifikate erneuern. Herrlich.

Schritt 5: Hosts im NPM einrichten

Jetzt bekommt jeder Dienst seinen eigenen Eintrag. Das Prinzip ist immer gleich – hier am Beispiel eines beliebigen Dienstes:

  1. HostsProxy HostsAdd Proxy Host
  2. Details:
    • Domain: dienst.s3nf-net.com
    • Forward Hostname / IP: die interne IP des Dienstes
    • Forward Port: der interne Port (z. B. 8080)
  3. SSL (wichtig!):
    • Im Dropdown das neue *.s3nf-net.com-Zertifikat auswählen
    • Force SSL, HTTP/2 Support und HSTS Enabled aktivieren
  4. Speichern

Das Ganze wiederholst du für jeden Dienst, der bei dir so läuft. Geht nach dem zweiten Mal in Fleisch und Blut über.

Schritt 6: Lokales DNS-Routing (AdGuard)

Jetzt kommt der eigentliche Split-Horizon-Trick. AdGuard soll die Domain intern nicht über das Internet auflösen, sondern direkt auf den NPM zeigen.

  1. AdGuard öffnen
  2. FilterDNS-Umschreibungen (DNS rewrites)
  3. Pro Dienst einen eigenen Eintrag hinzufügen – jeweils auf die IP des NPM (10.1.0.253). Zum Beispiel:
dienst1.s3nf-net.com   →  10.1.0.253
dienst2.s3nf-net.com   →  10.1.0.253
dienst3.s3nf-net.com   →  10.1.0.253

Ergebnis: Wer im heimischen WLAN ist, landet direkt und verschlüsselt beim NPM. Kein Umweg über Frankfurt. Und weil der NPM das gültige Wildcard-Zertifikat ausliefert, gibt es auch intern keine einzige Zertifikatswarnung.

Und jetzt der wichtigste Punkt an der ganzen Sache – der, an dem sich sonst still und heimlich die E-Mail verabschiedet:

⚠️ Kein Wildcard-Rewrite *.s3nf-net.com verwenden! Ein Wildcard biegt jeden Namen intern auf den NPM um – also auch mail. und alles, was zu deiner E-Mail gehört: MX, SPF, DKIM, DMARC, autodiscover, www. Fängt AdGuard diese Namen intern ab, kommt intern keine Mail mehr rein oder raus.

Deshalb die Regel: Jeder Dienst bekommt seine eigene, explizite Rewrite-Zeile. Alles, was du nicht auflistest, wird ganz normal nach außen aufgelöst – deine E-Mail bleibt öffentlich, immer aktuell und heil, ohne dass du irgendwas kopieren oder pflegen musst. Ein neuer Dienst heißt dann eben: eine neue Zeile in AdGuard. Kein großer Akt – und dafür schießt du dir nicht die Mail ab.

Schritt 7: Externes Routing (Cloudflare Zero Trust Tunnel)

Fehlt noch der Weg von außen – also alles, was passiert, wenn du unterwegs bist, ohne WLAN und ohne VPN.

  1. Cloudflare Zero Trust Dashboard öffnen
  2. NetworksTunnels → den bestehenden Tunnel bearbeiten
  3. Unter Public Hostname eine Route anlegen – am besten pro Dienst (z. B. dienst.s3nf-net.com). Auch hier gilt: Läuft E-Mail auf der Domain, verzichte auf die pauschale Wildcard-Route * – die würde sonst Mail-Namen wie mail. oder autodiscover. mit in den Tunnel ziehen.
  4. Service-Konfiguration:
    • Type: HTTPS (wichtig, nicht HTTP!)
    • URL: 10.1.0.253:443

Und jetzt kommt die Stolperfalle, über die vermutlich jeder einmal fällt:

  1. Additional application settings aufklappen → TLS:
    • No TLS Verify aktivieren
    • Bei Origin Server Name zwingend die Domain eintragen (z. B. s3nf-net.com oder dienst.s3nf-net.com)

Warum das so wichtig ist? Der NPM entscheidet anhand des angefragten Hostnamens (SNI), welches Zertifikat und welchen Proxy Host er ausliefert. Kommt die Anfrage vom Tunnel ohne passenden Servernamen an, lehnt der NPM die Verbindung schlicht ab – und du starrst auf einen 502 Bad Gateway und fragst dich, was du falsch gemacht hast. Der Origin Server Name löst genau dieses Problem.

Speichern – und das war's.

Fazit

Was am Ende dabei rauskommt:

  • Zuhause: Direkter, verschlüsselter Zugriff auf alle Dienste – ohne Umweg übers Internet, spürbar schneller – gerade für beispielsweise selfhost-Cloud-Speicher ein absoluter Game-Changer.
  • Unterwegs: Derselbe Hostname, derselbe Dienst, sicher durch den Cloudflare Tunnel.
  • Überall: Gültiges SSL, null Zertifikatswarnungen, und der NPM verlängert das Wildcard-Zertifikat vollautomatisch.

Das Schöne an dem Setup: Es ist die logische Weiterentwicklung des Tunnel-Setups aus meinem letzten Beitrag. Der Tunnel bleibt für den Zugriff von außen, AdGuard übernimmt intern – und der NPM sitzt als zentrale Stelle in der Mitte und hält beides zusammen.

Neuer Dienst? Proxy Host im NPM anlegen, fertig. Intern wie extern sofort erreichbar.

Einmal eingerichtet – läuft einfach.