Willkommen zum dritten Teil der Tutorialreihe zur Einrichtung des NAS als Private Cloud. Nachdem in Teil 1 unser virtueller privater Server vorbereitet und in Teil 2 das VPN-Netz aufgebaut wurde, möchte ich mich hier der Usability widmen.
Das Ziel vor Augen: Was wollen wir erreichen?
Ich möchte irgendwann einige Services, die aktuell über Cloud-Dienste konsumiert werden, auf der eigenen Hardware bereitstellen. Das heißt aber auch, dass manche Dienste von meiner Familie genutzt werden. Auf deren Geräten WireGuard zu installieren und konfigurieren und zu zeigen, wie man über das Kontrollzentrum der Geräte VPN aktiviert (sollte es mal aus sein, es könnte ja dauerhaft laufen), ist kein Problem. Aber dann für gewisse Dienste IPs, statt schönen DNS-Namen zu nutzen, ist deutlich schwieriger.
“Wie war nochmal die Adresse vom Foto-Dienst”? - “10.8.0.14:5725”
… das wird nichts. Da muss es etwas geben, wie “photos.vpn.meinedomain.de”.
Deshalb geht es erstmal darum, unsere internen Routen aufzuhübschen:
- Eine URL, die man sich merken kann (am besten ohne Ports)
- Keine HTTPS-Warnung, da diese im internen Netz eher nervig sind (für das Internet natürlich sehr sinnvoll!)
Setup für eigene private Routen
Eigene private Routen können wir nicht einfach in Caddy anlegen. Jede Route dort ist über eine öffentliche URL erreichbar. Deshalb können wir aktuell vpn.meinedomain.de ohne verbundenem VPN Client aus dem Internet heraus erreichen. Bei unserem Registrar haben wir den Wildcard A Record auf die öffentlich erreichbare IP unseres Servers gerichtet.
Das war auch wichtig, damit Caddy auf einfache Art und Weise ein TLS Zertifikat für diesen Route bekommen konnte. Für Routen bei unserer Domain, die aber nicht öffentlich erreichbar sein sollen, geht das nicht so einfach. Lass uns hierzu mal einen kurzen Blick hinter die Kulissen werfen, um zu verstehen, wieso wir nun einen etwas anderen Weg gehen müssen.
Wie bekommt man eigentlich ein TLS Zertifikat?
Es gibt verschiedene Arten, ein TLS Zertifikat zu bekommen. Let’s Encrypt beschreibt diese in der eigenen Doku recht ausführlich. Für uns wichtig sind dabei die zwei Wege.
Die gewöhnliche Methode - die auch Caddy für unsere vpn.* Subdomain nutzte, ist die HTTP-01 Challenge (oder einfach HTTP Challenge). Hierbei ruft unser ACME Client (Bei uns in Caddy integriert) einen Token bei der Zertifikatsstelle ab und legt diesen auf dem Webserver ab. Das heißt, Caddy fragt bei Let’s Encrypt:
“Hey, ich brauche ein Zertifikat für vpn.deinedomain.de”
Let’s Encrypt erwidert:
“Alles klar, hier ist ein Token. Beweise mir, dass die Seite hinter der URL dir gehört und lege den Token unter vpn.deinedomain.de/.well-known/acme-challenge/{TOKEN} ab.”
Caddy erhält den Token, legt diesen ab und lässt Let’s Encrypt dies prüfen. Findet Let’s Encrypt den Token, bekommt Caddy das Zertifikat, da der Besitz der Seite hinter der Domain bewiesen wurde.
Diese Art ist ziemlich einfach umzusetzen, aber hat für unser Vorhaben einen großen Nachteil. Die URL muss öffentlich erreichbar sein und auf einen öffentlich erreibaren Server zeigen, auf dem der Token abgelegt werden kann. Würde vpn.deinedomain.de auf eine IP im VPN Netz zeigen (10.8.0.1), dann würde Let’s Encrypt diesen Endpunkt nicht erreichen, den Token nicht finden und kein Zertifikat ausstellen.
Es gibt aber noch eine zweite Variante, die DNS-01 Challenge (oder DNS Challenge). Mit dieser Methode beweisen wir nicht, dass und der Webserver hinter der URL gehört, sondern, dass uns die Domain selbst gehört. Hierbei muss der Token also nicht auf dem Webserver landen, sondern als TXT Record bei der Domain und dieser würde von Let’s Encrypt geprüft - ohne auf die A Records zu achten. Die Verhandlung liefe also so ab:
Caddy: “Hey, ich brauche ein Zertifikat für vpn.deinedomain.de und will die DNS Challenge nutzen”
Let’s Encrypt: “Alles klar, hier ist ein Token-String, hinterlege diesen als TXT Record bei der Domain”
Caddy erhält den Token und braucht nun einen Weg, um diesen Eintrag tatsächlich bei unserem Registrar zu hinterlegen. Sobald der TXT Record vorhanden ist und Let’s Encrypt diesen gefunden hat, wird das Zertifikat ausgestellt. Dabei werden die A Records ignoriert, da gar nicht verfolgt werden muss, wohin diese zeigen. Caddy hat auch so bewiesen, dass wir die Hoheit über die Domain haben.
Bei diesem Weg gibt es zwei wesentliche Unterschiede zur HTTP Challenge. Erstens müssen wir Caddy tatsächlich ermächtigen, den Eintrag zu setzen (Zugangsdaten oder Token vom Domain Registrar), aber zweitens können wir damit Zertifikate für Domains holen, die keinen A Record Eintrag haben.
DNS Challenge mit Caddy vorbereiten
Caddy kann von Haus aus keine DNS Challenge durchführen, aber es gibt caddy-dns Plugins für diverse Domain Registrare (Cloudflare, route53, duckDNS, Digital Ocean, Hetzner und auch INWX). Besucht dafür einfach mal die Caddy Download Seite und sucht nach eurem Registrar. Für INWX finde ich das Plugin caddy-dns/inwx.

Achte dabei darauf, bei der “Platform” oben links nicht dein vorausgewähltes Betriebssystem zu nutzen, sondern “Linux amd64” oder “Linux arm64”, je nachdem, welche Architektur dein Server hat. Selektierst du dieses Paket, kannst du es per Download herunterladen.
Dieses Paket ist ein Binary von Caddy, mit diesem einen Plugin. Damit werden wir das vorhandene Binary ersetzen. Dann sollte erstmal alles so laufen, wie vorher, nur haben wir dann Zugriff auf das Modul, welches bei INWX (du hoffentlich bei deinem Registrar) eine DNS Challenge durchführen kann.
Es gibt auch andere Möglichkeiten, die DNS Challenge durchzuführen. Das Tool acme.sh ist ebenfalls beliebt, kann gut mit Caddy zusammenarbeiten, aber wie es nunmal so ist. Es führen oft mehrere Wege nach Rom oder zum Zertifikat. Wenn die Caddy Community mir die Möglichkeit bietet, dann will ich erstmal diesen Weg gehen, um meine Tools im Überblick zu behalten.
Also, tauschen wir das vorhandene Binary mit diesem aus. Im ersten Teil der Reihe haben wir caddy unter /usr/local/bin/ abgelegt. Lass uns einmal die aktuelle Version untersuchen, dann das Binary ersetzen und die Versionen vergleichen. Dafür starten wir damit, wieder per ssh auf den Server zu gehen:
| |
Damit siehst du die aktuelle Caddy Version, sowie alle installierten Module. Am Ende siehst du, wie viele Standard Module, wie viele Extra Module und wie viele unbekannte Module vorhanden sind.
Von dieser Version machst du ein Backup (optional, da wir es immer wieder herunterladen können) und löscht dann das eigentliche File:
| |
Dann per exit die SSH Session verlassen und die heruntergeladene Caddy Datei auf den Server kopieren (passe dabei deinen lokalen Pfad an):
| |
Achtung, wenn du SSH auf einen anderen Port gelegt hast, wird dieser (anders, als bei SSH) mit einem P als Großbuchstabe spezifiziert, scp -P 2222 ~/Downloads/....
Danach geht’s wieder per ssh auf den Server, wir legen die Datei in den korrekten Ordner (per scp hatten wir die Rechte nicht), machen sie ausführbar und vergleichen sie mit der ursprünglichen Version:
| |
Die Version ist die gleich, wie bei der vorigen Installation. Bei der Auflistung der DNS-Module sollte nun aber euer DNS Provider dabei sein. Für mich ist das dns.providers.inwx. Du solltest natürlich deinen DNS Provider sehen.
Damit können wir Caddy nutzen, um Zertifikate per DNS Challenge von unserem Provider zu bekommen.
dnsmasq einrichten
Bevor wir nun mit Caddy weitermachen (aktuell sollte noch alles so funktionieren, wie vorher), will ich dnsmasq einrichten. Dazu müssen wir das Paket installieren und ein wenig konfigurieren.
Linux Distributionen nutzen im Standard systemd-resolve mit der Konfigurationsdatei /etc/resolve.conf, um Namensauflösungen zu vollziehen. Nachdem wir also dnsmasq installiert haben, müssen wir einmal dnsmasq konfigurieren (dazu nutzen wir dessen config /etc/dnsmasq.conf) und dann in einer eigenen /etc/resolve.conf hinterlegen, dass für Namensauflösungen dnsmasq verwendet werden soll.
Legen wir los mit der Installation
| |
Es kann sein, dass bei der Installation ein Fehler auftritt, dass eine andere Applikation auf Port 53 horcht und deshalb der Listener nicht erstellt werden konnte. Das ist erstmal kein Problem. Damit konnte dnsmasq erstmal nur nicht gestartet werden. Da es vermutlich systemd-resolved ist, was auf den Port hört, sind die nächsten Schritte trotzdem identisch für alle (egal, ob mit oder ohne diesen Fehler). Denn wir wollen systemd-resolved sowieso beenden und vor allem deaktivieren, damit es sich nicht beim nächsten Reboot des Servers wieder aktiviert.
| |
Danach bennen wir die bestehende /etc/resolve.conf um. Du könntest sie auch löschen, aber was, wenn man die Konfiguration später zurückdrehen will? Danach erstellen wir eine eigene Version der Datei, welche als nameserver den localhost nutzt. Damit verweist unsere Version dieser Datei dann auf dnsmasq und so werden interne Anfragen zur Namensauflösung ebenfalls an dnsmasq weitergeleitet. Außerdem müssen wir dafür sorgen, dass alle die Datei lesen können. All das passiert mit den folgenden Commands:
| |
Jetzt editieren wir die Konfig-Datei für dnsmasq:
| |
Die Datei ist groß, deshalb gebe ich hier nur die Zeilen an, die geändert werden sollen - dabei muss das Hashsymbol entfernt werden, damit es kein Kommentar mehr ist:
| Alter Wert | Neuer Wert |
|---|---|
#domain-needed | domain-needed |
#bogus-priv | bogus-priv |
#no-resolve | no-resolve |
Unter #add other name servers here... #server=/localnet/192... | server=1.1.1.1 |
Unter #Add domains which you want to force... #address=/double-click.net... | address=/internal.{deinedomain.de}/10.8.0.1 |
#listen-adress= | listen-address=127.0.0.1,10.8.0.1 |
Letztendlich ist es egal, ob du die Zeilen so anpasst oder die neuen Werte einfach ganz ans Ende der Datei schreibst. Ich habe die Werte nur auch dort, wo sie in der Datei beschrieben werden. Mit dem folgenden Befehl kannst du nun prüfen, welche Zeilen in der Datei aktiviert sind, das Ergebnis siehst du (für dich wohl leicht angepasst) darunter.
| |
grep steht für “Global Regular Expression Print” und kann Ausgaben anhand von Regular Expression erzeugen. Regular Expression sind sozusagen Muster, die in einem Text erkannt werden können und die Passagen, die auf dieses Muster zutreffen, werden selektiert.
-vsteht für die Umkehrung der folgenden Muster. Also es soll alles ausgegeben werden, was nicht dem Muster entspricht-e "^#"steht für “Jede Zeile, die mit einem Hash-Symbol beginnt”-e "^$"steht für “Leere Zeile: ‘^’ heißt Zeilenanfang und ‘$’ heißt Zeilenende. Also Anfang direkt vor Ende, nicht dazwischen
Somit gibt diese Regular Expression aus, “Alle Zeilen, die nicht (-v) mit einem Hashsymbol beginnen und nicht (-v) leer sind, aus der Datei /etc/dnsmasq.config”. Das Ergebnis sollte so aussehen:
| |
Eine kurze Erklärung dazu. no-resolv weist dnsmasq an, nicht den Standard-System-Resolver zu verwenden (den wir bereits deaktiviert haben). Der server ist der DNS-Server, der verwendet werden soll, wenn der Name nicht lokal aufgelöst werden kann (Web-Adressen, wie google.de). Hier nutzen wir Cloudflare, dir steht frei, welchen du nutzt. listen-address gibt an, auf welchen Interfaces dnsmasq auf Anfragen hören soll, wir nutzen beide Interfaces. domain-needed sagt, dass nur volle Domainnamen an die DNS Server geleitet werden. Dinge, wie “mycomputer” werden über /etc/hosts aufgelöst. bogus-priv verhindert umgekehrte DNS Lookups (PTR Records) und schlussendlich das Kernstück: address gibt an, dass die Domain selbst (internal.deinedomain.de), sowie alle Subdomains (*.internal.deinedomain.de) an 10.8.0.1 geleitet werden. Dahinter hängt dann unser Caddy, der diese Anfragen entgegennimmt und anhand seiner Proxy Routen weiterleiten kann. Statt internal kannst du hier wieder ein Kürzel wählen, wie du es möchtest. Als kleinen Hinweis könntest du überlegen, ob du eine Route nimmst, die auch aus deinem Heimnetz (ohne VPN) sinnvoll wäre. Dann könntest du das Setup auch lokal machen, aber auf 192.168.X.Y auflösen und somit dieselben URLs im Heimnetz und VPN haben und dabei trotzdem immer lokal routen.
Jetzt müssen wir nochmal alles testen bzw. verifizieren und dann können wir dnsmasq (neu) starten und aktivieren, damit es nach Neustarts automatisch aktiviert wird.
| |
Sollte dein dnsmasq anfangs auf den Portfehler gelaufen sein, muss du in der zweiten Zeile nur start statt restart eingeben. Und damit läuft dein lokaler DNS Server!
Caddyfile vorbereiten
Nachdem dnsmasq jetzt läuft, müssen wir die Routen in Caddy auch entgegennehmen und sauber auf die Services routen. Also aktualisieren wir als nächstes das Caddyfile.
| |
Aufgrund des ersten Teils dieser Serie, sollte dein Caddyfile ungefähr so aussehen:
| |
Das müssen wir nun anpassen, um die DNS Challenge einzubauen und die gewünschten Routen aufzubauen. Diese können bei dir natürlich anders aussehen:
| |
Und damit sollte es geschafft sein. Datei speichern und schließen:
| |
Und abschließend Caddy noch einmal neustarten:
| |
Fertig, damit sollte Caddy Anfragen zu den entsprechenden internal... Subdomains an die korrekten Services leiten und die Routen sollten dank DNS Challenge per HTTPS abgesichert sein. Diese Domains haben aber keinen öffentlichen A Record, sondern werden vom lokalen DNS Server an Caddy geleitet.
Als letztes müssen wir also den DNS Server bei unseren VPN Clients hinterlegen.
DNS für VPN Clients hinterlegen
Jetzt hast du zwei Optionen, deine bestehenden WireGuard Clients zu aktualisieren. Entweder du editierst die wg0.conf überall manuell oder du wirfst die Clients nochmal aus WireGuard-UI heraus, editierst die Global Config, wo du bei den DNS Servern nun die VPN IP eintragen kannst und fügst diese Konfig dann nochmal bei deinen Clients hinzu (dabei musst du auch auf den Clients dann die alte Konfig löschen).
Solltest du in Teil 2 dein NAS mit einer WireGuard Konfig versehen haben, müsstest du das NAS eigentlich nicht ändern. Du wirst ja vermutlich nicht vom NAS aus (also per SSH oder aus dem DSM heraus) auf die lokalen Routen zugreifen, die wir eben erstellt haben. Bei denen geht es ja eher darum, dass du diese Domains auf deinem Rechner, Smartphone oder Tablet nutzen kannst.
Ich denke, mit diesen zwei Wegen kannst du die Anpassung der Clients selber durchführen und sobald einer, deiner Clients eine neue Konfig mit dem entsprechenden DNS Server hat, heißt es, deine Route mal zu testen. Öffne mal https://dns.internal.deinedomain.de und du solltest mit gültigem Zertifikat auf das DSM deines NAS geleitet werden. Mit solchen Domains lässt sich viel mehr anfangen und sie haben die Sicherheit, nur mit verbundenem VPN Client erreichbar zu sein.
Als optionalen nächsten Schritt könnten nun die Routen, die ins offene Internet gehen, noch mit Diensten, wie Authentik abgesichert werden. Wenn du das nicht tust, stell zumindest sicher, dass alle Dienste mit einem starken Passwort versehen sind, es keine bekannten Sicherheitslücken gibt und am besten auch Multi-Faktor-Authentication unterstützen.
Im nächsten Beitrag widme ich mich Pangolin, was eine Art All-In-One-Lösung für unser Setup ist. Oder vielleicht eher eine Selfhosted-Lösung für Cloudflare Tunnels. Bis dahin erstmal viel Spaß mit deinem Setup!
