Raspberry Pi mit Domain hinter Unitymedia Router (IPv6)

Das war mal wieder komplizierter als gedacht. So richtet man sein Netzwerk so ein, dass man einen Raspberry Pi hinter einem Unitymedia-Router via Dyndns erreichen kann.

Setup:
* Internet von Unitymedia via der Connectbox
* Eine Dyndns-Subdomain (bei mir von inwx)
* Ein via WLAN verbundener Raspberry Pi mit Debian Stretch (9.3)

Probleme, die es zu lösen gilt:
* Die Verbindung muss über IPv6 ablaufen, da Unitymedia keine allein genutzten IPv4 Adressen vergibt
* Der Raspberry Pi soll ein autoreconnect zum WLAN machen
* Die Connectbox muss die Pakete weiterleiten
* Der Raspberry Pi darf keine IPv6 Privacy Extensions verwenden (zufällige IP suffixe), weil sonst nach einer Woche die Filterregeln der Connectbox ihre Gültigkeit verlieren.
* Let’s Encrypt-Zertifikate für eine abhörsichere Verbindung
* Zugriffsbeschränkung
* Mein Smartphone sollte die Verbindung aufbauen können

Ich gehe mal davon aus, dass der Raspberry-Pi soweit funktioniert. Alle $ Befehle beziehen sich auf die Linux-Shell des Raspberry Pi. Das $ Zeichen darf nicht mit eingegeben werden. Wie man Konfigurationsdateien bearbeitet, erklärt Paul McWhorter hier.

Mein Raspberry läuft mit Debian Stretch (9.3). Die Debian-Version lässt sich über
cat /etc/debian_version
herausfinden.

Wlan

Der offizielle Guide zeigt, wie man sich mit einem WLAN verbindet.

Um bei WLAN-Ausfall automatisch wiederverbunden zu werden, erstellt man eine neue Konfigurationsdatei ($ sudo nano /etc/network/interfaces.d/99-wlan) mit folgendem Inhalt:

allow-hotplug wlan0
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp

IPv6 Adresse

Im Gegensatz zu den bekannten und quasi aufgebrauchten IPv4-Adressen (z.B. 221.14.142.35) gibt es von den IPv6-Adressen einfach unglaublich viele (z.B. 2a02:8071:1ec:d900:ba27:ebff:fef3:2eaf). So viele, dass Netzwerken ganze Teilbereiche zugewiesen werden, aus denen sich dann die Teilnehmer (z.B. der Raspberry) eine raussuchen können. Am Ende setzt sich so eine Adresse folgendermaßen zusammen:

  2a02:8071:1ec:d900:ba27:ebff:fef3:2eaf
  <  prefix        > < interface       >
                       identifier

Das Präfix bekommt die Connectbox von Unitymedia zugewiesen und der Interface-Identifier enthält die MAC-Adresse des Teilnehmers (plus ff:fe in der Mitte und einen Bitkipper im achten Bit). Da das nicht sehr Datenschutzfreundlich ist, gibt es die Privacy-Extensions, die den Interface-Indentifier zufällig machen und alle x Stunden wechseln. Und weil Unitymedia selbst ein bisschen Datenschutz machen will, wechselt auch das Präfix alle paar Tage. Das genaue Ablaufdatum sieht man auf der Connectbox (192.168.0.1) unter Admin -> Information -> IPv6 lease expire.

Der Raspberry (bzw Raspian) ist jetzt standardmäßig so eingestellt, dass er zwar nicht die Privacy-Extensions verwendet, aber sich seinen Interface-Identifier zumindest halb-zufällig erstellt, nämlich aus einer Kombination des Präfixes, der Mac-Adresse und der Uhrzeit. Das bedeutet, dass sich der Interface-Identifier jedes mal ändert, wenn sich das Präfix ändert. Da wir gleich Portfilter in der Connectbox einrichten wollen, muss zumindest der Interface-Identifier konstant bleiben. Die Connectbox ist schlau genug, den Präfix der IPv6-Adressen im Portfilter automatisch zu aktualisieren.

Dazu editieren wir $ sudo nano /etc/dhcpcd.conf, suchen die Zeile

# Generate Stable Private IPv6 Addresses instead of hardware based ones
slaac private

und kommentieren die slaac private Einstellung aus:

# Generate Stable Private IPv6 Addresses instead of hardware based ones
#slaac private

Nach einem Neustart sollte die IPv6-Adresse ($ ip -6 addr show dev wlan0) die MAC-Adresse des WLAN-Adapters ($ ip link show dev wlan0) enthalten (mit der oben beschriebenen Verwurstelung). Ersterer Befehl zeigt zwei Adressen an. Diejenige, die mit fe80: startet ist die lokale Adresse, wie früher 192.168.x.x.

Portfreigabe

In der Oberfläche der Connectbox (192.168.0.1) unter Erweiterte Einstellungen -> Sicherheit -> Ip und Port Filter -> IPv6 Port Filter erstellen wir eine neue eingehende Port-Regel. Wer schon früher Portregeln für IPv4 erstellt hat, muss aufpassen. Die Quellportangabe hat hier eine andere Bedeutung.

[x] Aktiviert    [ ] Deaktiviert
Traffic policy: [x] Ja    [ ] Nein
Protokoll: TCP
Quell IP-Adresse: Alle
Ziel IP-Adresse: <Die aktuelle Adresse des Raspberry Pi.
                  Diejenige, die NICHT mit fe80 anfängt.>
Quell Port Range: Beliebig !!!
Ziel Port Range: Manuell. Start: 80. Ende: 80.

Dann ein Klick auf „Regel übernehmen“ und ganz wichtig danach auf „Änderungen übernehmen“.

Dann noch eine zweite Portfreigabe für SSL-Verbindungen einrichten (SSL ist nicht SSH):

Ziel Port Range: Manuell. Start: 443. Ende: 443.

Dyndns

Da wird es jetzt komplizierter, da es verschiedene Anbieter gibt. Ich habe bei mir darauf geachtet, dass es für meine (Sub-)Domain nur einen AAAA-Record gibt und keinen A-Record. (Der A-Record übersetzt einen Domainnamen in eine IPv4-Adresse, der AAAA-Record in eine IPv6-Adresse). Ich will damit erreichen, dass Verbindungen von außen gar nicht erst versuchen, eine IPv4-Verbindung aufzubauen. Abgesehen davon, wohin sollte ich die leiten? 0.0.0.0?

Mein Anbieter ist inwx.de, da habe ich für 5 Euro im Jahr eine Domain. Dazu gibt es eine „kostenlose“ Dyndns-Funktion, bei der man dann den AAAA-Record per URL-Aufruf aktualisieren kann. Ich hab die DynDns-Funktion einfach für eine neue Subdomain eingerichtet. Es wurde automatisch ein A und ein AAAA-Record erstellt. Den A-Record hab ich dann einfach wieder gelöscht. Solange ich bei dem URL-Aufruf den Parameter myip=ipaddr weglasse, wird der auch nicht mehr neu erstellt, so wie ich das wollte. Bei der Dyndns-Konfiguration erscheint interessanterweise die Fehlermeldung DynDNS-Record gelöscht, aber es funktioniert trotzdem noch, den AAAA-Record zu aktualisieren.

Bei allen folgenden Befehlen/Scripten/Konfigurationsdateien musst du deinen eigenen Domainnamen eintragen. Meiner ist radi.invisibeltower.de. Geheimhalten bringt nichts, denn alle Domains, für die ein Zertifikat ausgestellt wird, werden in einer großen Liste veröffentlicht.

Auf dem Raspberry-Pi erstellen wir ein Script, das die Dyndns-Url aktualisiert:

$ mkdir ~/domain
$ touch ~/domain/dyndns_update.sh
$ chmod +x ~/domain/dyndns_update.sh 
$ nano ~/domain/dyndns_update.sh

mit dem folgenden Inhalt:

#!/bin/bash

HOSTNAME=radi.invisibletower.de
DYNDNSUSER=hier_username_eintragen
DYNDNSPW=hier_passwort_eintragen
DYNDNSURL=hier_die_update_url_bis_zum_Fragezeichen_aber_ohne_das_Fragezeichen_eintragen

CURRENT_IP6=$(ip address show dev wlan0 | grep ff:fe | grep -v fe80: | awk '{print $2}' | sed 's/^\([0-9a-f:]*\).*/\1/g')
DNS_IP6=$(host -t AAAA ${HOSTNAME} | tr " " "\n" | grep ff:fe)

if [[ "${CURRENT_IP6}" == "" ]]; then
  date
  echo ERROR - COULD NOT GET OWN IP
  exit
fi

if [[ "${CURRENT_IP6}" == "${DNS_IP6}" ]]; then
  # Printing if everything is ok just spams the log.
  # echo OK.
  :
else
  date
  echo The DNS knows ip: ${DNS_IP6}
  echo The real ipv6 address is: ${CURRENT_IP6}
  echo Renew DNS ...
  curl ${DYNDNSURL}\?myipv6\=${CURRENT_IP6}\&hostname\=${HOSTNAME}\&username\=${DYNDNSUSER}\&password\=${DYNDNSPW}
  echo
  echo Done. Sleep 60 seconds.
  sleep 60
  echo Lookup again ...
  DNS_IP6=$(host -t AAAA ${HOSTNAME} | tr " " "\n" | grep ff:fe)
  if [[ "${CURRENT_IP6}" == "${DNS_IP6}" ]]; then
    echo DNS ok
  else
    echo ERROR - COULD NOT UPDATE DNS \(or dns TTL is longer than expected\)
  fi
fi

Ausführen via $ ~/domain/dyndns_update.sh . Jetzt sollte der DNS-Teil schonmal funktionieren.

Wenn nicht, hilft vielleicht unboundtest.com bei der Fehlersuche. Mein Fehler war ein simpler Buchstabendreher im Domainnamen. Wenn was schief geht, hilft es oft auch, einfach 3600 Sekunden zu warten. Vor allem wenn es mit unbound funktioniert, mit host -t AAAA domain.de aber nicht.

Damit das automatisch funktioniert, legen wir für dieses script einen cronjob an. Cronjobs führen Scripte regelmäßig ohne unser Zutun aus.

Mit $ sudo crontab -e öffnen wir die Tabelle aller Cronjobs und fügen ans Ende folgende Zeile ein:

*/5 * * * * /home/pi/domain/dyndns_update.sh >> /var/log/dyndns_update.log

Let’s Encrypt Nr 1

Zu Beginn brauchen wir erstmal ein SSL-Zertifikat, das wir dann im nächsten Schritt benutzen können. Dazu hab ich mich an dieser Anleitung orientiert.

Let’s encrypt stellt ein sich selbst aktualisierendes Tool mit dem Namen certbot-auto bereit. Das installieren wir erstmal:

$ cd ~/domain
$ wget https://dl.eff.org/certbot-auto
$ chmod a+x certbot-auto
$ ./certbot-auto --version

Zum Aktualisieren der Zertifikate erstellen wir ein Script:

$ cd ~/domain
$ touch letsencrypt_init.sh
$ chmod +x letsencrypt_init.sh
$ nano letsencrypt_init.sh

mit folgendem Inhalt:

#!/bin/bash

DOMAIN=radi.invisibletower.de

service haproxy stop
/home/pi/domain/certbot-auto certonly --standalone -d $DOMAIN

mkdir -p /etc/haproxy/certs
cat /etc/letsencrypt/live/$DOMAIN/fullchain.pem /etc/letsencrypt/live/$DOMAIN/privkey.pem > /etc/haproxy/certs/$DOMAIN.pem
chmod -R go-rwx /etc/haproxy/certs

service haproxy start

Da kommt auch schon der haproxy drin vor. Die beiden service-Befehle werden erstmal fehlschlagen, aber das ist ok. Ausführen mit sudo ~/domain/letsencrypt_init.sh .

Die Zertifikate sollten jetzt zu finden sein: $ sudo ls -l /etc/haproxy/certs

Haproxy

Ich benutze weder apache noch nginx als Webserver. Stattdessen läuft ein Proxy auf Port 80 und 443 der einzelne Unterverzeichnisse an andere Serverprogramme auf dem Raspberry Pi (z.B. Octoprint) weiterleitet. Der Proxy heißt Haproxy. Er kümmert sich um sowohl um SSL als auch um die Authentifizierung.

Erstmal installieren mit $ sudo apt-get install haproxy. Dann die Konfigurationsdatei $ sudo nano /etc/haproxy/haproxy.cfg anpassen:

global
        daemon
        log 127.0.0.1 local0 debug
	tune.ssl.default-dh-param 2048

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        retries 3
        option redispatch
        option http-server-close
        option forwardfor
        maxconn 2048
        timeout connect 5s
        timeout client  15min
        timeout server  15min

frontend http-in
	bind :::80 v4v6

        acl is_letsencrypt path_beg /.well-known/acme-challenge/

        use_backend letsencrypt-backend if is_letsencrypt
        redirect scheme https code 301 if !{ ssl_fc } !is_letsencrypt

frontend https-in
        bind :::443 v4v6 ssl crt /etc/haproxy/certs/radi.invisibletower.de.pem
	reqadd X-Forwarded-Proto:\ https
        option forwardfor
	
	acl myvaliduser http_auth(L1)

	use_backend webcam if myvaliduser { path_beg /webcam/ } 
	use_backend octoprint if myvaliduser { path_beg /octoprint/ } 
        use_backend octoprint_socket if myvaliduser { path_beg /sockjs/ }
	use_backend askforauth if !myvaliduser

backend webcam
	reqrep ^([^\ :]*)\ /webcam/(.*)     \1\ /\2
	server webcam1  127.0.0.1:8080

backend octoprint
	reqrep ^([^\ :]*)\ /octoprint/(.*)  \1\ /\2
	reqadd X-Script-Name:\ /octoprint
	option forwardfor
	reqadd X-Scheme:\ https if { ssl_fc }
	server octoprint1 127.0.0.1:5000

backend askforauth
	http-request auth realm Hallo

backend octoprint_socket
	reqrep ^([^\ :]*)\ /(.*)     \1\ /\2
	server octoprint1 127.0.0.1:5000

backend letsencrypt-backend
	server letsencrypt 127.0.0.1:54321

userlist L1
    group G1
    user meinusername insecure-password meinpasswort groups G1
    user zweiter_username insecure-password anderespasswort groups G1

Das sieht kompliziert aus (Doku), aber ein bisschen muss man sich da reinfuchsen. Deswegen hier ein bisschen Kontext.

Ruft man eine Internetseite im Browser auf, passiert das über das sogenannte HTTP-Protokoll. Das legt fest, wie genau der Browser nach einer bestimmten URL fragt und wie der Server darauf antworten muss. Die Frage nennt man HTTP-Request, die Antwort HTTP-Response. Beide bestehen aus Klartext, erst kommen einige sogenannte Header, darauf folgt der eigentliche Inhalt, der bei Request meist leer ist und bei Responses den HTML-Code enthält. Der HTTP-Request, mit dem ich diesen Beitrag aufrufe, sieht beispielsweise so aus:

GET /?p=241&preview=true HTTP/1.1
Host: invisibletower.de
User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://invisibletower.de/
Cookie: wordpress_logged_in=geheim; wp-settings-1=geheim; wp-settings-time-1=geheim
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0

Die erste Zeile darin gibt den Typ (GET/POST/..) und den Pfad an. Jede weitere Zeile darin ist ein Header und erfüllt irgendeine Funktion. Ein Webserver macht nichts anderes, als einen beliebigen Port zu öffnen (standardmäßig Port 80) und auf HTTP-Requests zu warten.

Der haproxy öffnet ebenendiesen Port 80, nimmt alle Anfragen an, schaut sich die Header an und leitet die Anfragen quasi als Mittelsmann nach den eigenstellten Regeln an andere Server weiter. Die Regeln können beispielsweise den aufgerufenen Pfad abfragen oder ob in den Headern ein korrektes Passwort mitgeschickt wurde. Außerdem kann haproxy den Request manipulieren, z.B. neue Header einfügen oder den Pfad verändern. Die „anderen“ Server können auf anderen Computern oder auf dem gleichen Computer, dann aber auf anderen Ports laufen. Ein Server ist quasi nur ein Programm, dass einen Port geöffnet hat. (PS: haproxy kann auch ganz normale Netzwerkverbindungen routen, die nicht das HTTP-Protokoll verwenden.)

Haproxy ist quasi ein Router. Um das intern umzusetzen, hat der haproxy sogenannte Frontends und Backends. Ein Frontend sagt, wo der haproxy Anfragen annimmt und an welches Backend sie weitergeleitet werden und das Backend sagt, wie der dahinterstehende Server erreichbar ist.

Gehen wir mal die Konfigurationsdatei durch.

frontend http-in
	bind :::80 v4v6

        acl is_letsencrypt path_beg /.well-known/acme-challenge/

        use_backend letsencrypt-backend if is_letsencrypt
        redirect scheme https code 301 if !{ ssl_fc } !is_letsencrypt

frontend sagt, dass jetzt ein neues Frontend anfängt. http-in ist der frei wählbare Name des Frontends. Der Name ist eigentlich nur wichtig für die Logdateien. bind :::80 v4v6 sagt, dass dieses Frontend Port 80 auf allen ipv4 und ipv6 adressen dieses Computers öffnen soll. acl regelname regel legt eine neue Regel an, die später im Zusammenhang mit if Anweisungen benutzt werden kann. In diesem Fall ist die Regel is_letsencrypt erfüllt, wenn der Pfad mit /.well-known/acme-challenge/ anfängt. Die use_backend-Zeile sorgt dafür, dass das Backend mit dem Namen letsencrypt-backend benutzt wird, wenn die Regel is_letsencrypt erfüllt ist. In allen anderen Fällen tritt die redirect-Anweisung in Kraft. Die liefert dem anfragenden Browser eine Antwort mit einem HTTP-Fehlercode zurück, der dem Browser sagt, er soll es mit der verschlüsselten Variante (https://) versuchen.

Was hier absichtlich fehlt sind weitere use_backend-Angaben: Damit kann eine unverschlüsselte Anfrage an Port 80 nichts schlimmes anrichten, denn hier wird weder verschlüsselt noch authentifiziert.

frontend https-in
        bind :::443 v4v6 ssl crt /etc/haproxy/certs/radi.invisibletower.de.pem
	reqadd X-Forwarded-Proto:\ https
        option forwardfor
	
	acl myvaliduser http_auth(L1)

	use_backend letsencrypt-backend if { path_beg /.well-known/acme-challenge/ }
	use_backend webcam if myvaliduser { path_beg /webcam/ } 
	use_backend octoprint if myvaliduser { path_beg /octoprint/ } 
        use_backend octoprint_socket if myvaliduser { path_beg /sockjs/ }
	use_backend askforauth if !myvaliduser

Das nächste Frontend, diesmal lauscht es auf Port 443 und macht eine SSL-Verschlüsselung mit dem angegebenen privaten Zertifikat. reqadd X-Forwarded-Proto:\ https fügt dem HTTP-Request einen X-Forwarded-Proto Header hinzu. Welche Bedeutung der genau hat muss man googlen. (PS: Der Schrägstrich escapet das Leerzeichen). option forwardfor fügt ebenfalls irgendeinen (wichtigen?) Header hinzu. acl myvaliduser http_auth(L1) legt eine neue Regel mit dem frei wählbaren Namen myvaliduser an. Die Regel ist erfüllt, wenn http_auth(L1) stimmt. http_auth schaut sich die Request-Header an, sucht nach einer Username:Passwort-Kombination und vergleicht die mit der Liste L1. Die use_backend Zeilen nutzen das Ergebnis dieser Überprüfung für ihre Entscheidung, an welches Backend sie den Request weiterleiten sollen. Das Backend askforauth bekommt alle Anfragen mit falschem oder fehlendem Passwort (das ! bedeutet Negation). Die Regeln können übrigens entweder über eine acl-Anweisung angegeben werden oder innerhalb von geschweiften Klammern { .. } nach dem if stehen. Zwischen den einzelnen Regeln braucht nur ein Leerzeichen zu stehen, sie werden behandelt, als würde dazwischen ein logisches UND stehen.

Das Passwort wird zwar über die Leitung geschickt, ist aber wegen der SSL-Verschlüsselung für alle anderen verschlüsselt. Damit niemand beispielsweise in einem öffentlichen WLAN das Passwort abgreifen kann, sollte man am besten keine Authentifizierung im http-in-Frontend einfordern, nur wie hier im https-in-Frontend.

backend webcam
	reqrep ^([^\ :]*)\ /webcam/(.*)     \1\ /\2
	server webcam1  127.0.0.1:8080

Dieses Backend leitet alle Anfragen an den Server weiter, der lokal auf Port 8080 lauscht. (127.0.0.1 ist immer die IP-Adresse des Servers selbst). webcam1 ist wieder ein frei wählbarer Name. Die Zeile mit reqrep schneidet den /webcam/ Teil des Pfades aus der Anfrage heraus.

backend askforauth
	http-request auth realm Hallo

Dieses Backend antwortet fordert mit einem speziellen HTTP-Response-Header eine Username:Passwort-Kombination vom Browser an.

userlist L1
	group G1
	....

Ist die Liste der erlaubten User. Selbsterklärend.

Mit diesem Wissen sollte man jetzt selbst weitere Backends anlegen können.

Hat man die Konfiguration geändert, kann man haproxy so neustarten:

$ sudo service haproxy stop
$ sudo service haproxy start
$ sudo service haproxy status 

Mit $ journalctl -xe kann man sich mehr Details zu Fehlern der Konfigurationsdatei anschauen.

Let’s Encrypt 2

Jetzt wo der Proxy steht, kann man die regelmäßige Let’s Encrypt Zertifikatserneuerung auch über den Proxy abwickeln. Auch diese Anleitung ist schamlos abgeschrieben.

Dazu erstellen wir einen Cronjob, der jede Nacht $ certbot renew --deploy-hook letsencrypt_renewhook.sh aufruft, welches bei erfolgtem Renewal das Script letsencrypt_renewhook.sh aufruft, welches wiederum die neuen Zertifikate für haproxy zusammenkopiert.

Als erstes erstellen wir das Script mit $ sudo nano ~/domain/letsencrypt_renewhook.sh:

 
#!/bin/sh

SITE=radi.invisibletower.de

# move to the correct let's encrypt directory
cd /etc/letsencrypt/live/$SITE

# cat files to make combined .pem for haproxy
cat fullchain.pem privkey.pem > /etc/haproxy/certs/$SITE.pem

# reload haproxy
service haproxy reload

Jetzt noch das Script ausführbar machen: $ sudo chmod u+x ~/domain/letsencrypt_renewhook.sh und mit $ sudo /home/pi/domain/letsencrypt_renewhook.sh testen. Es sollte ohne Fehler durchlaufen.

Jetzt muss noch certbot so eingestellt werden, dass er hinter dem haproxy läuft. Dazu öffnen wir die Konfigurationsdatei mit $ sudo nano /etc/letsencrypt/renewal/radi.invisibletower.de.conf und fügen in die Kategorie [renewalparams] folgende Einstellung ein:

http01_port = 54321

Den Prozess kann testen wir mit $ sudo certbot renew --dry-run. Es sollte kein roter Fehlertext auftauchen.

Mit $ sudo crontab -e öffnen wir die Tabelle aller Cronjobs und fügen ans Ende folgende Zeile ein:

30 2 * * * /home/pi/domain/certbot-auto renew --deploy-hook "/home/pi/domain/letsencrypt_renewhook.sh" >> /var/log/le-renewal.log

Android

Jetzt hatte ich noch das Problem, dass mein Handy die Seite nicht aufrufen wollte (Congstar im Telekom-Netz). Das Problem war bzw. ist, dass standardmäßig kein IPv6 unterstützt wird. Sagt man zumindest im Congstar-Forum. Aber:

Gehe im Handy in die Einstellungen. Dann nach Mobilfunknetze (das befindet sich bei mir unter Drahtlose Netzwerke => Mehr). Dann nach Zugangspunkte und wähle den aktiven Zugangspunkt aus. In der Liste ganz nach unten scrollen und APN-Protokoll sowie APN-Roaming-Protokoll auf IPv4/IPv6 stellen. Eventuell kurz den Flugzeugmodus an- und wieder ausschalten. Tadaa.

Sicherheit

Die Konfiguration hat jetzt folgende Probleme:
– Aus dem internen Netzwerk sind die „Unterserver“ auch auf ihren Spezialports zu erreichen. Das ist nicht unbedingt schlimm. Abhilfe würde dieser Befehl schaffen:

$ sudo apt-get install iptables-persistent
$ PORT=8080 sudo /sbin/iptables -A INPUT -p tcp -i wlan0 ! -s 127.0.0.1 --dport ${PORT} -j DROP && sudo /sbin/ip6tables -A INPUT -p tcp -i wlan0 ! -s ::1 --dport ${PORT} -j DROP && sudo /sbin/iptables-save | sudo tee /etc/iptables/rules.v4 && sudo /sbin/ip6tables-save | sudo tee /etc/iptables/rules.v6

– Wer die Dateien certbot-auto, dyndns_update.sh oder letsencrypt_renewhook.sh editiert hat wegen des cronjobs automatisch root-Rechte, auch wenn man ein Passwort für root vergibt. Abhilfe schafft:

$ sudo chown -R root:root ~/domain
$ sudo chmod -R 755  ~/domain

Fazit

So, jetzt sind alle Informationen mal an einer Stelle zusammengefasst. Fehler in der Anleitung bitte in die Kommentare.

Daniel.

23 comments

  1. Alex sagt:

    Vielleicht sind hier ja ein paar Strato Nutzer, für diese muss die DNS update URL wie folgt lauten:

    https://paketdomain.de:dyndnspwd@dyndns.strato.com\nic/update?hostname=subdomain.paketdomain.de&myip=%IP%&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG

    Wobei paketdomain.de die domaine ist und dyndnspwd das DynDns passwort und subdomain.paketdomain.de die entsprechende subdomain ist.

    Vielen Dank übrigens für diese Anleitung 🙂

  2. lefr sagt:

    Hallo,
    vielen Dank für die Anleitung!
    Ich habe als DynDNS Anbieter dynipv6 gewählt, komme aber nicht drauf, was die UpdateURL sein soll und woher ich sie bekomme… Irgendeine Idee?
    vielen Dank!

  3. Karl sagt:

    Erst mal vielen Dank für die Anleitung!
    Ich hab das gleiche Setup mit RaspberryPi, Unitymedia Connect Box und nutze freedns.net.
    Leider habe ich Probleme den haproxy zu starten („Failed to start HAProxy Load Balancer.“).
    Hast du noch irgendwelche Tipps?
    Vielen Dank!

    • Der Bewohner sagt:

      Ich schätze da gibt es irgendeinen Fehler in der Konfiguration von haproxy.
      Versuch mal
      `sudo haproxy -f /etc/haproxy/haproxy.cfg -c`
      Das überprüft die Konfiguration ohne sie zu laden.

      • Karl sagt:

        Du hast Recht, die Konfiguration war fehlerhaft!
        Der Befehl hat Abhilfe geschaffen!
        Vielen Dank!

      • kerem sagt:

        Vielen Dank für deine ausführliche Erklärung. Ich bekomme auch die Fehlermeldung („Failed to start HAProxy Load Balancer“). Ich habe deine Konfigurationsdatei kopiert und bei angefügt. Anschließend habe ich in dem Abschnitt fronted-https-in deinen Eintrag („/etc/haproxy/certs/radi.invisibletower.de.pem“) geändert.

        Bei Ausführung von „sudo haproxy -f /etc/haproxy/haproxy.cfg -c“ bekomme ich folgende Meldung:

        [WARNING] 166/145656 (5486) : parsing [/etc/haproxy/haproxy.cfg:26] : a ‚redirect‘ rule placed after a ‚use_backend‘ rule will still be processed before.
        [ALERT] 166/145656 (5486) : parsing [/etc/haproxy/haproxy.cfg:29] : ‚bind :::443‘ : unable to load SSL private key from PEM file ‚/etc/haproxy/certs/kerem.spdns.org.pem‘.
        [ALERT] 166/145656 (5486) : Error(s) found in configuration file : /etc/haproxy/haproxy.cfg
        [ALERT] 166/145656 (5486) : Fatal errors found in configuration.

        Hast Du Tipps, wie ich das Problem lösen kann?
        Vielen Dank!

  4. Jan sagt:

    Vielen Dank für diese ausführliche Anleitung!
    Hatte vorher große Probleme bei der Umstellung auf ipv6.

  5. Peter sagt:

    Hi,

    ich bekomme beim Dyndns Skript einen Syntaxfehler.

    /home/pi/domain/dyndns_update.sh: Zeile 20: Syntaxfehler beim unerwarteten Wort `else‘
    /home/pi/domain/dyndns_update.sh: Zeile 20: `else‘

    Ich habe es mit den individuellen Anpassungen exakt so kopiert. Was kann hier schief gelaufen sein?

  6. Aircan sagt:

    Hallo, danke für die Anleitung.

    Das Skript für die Zertifikaterneuerung wirft bei mir folgenden fehler, obwohl copy paste und Anpassungen wie erforderlich.

    /home/pi/domain/dyndns_update.sh: Zeile 20: Syntaxfehler beim unerwarteten Wort `else‘
    /home/pi/domain/dyndns_update.sh: Zeile 20: `else‘

  7. Frenemy123 sagt:

    Hallo,
    ich bekomme die fehlermeldung Error Could not get own ip.

    Wie komme ich jetzt weiter?

  8. Morti sagt:

    Hallo,

    eine Frage zu den DynDns Anbietern (ich verwende DDnns.de). Wenn ich dort einen neuen Host mit ipv6 eröffne, so trage ich als „IP/Host“ doch die öffentliche IPv6 (nicht die „Fe80:….“) meines Pi ein oder etwa nicht? Weil Standardmäßig ist dort die IP meines Laptops eingetragen und in den bisherigen Tutorials wird immer gesagt, man müsse dort nichts ändern?!

    Ansonsten vielen Dank für das Tutorial, ich bin mir sicher, ich werde es bald u.a. mithilfe deines Tuts schaffen als ziemlicher Neuling mein Pi über Ipv6 über meinen Unitymediarouter zum Laufen zu bringen.

    Morti

    • Der Bewohner sagt:

      Das ist gerade der Sinn von Dyndns, dass sich die IP Adresse auch auf der DNS-Seite dynamisch anpasst. Sobald du ein entsprechendes updateskript am laufen hast wird der Wert, den du beim Anlegen angegeben hast, überschrieben.

  9. Ibims sagt:

    Super Tutorial, alles klappt wunderbar, ich habe mir dazu noch Nextcloud auf den Pi gepackt, eingerichtet.
    Nur ist mein Pi über die dyndns nicht von außerhalb erreichbar.
    Wenn ich im Heimnetzwerk bin alles wunderbar, sobald ich von außerhalb/vpn zugreifen will ist die Seite nicht erreichbar.

    • Der Bewohner sagt:

      Kann der Internetzugang, den du benutzt, um von außerhalb zuzugreifen überhaupt IPv6? (http://ipv6-test.com/)
      Gibt https://unboundtest.com für deine DynDns-Adresse die selbe Adresse zurück wie der Befehl `ip address show dev wlan0` auf dem Raspberry?
      Da seh ich gerade, mein Tutorial funktioniert so nur, wenn der Pi über Wlan verbunden ist. Ist deiner über Ethernet verbunden?

      • Ibims sagt:

        Danke für die schnelle Antwort!
        Zu unboundtest: Ja.
        Pi läuft über Wlan ja.
        Ob der Internetzugang IPv6 kann, weiß ich nicht, dann wird es wahrscheinlich daran liegen, werde ich bei Zeiten checken. Also müsste ich meinen Pi über Portmapping (Feste ip net) IPv4 erreichbar machen oder gibts noch ne andere Möglichkeit?

        • Der Bewohner sagt:

          Das ist zumindest das Problem bei Unitimedia, dass du eben von außen keinen IPv4-Zugriff hast.

          Falls du irgendwo einen Linux-Server im Internet zur Verfügung hast, kannst du per ssh eine Portweiterleitung einrichten, so dass der Server im Internet quasi den Übersetzer zwischen IPv4 und IPv6 spielt. Hab ich aber selbst noch nie gemacht.

          • Hulkk sagt:

            Ich versuche gerade meinen Pi mit Hilfe deines tollen Guides einzurichten. Habe ihn aber über Ethernet verbunden. Gibt es dafür eine Lösung, dass ich die Adresse die NICHT mit fe80 anfängt angezeigt bekomme?
            WLAN ist für mich leider keine Option, ansonsten müsste ich nach einer anderen Lösung suchen.

  10. Fiximan sagt:

    Danke für die Anleitung.

    Statt Deines Scriptes für die dynDNS-Updates kann ich nur ddclient empfehlen – das ist in den Respositories für Raspbian verfügbar ( apt install ddclient ) und kann dann über dpkg-reconfigure ddclient zumindest vorkonfiguriert werden – dazu muss man die Update-URL und das verwendete Protokoll seines DynDNS-Dienstleisters wissen.

    Meine Konfiguration (STRATO) sieht wie folgt aus:

    ——

    # Configuration file for ddclient generated by debconf
    #
    # /etc/ddclient.conf

    protocol=dyndns2
    usev6=if, if=wlan0
    if-skip=Scope:link
    server=dyndns.strato.com/nic/update
    login=mein-login
    password=’mein-PW‘
    meine-domain.de, subdomain1.meine-domain.de, subdomain2.meine-domain.de

    ——

    Erklärung:
    protocol – das vom Dienstleister akzeptierte übertragungsprotokoll
    usev6=if – IPv6 aus den Informationen des Interfaces beziehen (statt über z.B. Webdienste wie ifconfig.me )
    if=wlan0 – die WLAN-Karte (mit der eigenen IPv6)
    if-skip=Scope:link – die lokale IPv6 ignorieren (Keywords ausschließen)
    server/login/password – die Update-URL und Anmeldedaten
    meine-domain.de … – zu (Sub)Domains, die das IP-Update beziehen sollen

    Unter ddclient –help sind die Optionen sehr ausführlich erklärt.

  11. marius321 sagt:

    Gute Anleitung!

    Habe auch mit inwx als Provider begonnen. Habe es aber bisher nicht geschafft für meine Domain auch einen AAAA-Record zu erstellen. Kannst du dazu noch etwas mehr schreiben.

    Danke und Gruß
    Marius

  12. Tahlmatril sagt:

    Danke für die Anleitung.

    Leider habe ich meinen Mobilfunkvertrag bei o2, es ist also keine IPv6-Unterstützung möglich. Unsere Rechner im Büro hängen ebenfalls über Proxy an einem Rechenzentrum und IPv6 ist nicht verfügbar.
    Was wäre die einfachste Möglichkeit, den so konfigurierten Pi für IPv4-Geräte ansteuerbar zu machen?

    Danke im Voraus!

Schreibe einen Kommentar zu Frenemy123 Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert