Inhaltsverzeichnis
Home-Server
DynDNS
Gelegentlich ist es eine gute Idee, einen Server zu Hause einzurichten und ihn dann aus dem Internet erreichbar zu machen. Das nennt sich "Home-Server".
Hat man seinen Internetzugang bei der Telekom oder bei 1und1, dann ist das mit einem DynDNS-Account ganz einfach zu realisieren. Komplizierter wird es, wenn man seinen Internetzugang bei Unitymedia hat.
Mit einem Internetzugang von Unitymedia, bei dem man eine Fritz!Box bekommen hat, benötigt man einen DynDNS-Anbieter, der IPv6 unterstützt.
deutsche DynDNS-Anbieter:
- http://selfhost.de/ - der beste, kann aber kein IPv6
- http://spdns.de/ - kann IPv6
ddclient
Achtung: ddclient ist ziemlich buggy, wenn Cloudflare als DNS zum Einsatz kommt, empfehle ich das selbstgeschriebene Skript weiter unten (Stand ddclient 3.9.1)
- https://github.com/ddclient/ddclient - originale Konfigurationsvorlage findet man im repo unter dem Namen: ddclient.conf.in
- IPv6 und manche DNS Anbieter (z.B. Cloudflare) brauchen noch weitere Abhängigkeiten. Siehe Installation.
Konfigurationsdateien
- /etc/ddclient/ddclientv4.conf
daemon=0 syslog=yes pid=@runstatedir@/ddclient.pid ssl=yes ipv6=no login=E-MAIL password=API-KEY-TOKEN use=cmd, cmd='curl --ipv4 http://checkip.dyndns.org/', cmd-skip='Current IP Address: ' #use=web, web='http://checkip.dyndns.org/', web-skip='Current IP Address: ' protocol=cloudflare, zone=EXAMPLE.COM, ttl=1, EXAMPLE.COM
- /etc/ddclient/ddclientv6.conf
daemon=0 syslog=yes pid=@runstatedir@/ddclient.pid ssl=yes ipv6=yes login=E-MAIL password=API-KEY-TOKEN use=cmd, cmd='curl --ipv6 http://checkipv6.dyndns.org/', cmd-skip='Current IP Address: ' #use=web, web='http://checkipv6.dyndns.org/', web-skip='Current IP Address: ' protocol=cloudflare, zone=EXAMPLE.COM, ttl=1, EXAMPLE.COM
IPv6 auf der von Debian gepatchten Version (z.B. Ubuntu)
- /etc/ddclient/ddclientv6.conf
daemon=0 syslog=yes pid=@runstatedir@/ddclient.pid ssl=yes ipv6=yes login=E-MAIL password=API-KEY-TOKEN ### usev6 only works with debian's patched version in apt repos usev6=if, if='eth0', if-skip='inet6 ' protocol=cloudflare, zone=EXAMPLE.COM, ttl=1, EXAMPLE.COM
Benutzung
Aufruf (IPv4 & IPv6):
ddclient -daemon 0 -file /etc/ddclient/ddclientv4.conf -force && ddclient -daemon 0 -file /etc/ddclient/ddclientv6.conf -force
Debuggen (IPv4 & IPv6)
ddclient -daemon=0 -file /etc/ddclient/ddclientv4.conf -force -debug -noquiet -verbose && ddclient -daemon 0 -file /etc/ddclient/ddclientv6.conf -force -debug -noquiet -verbose
ddclient soll stündlich statt täglich ausgeführt werden
mv /usr/local/etc/periodic/daily/ddclient_force /usr/local/etc/periodic/hourly/
alternativ: nur den einzelnen Befehl in crontab hinzufügen
0 * * * * ddclient -daemon 0 -file /etc/ddclient/ddclientv4.conf -force && ddclient -daemon 0 -file /etc/ddclient/ddclientv6.conf -force
DynDNS-Client selbst gebaut
Cloudflare
neuste Version auf GitHub: https://github.com/masterflitzer/cloudflare-ddns.git
Abhängigkeiten: links und jq
Cron:
@reboot root cloudflare-ddns.sh > /var/log/cloudflare-ddns.log 2>&1 @hourly root cloudflare-ddns.sh > /var/log/cloudflare-ddns.log 2>&1
Skript
> apt install links curl jq
- cloudflare-ddns.ini
API_TOKEN=1234567893feefc5f0q5000bfo0c38d90bbeb ZONE_NAME=example.com
- cloudflare-ddns.sh
#!/bin/bash ##### Variables CONFIG_FILE="$(dirname "$0")/$(basename -- "$0" .sh).ini" INTERVAL="5" COUNTER="10" # boolean # if "true" the dns record for the root domain will be updated UPDATE_ROOT_DOMAIN="true" # multiple record names (subdomains) to be updated # separated by space, e.g. "www mail smtp" RECORD_NAME_V4="" RECORD_NAME_V6="" TTL="1" PROXIED="false" # stable base URL for all Version 4 HTTPS endpoints API_ENDPOINT="https://api.cloudflare.com/client/v4" # custom API-Token (not global API-Key) # permissions needed: #dns_records:edit API_TOKEN="$(cat "$CONFIG_FILE" | grep -E "^API_TOKEN=" | head -1 | cut -d "=" -f2)" # when you want to update "www.example.com", "www" is the RECORD_NAME and "example.com" is the ZONE_NAME ZONE_NAME="$(cat "$CONFIG_FILE" | grep -E "^ZONE_NAME=" | head -1 | cut -d "=" -f2)" COUNTER_V4="$COUNTER" COUNTER_V6="$COUNTER" ##### Functions links_IPv4() { IP_V4="$(links -dump http://checkip.dyndns.org/ | tr -s '[ :]' '\n' | egrep '[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+')" #IPv4="1.1.1.1" } links_IPv6() { IP_V6="$(links -dump http://checkipv6.dyndns.org/ | tr -s ' ' '\n' | egrep '[0-9a-f]+[:]+[0-9a-f]+[:]*')" #IPv6="2606:4700:4700::1111" } ##### Script ### Get IPs printf "\n#==============================================================================#\n\n" echo -n "Determining IPv4 address" links_IPv4 while test -z "$IP_V4" -a "$COUNTER_V4" -gt "0" do echo -n '.' COUNTER_V4="$(echo "$COUNTER_V4"|awk '{print $1-1}')" sleep $INTERVAL links_IPv4 done echo echo -n "Determining IPv6 address" links_IPv6 while test -z "$IP_V6" -a "$COUNTER_V6" -gt "0" do echo -n '.' COUNTER_V6="$(echo "$COUNTER_V6"|awk '{print $1-1}')" sleep $INTERVAL links_IPv6 done echo echo "IPv4: $IP_V4" echo "IPv6: $IP_V6" printf "\n#==============================================================================#\n\n" ### Get Zone ID ZONE_ID="$(curl -s -X GET "${API_ENDPOINT}/zones" -H "Authorization: Bearer ${API_TOKEN}" -H "Content-Type: application/json" 2>/dev/null | jq -r ".result[] | select(.name == \"${ZONE_NAME}\") | .id")" ### Get Record ID (IPv4) RECORD_ID_V4="$(curl -s -X GET "${API_ENDPOINT}/zones/${ZONE_ID}/dns_records" -H "Authorization: Bearer ${API_TOKEN}" -H "Content-Type: application/json" 2>/dev/null | jq -r ".result[] | select((.name == \"${ZONE_NAME}\") and (.type == \"A\")) | .id")" ### Get Record ID (IPv6) RECORD_ID_V6="$(curl -s -X GET "${API_ENDPOINT}/zones/${ZONE_ID}/dns_records" -H "Authorization: Bearer ${API_TOKEN}" -H "Content-Type: application/json" 2>/dev/null | jq -r ".result[] | select((.name == \"${ZONE_NAME}\") and (.type == \"AAAA\")) | .id")" echo "Record Name = $ZONE_NAME" echo "ZONE_ID = $ZONE_ID" echo "Record ID (IPv4) = $RECORD_ID_V4" echo "Record ID (IPv6) = $RECORD_ID_V6" ### Set IP printf "\n#==============================================================================#\n\n" if test $UPDATE_ROOT_DOMAIN == "true" then echo "IPv4: Updating DNS Record to '$IP_V4'" curl -s -X PUT "${API_ENDPOINT}/zones/${ZONE_ID}/dns_records/${RECORD_ID_V4}" -H "Authorization: Bearer ${API_TOKEN}" -H "Content-Type: application/json" --data "{\"type\":\"A\",\"name\":\"${ZONE_NAME}\",\"content\":\"${IP_V4}\",\"ttl\":${TTL},\"proxied\":${PROXIED}}"; echo printf "\n#------------------------------------------------------------------------------#\n\n" echo "IPv6: Updating DNS Record to '$IP_V6'" curl -s -X PUT "${API_ENDPOINT}/zones/${ZONE_ID}/dns_records/${RECORD_ID_V6}" -H "Authorization: Bearer ${API_TOKEN}" -H "Content-Type: application/json" --data "{\"type\":\"AAAA\",\"name\":\"${ZONE_NAME}\",\"content\":\"${IP_V6}\",\"ttl\":${TTL},\"proxied\":${PROXIED}}"; echo fi ### Set IP for Record Names printf "\n#==============================================================================#\n\n" if test ! -z "${RECORD_NAME_V4// }"; then printf "IPv4: Subdomains\n\n"; fi COUNTER="0" for RECORD_NAME in $RECORD_NAME_V4 do if test $COUNTER -gt 0; then printf "\n#------------------------------------------------------------------------------#\n\n"; fi RECORD_ID="$(curl -s -X GET "${API_ENDPOINT}/zones/${ZONE_ID}/dns_records" -H "Authorization: Bearer ${API_TOKEN}" -H "Content-Type: application/json" 2>/dev/null | jq -r ".result[] | select((.name == \"${RECORD_NAME}.${ZONE_NAME}\") and (.type == \"A\")) | .id")" echo "Record Name = $RECORD_NAME.$ZONE_NAME" echo "Record ID = $RECORD_ID" echo "Updating DNS Record to '$IP_V4'" curl -s -X PUT "${API_ENDPOINT}/zones/${ZONE_ID}/dns_records/${RECORD_ID}" -H "Authorization: Bearer ${API_TOKEN}" -H "Content-Type: application/json" --data "{\"type\":\"A\",\"name\":\"${RECORD_NAME}.${ZONE_NAME}\",\"content\":\"${IP_V4}\",\"ttl\":${TTL},\"proxied\":${PROXIED}}"; echo let "COUNTER += 1" done if test $COUNTER -gt 0; then printf "#==============================================================================#\n\n" fi if test ! -z "${RECORD_NAME_V6// }"; then printf "IPv6: Subdomains\n\n"; fi COUNTER="0" for RECORD_NAME in $RECORD_NAME_V6 do if test $COUNTER -gt 0; then printf "\n#------------------------------------------------------------------------------#\n\n"; fi RECORD_ID="$(curl -s -X GET "${API_ENDPOINT}/zones/${ZONE_ID}/dns_records" -H "Authorization: Bearer ${API_TOKEN}" -H "Content-Type: application/json" 2>/dev/null | jq -r ".result[] | select((.name == \"${RECORD_NAME}.${ZONE_NAME}\") and (.type == \"AAAA\")) | .id")" echo "Record Name = $RECORD_NAME.$ZONE_NAME" echo "Record ID = $RECORD_ID" echo "Updating DNS Record to '${IP_V6}'" curl -s -X PUT "${API_ENDPOINT}/zones/${ZONE_ID}/dns_records/${RECORD_ID}" -H "Authorization: Bearer ${API_TOKEN}" -H "Content-Type: application/json" --data "{\"type\":\"AAAA\",\"name\":\"${RECORD_NAME}.${ZONE_NAME}\",\"content\":\"${IP_V6}\",\"ttl\":${TTL},\"proxied\":${PROXIED}}"; echo let "COUNTER += 1" done if test $COUNTER -gt 0; then printf "#==============================================================================#\n\n" fi
Selfhost
Wird dagegen der Internetzugang per Horizon-Box bereitgestellt, dann kann man dort keinen DynDNS-Account eintragen und muss sich einen DynDNS-Client selber bauen.
hierfür sind folgende Schritte abzuarbeiten:
- Home-Server mit fester IP im LAN (z.B. 192.168.0.2) konfigurieren, der Server darf keine DHCP-Adresse bekommen, da sich diese u.u. ändern kann;
- in der Horizon-Box muss unter
FORTGESCHRITTEN / Weiterleitungeine Port-Weiterleitung eingerichtet werden, z.B.:| 80 | 192.168.0.2 | 80 | TCP |
- sinnvoll wäre auch ein Portweiterleitung für den Port 443 aber natürlich nur, wenn man seine Web-Seite SSL-verschlüsselt hat
- jetzt wird ein DynDNS-Zugang benötigt, den kann man u.a. bei selfhost bekommen;
- beim DynDNS-Anbieter eine Umleitung einrichten und das vergebene Passwort merken, man kann sich bei selfhost auch schon eine Update-URL generieren, von der nur die IP entsprechend jedesmal angepasst werden muss;
- beispielsweise sieht das bei selfhost so aus:
- man kann es auch automatisieren, dann würde der Kommandozeilenaufruf von Linux aus so aussehen:
links -dump http://3075846:geheim@carol.selfhost.de/nic/update?myip=$(links -dump http://www.meine-aktuelle-ip.de/ | awk '/Ihre aktuelle IP Adresse:/{print $NF}')
- die Kommandozeile kann man dann in die
crontabeintragen und einmal am Tag ausführen lassen, damit wäre der selbst gebaute DynDNS-Client fertig;- Wichtig ist hierbei noch, dass er nicht zu oft ausgeführt wird, da einige Anbieter nur ein IP-Update pro Tag zulassen!
hier noch ein paar alternative Kommandozeilenaufrufe für Linux, die theoretisch alle das gleiche bewirken sollten:
links -dump http://3075846:geheim@carol.selfhost.de/nic/update?myip=$(links -dump http://www.ip-secrets.info/ | awk '/Ihre aktuelle IP-Adresse:/{print $NF}')
links -dump http://3075846:geheim@carol.selfhost.de/nic/update?myip=$(links -dump http://www.wieistmeineip.de/ | sed -n '/Ihre IP-Adresse lautet:/,/[0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*/p' | awk '/[0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*/{print $NF}')
links -dump http://3075846:geheim@carol.selfhost.de/nic/update?myip=$(links -dump http://www.meine-aktuelle-ip.de/ | awk '/Ihre aktuelle IP Adresse:/{print $NF}')
links -dump http://3075846:geheim@carol.selfhost.de/nic/update?myip=$(links -dump http://www.meineip.de/ | sed -n '/Meine IP-Adresse lautet:/,/[0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*/p' | awk '/[0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*/{print $NF}')
links -dump http://3075846:geheim@carol.selfhost.de/nic/update?myip=$(links -dump http://meineipadresse.de/ | fgrep 'Meine o:ffentliche' | tr -s ' ' '\n' | awk '/[0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*/{print $NF}')
links -dump http://3075846:geheim@carol.selfhost.de/nic/update?myip=$(links -dump http://www.heise.de/netze/tools/meine-ip-adresse/ | awk '/Ihre Anfrage kommt von der IP-Adresse:/{print $NF}')
Statt "3075846" und "geheim" sind die eigenen Zugangsdaten für den DynDNS-Account anzugeben.
Und nicht vergessen!
Es muss unbedingt der PATH angegeben werden, denn sonst kann der CRON-Dienst das Programm links nicht finden.
Da diese Kommandos mit Linux und FreeBSD funktionieren sollen, kann ich hier den absoluten Pfad nicht angeben. Denn der links-Pfad ist bei Linux und FreeBSD unterschiedlich.
