Mein Vater hat einen neuen Internetanschluss, der nun auch keine eigene IPv4-Adresse enthält. Stattdessen ist er hinter einem NAT und bekommt nur eine private IPv4-Adresse auf der Fritz-Box zugewiesen. Bisher hatte er seine eigene Nextcloud auf reinem RaspberryPi laufen, die über DynDNS auch online erreichbar war. Da das nun nicht mehr möglich ist, sollte eine Lösung her, mit der der Webserver für die Nextcloud trotzdem über IPv4 und zusätzlich über IPv6 erreichbar ist.
IPv4-Tunnel über Hetzner-Server
Als DynDNS-Service nutze ich dynv6, welches so konfiguriert werden kann, dass man nur die IPv6-Adresse dynamisch ändert und die IPv4 dann immer gleich bleibt. Dort habe ich dann für IPv4 die IP unseres Hetzner-Servers hinterlegt. DNS-Auflösungen der Domain zeigen im IPv4-Teil also auf unseren Server. Somit kommen auch HTTP-Anfragen und SSH-Verbindungen dort an.
Um sie auf die unerreichbare private IPv4-Adresse zu lenken, gibt es SSH-Tunnel. Diese können zwischen zwei Servern aufgebaut werden und tunneln dann einen oder mehrere TCP-Ports. Ich nutze dafür AutoSSH, damit die Verbindung vom Pi zum Server automatisch aufgebaut wird. Der SSH-Port ist dort öffentlich erreichbar und somit direkt ansprechbar. Beim HTTP-Port ist es etwas schwieriger, denn auf unserem Hetzner-Server ist dieser schon mit einem Nginx belegt. Deshalb gibt es dort einen neuen Eintrag:
upstream torte_autossh_server { # Der HTTPS-Tunnel wird so aufgebaut: -R 55443:127.0.0.1:443 server localhost:55443 fail_timeout=0; } # Umleitern der HTTP-Anfragen auf den HTTPS-Port server { listen 80; listen [::]:80; server_name papa.georf.de; rewrite ^(.*) https://$host$1 permanent; } server { listen 443 ssl; listen [::]:443 ssl; server_name papa.georf.de; ssl_certificate /etc/ssl/letsencrypt/papa.georf.de.pem; ssl_certificate_key /etc/ssl/letsencrypt/papa.georf.de.key; # Letsencrypt selber aushandeln location /.well-known/acme-challenge/ { auth_basic off; alias /var/lib/dehydrated/acme-challenges/; } # Anfragen als Proxy an den SSH-Tunnel weiterleiten location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Proto https; proxy_pass https://torte_autossh_server; } }
Um das auf diese Art und Weise zu machen, muss der Nginx-Server die Verbindung lesen können und braucht das entsprechende Zertifikat. Ich habe mich dazu entschieden, dass der Hetzern-Server dies mit Letsencrypt aushandelt und dann regelmäßig das fertige Zertifikat auf den Pi kopiert. Beide Server verwenden also das gleiche Zertifikat.
Sind alle Einstellungen korrekt, reicht das schon, um alle IPv4-HTTP-Anfragen vom Online-Server über den SSH-Tunnel auf den Pi-Webserver umzuleiten. Dort muss natürlich der entsprechende Web-Dienst laufen.
IPv6-Adresse direkt nutzen
Bei der IPv6-Adresse könnte man diesen Tunnel genauso nutzen. Allerdings hätte man dann den Nachteil, dass alle Daten über den Hetzner-Server ausgetauscht werden. Da ich von folgenden zwei Punkten ausgehe, möchte ich die IPv6-Adresse des RaspberryPis direkt nutzen:
- Die Verfügbarkeit von IPv6 wird immer weiter ansteigen und irgendwann die Überhand gewinnen.
- Mein Vater wird die meisten Daten zu Hause in der Nextcloud speichern. Für ihr wäre der Umweg über den Online-Server eine doppelte Belastung des Internetverkehrs. Auch wenn die IPv6-Adresse eine öffentliche ist, würde beim Routen die Fritz-Box merken, dass sie sich im eigenen Netzwerk befinden und entsprechend direkt an den Pi leiten.
Da dies der erste Server war, den ich mit einer dynamischen Adresse hinter einer Fritz-Box direkt im Internet verfügbar machen wollte, hatte ich mehrere Probleme zu lösen:
DynDNS mit IPv6
Wir oben erwähnt, nutze ich dynv6 als DynDNS-Anbieter. Als Skript nutze ich ddclient
mit folgender Konfiguration:
ssl=yes protocol=dyndns2 usev6=if, if=eth0 server=dynv6.com login=none password=long_and_secure mydomain.dynv6.net
Der ddclient
aus den Debian-Paketquellen ist aktuell genug. Allerdings musste ich die Backslashs aus der Standardkonfiguration entfernen. Mit der Option usev6
wird nur die öffentliche IPv6-Adresse übertragen.
Interface-Identifiers festzurren
Das installierte Raspbian nutzte die Privacy-Extensions, um die IPv6-Adressen ständig zu ändern. Dies führt allerdings dazu, dass man keine Firewall-Regeln für diese IP in der Fritzbox festlegen kann. Raspbian nutzt für die Adressvergabe den Dienst dhcpcd. Dort muss man in der Konfiguration den Wert von slaac private
auf slaac hwaddr
ändern. Nun sieht der IID-Wert der IPv6-Adresse (die hinteren 64bit) bei der lokalen IP (startet mit fe80) und der öffentlich IP (startet vermutlich mit 2) auch nach einem Neustart gleich aus. Diese IP sollte nun mit ddclient an den DynDNS-Dienst übertragen werden.
IPv6-Port in der Fritzbox freigeben
Im Gegensatz zur IPv4-Variante ändern sich möglicherweise die IP-Adresse des Pis im Netzwerk, denn nur die IID-Bereich der Adresse wurde oben festgelegt. Der Netzteil wird vom Provider festgelegt und kann sich entsprechend regelmäßig ändern. Die Änderung wird mittels DynDNS an die HTTP-Clients übertragen. Allerdings müssen wir auch der Fritzbox mitteilen, welchen Port wir freigeben wollen. Dafür gibt man in der Fritzbox nur den IID-Teil der IPv6-Adresse an, denn den Netzteil kennt die Fritzbox ja. Bekommt sie vom Provider einen einen neues Netz zugewiesen, wird die Firewall-Regel entsprechend automatisch auf die neue IP angepasst.
Ich gebe in der Fritzbox also den HTTP, HTTPS und geänderten SSH-Port für IPv6 des RaspberryPis frei. Anfragen über IPv6 kommen also direkt in der Fritzbox an und gehen nicht den Umweg des Hetzner-Servers.