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.
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 🙂
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!
Du meinst dynv6 statt dynipv6?
Dann schau mal hier . Also `https://dynv6.com/api/update?hostname=ab.de&token=qwe&undsoweiter=undsofort`
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!
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.
Du hast Recht, die Konfiguration war fehlerhaft!
Der Befehl hat Abhilfe geschaffen!
Vielen Dank!
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!
Vielen Dank für diese ausführliche Anleitung!
Hatte vorher große Probleme bei der Umstellung auf ipv6.
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?
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‘
Hallo
Es sieht so aus als würden manchr shells keinen leeren then block erlauben. https://unix.stackexchange.com/questions/133972/bash-syntax-error-when-else-follows-an-empty-then-clause
Ich habe das Skript an der Stelle korrigiert, indem ich einen : eingefügt habe. Das ist die no-operation von bash.
Bisher noch ungetestet.
Hallo,
ich bekomme die fehlermeldung Error Could not get own ip.
Wie komme ich jetzt weiter?
Hallo
Ich würde dir gerne helfen, aber dafür brauche ich ausreichend Kontext. Am besten: Wo genau hängst du, was hast du bis dahin gemacht, was hast du erwartet? Was könnte bei dir anders sein als bei mir? Eine Kopie des gesamten Terminaloutpits wäre hilfreich (> via pastebin teilen)
Diese Links können dir helfen, gute Fragen zu stellen (nicht nur hier sondern überall).
https://youtu.be/53zkBvL4ZB4
https://www.biostars.org/p/75548/
https://opensource.com/life/16/10/how-ask-technical-questions
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
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.
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.
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?
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?
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.
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.
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.
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
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!