een dynamische DNS server inzetten met Docker op Debian 10

Dynamische DNS is een netwerkdienst om domeinnamen aan dynamische (tijdelijke, vaak veranderende) IP adressen te koppelen. Het wordt gebruikt om computers te benaderen die geen statisch IP adres hebben, zoals die in SOHO (Small Office/Home Office) netwerken, en wordt vaak gebruikt in combinatie met port forwarding om systemen te benaderen die achter NAT firewalls staan. Dit artikel leidt je door de volledige opzet van een Dynamische DNS server in een Docker container op een Debian 10 systeem, inclusief het instellen van de vereiste DNS records, het plaatsen van de beheer-API achter een Nginx HTTPS reverse proxy, en het automatiseren van de client-side DNS record updates.

Vereisten

  • Een enkele Debian 10 server, eventueel met IPv6 connectiviteit. (192.0.2.2 en 2001:0db8::0db9 worden gebruikt als plaatshouders voor respectievelijk de IPv4 en IPv6 van de server).
  • Toegang tot de gebruiker root, of een gebruiker met sudo privileges.
  • De poorten tcp/53 en udp/53 moeten op de host beschikbaar zijn.
  • Een geregistreerde domeinnaam en toegang tot zijn nameservers/zonefile. Maak DNS records voor dit domein zoals in de volgende paragraaf.
  • De omgevingsvariabele $EDITOR moet ingesteld zijn.
  • Optioneel een Linux/Unix client systeem om automatische DNS record updates in te stellen.

DNS records maken.

Je zult minstens 2 DNS records moeten aanmaken om je dynamische DNS server te laten werken. Kies eerst een subdomein zoals ns1.your_domain dat naar het IPv4 adres van je server zal wijzen. Kies ten tweede een subdomein zoals ddns.je_domein dat gedelegeerd zal worden naar ns1.je_domein.

Je dynamische DNS server zal alle records onder ddns.your_domain afhandelen. Het derde record, van het type AAAA, is optioneel. De bijbehorende records zien er als volgt uit:

ns1.your_domain A 192.0.2.2
ddns.your_domain NS ns1.your_domain
ns1.your_domain AAAA 2001:0db8::0db9 (optional)

DNS records example

Je moet deze records aanmaken in het configuratiescherm van je domeinregistrar. Merk op dat het tot 24 uur kan duren voor deze records goed gepropageerd zijn, maar meestal duurt het enkele minuten.

Installatie

Als je niet de root gebruiker gebruikt, raden we je aan een tijdelijke root shell te starten, omdat de meeste commando’s die in deze gids getoond worden verhoogde rechten vereisen. Om een root shell te starten, gebruik je een van de volgende commando’s:

sudo su - root
sudo -s

Stap 1: Afhankelijkheden bijwerken en installeren.

Het is altijd een goede gewoonte om je systeem eerst te updaten:

apt update
apt upgrade -y
reboot

Installeer na de herstart de softwarepakketten die voor deze opstelling nodig zijn:

  • certbot zal gebruikt worden om SSL/TLS certificaten te verkrijgen.
  • make is nodig om het docker image te bouwen waarin de DDNS server zal draaien.
  • apt-transport-https, ca-certificates, curl, gnupg2 en software-properties-common zijn nodig om de Docker repository en de bijbehorende GPG sleutel te installeren.
  • dnsutils levert dig, dat voor het testen gebruikt zal worden.
apt install -y certbot make apt-transport-https curl ca-certificates software-properties-common gnupg2 dnsutils

Stap 2: Installeer Docker CE.

Voeg de GPG sleutel van Docker toe:

curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -

Installeer de docker repository:

add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian buster stable"

Werk Debian’s repository cache bij en installeer dan docker en zijn afhankelijkheden:

apt update
apt install -y docker-ce docker-ce-cli containerd.io

Als de installatie voltooid is, zorg je ervoor dat de docker dienst ingeschakeld is en draait als volgt:

systemctl enable --now docker.service

Stap 3: Download en bouw docker-ddns

Onze dynamische DNS server zal aangedreven worden door een docker container die Bind gebruikt als DNS server en een beheer-API geschreven in Go. Kloon eerst de Github repository en bouw het container image met de volgende commando’s:

git clone https://github.com/dprandzioch/docker-ddns.git
cd docker-ddns
make image

Wacht tot het proces klaar is, wat even kan duren, open dan het bestand envfile met een teksteditor:

$EDITOR envfile

En voer het volgende in:

SHARED_SECRET=your_secret 
ZONE=ddns.your_domain
RECORD_TTL=60

Het gedeelde geheim is een wachtwoord dat gebruikt zal worden om te authenticeren met de beheer-API. ZONE geeft aan voor welke DNS zone je server verantwoordelijk zal zijn, en de record TTL geeft aan hoe lang DNS records in de cache kunnen blijven. Een TTL van 60 seconden wordt aanbevolen voor vaak wisselende dynamische IP’s.

Indien nodig kun je een willekeurige tekenreeks van 40 tekens voor het geheim genereren met het volgende commando:

cat /dev/urandom | tr -dc "a-zA-Z0-9" | fold -w 40 | head -1

We kunnen nu de container aanmaken:

docker create -it -p 127.0.0.1:8080:8080 -p 53:53 -p 53:53/udp --env-file envfile -v /mnt/ddns-data:/var/cache/bind --name ddns-server davd/docker-ddns

Dit commando maakt een container met de naam ddns-server van het beeld dat we eerder bouwden, en brengt de poorten 8080/tcp, 53/tcp en 53/udp van de host naar de container in kaart. Hij zal ook de directory /mnt/ddns-data van de host aankoppelen, op /var/cache/bind in het bestandssysteem van de container. Dit wordt gebruikt voor het bewaren van DNS gegevens over container-recreaties heen.

Controleer of de container met het commando is aangemaakt:

docker container ls -a

Er zou een enkele regel moeten worden uitgevoerd met de naam ddns-server.

Stap 4: Systemd dienst (optioneel)

Deze stap dient voor eenvoudiger beheer, maar is niet strikt vereist. Als je ervoor kiest geen systemd dienst te gebruiken, zul je de container handmatig moeten beheren of een andere beheeroplossing moeten gebruiken. Merk op dat voor grotere, complexere container-implementaties een orkestratie-oplossing zoals Kubernetes of Docker Swarm wordt aangeraden. In dit geval is een systemd dienst prima geschikt, omdat we maar een enkele container draaien.

Om deze container als een systeemdienst te kunnen beheren, wikkelen we hem in een systemd eenheid. Maak met je teksteditor het bestand /etc/system/ddns-server-ct.service:

$EDITOR /etc/systemd/system/ddns-server-ct.service

En voeg het volgende toe :

[Unit]
Description=DDNS Server Docker Container
After=docker.service
Requires=docker.service
Requires=network.target
[Service]
Type=oneshot
TimeoutStartSec=240
Restart=no
RemainAfterExit=yes
ExecStart=/usr/bin/docker start ddns-server
ExecStop=/usr/bin/docker stop ddns-server
[Install]
WantedBy=multi-user.target

Sla op en sluit af, stel dan de juiste permissies op dit unit bestand in:

chmod 664 /etc/systemd/system/ddns-server-ct.service

Laad het nieuwe dienstbestand met het volgende commando:

systemctl daemon-reload

Je zou nu in staat moeten zijn deze container met systemctlte starten en te stoppen als elke andere systeemdienst.

Als je wilt dat de DDNS server automatisch start bij het opstarten van het systeem, voer je het volgende uit:

systemctl enable ddns-server-ct.service

Stap 5: Testen van je server

Voor we verder gaan met de setup, testen we eerst de management API lokaal. Start de container:

systemctl start ddns-server-ct.service

Stuur een GET verzoek naar de API om een nieuw record te maken:

OPMERKING: De API is momenteel alleen lokaal (d.w.z. vanaf localhost) toegankelijk.

curl "http://127.0.0.1:8080/update?secret=your_secret&domain=test1&addr=1.1.1.1"

Curl zou het volgende antwoord moeten teruggeven:

{"Success":true,"Message":"Updated A record for test1 to IP address 1.1.1.1","Domain":"test1","Domains":["test1"],"Address":"1.1.1.1","AddrType":"A"}

OPMERKING: Het domein test1 verwijst naar test1.ddns.your_domain. omdat de server de zone ddns.your_domain. behandelt.

Voer een DNS lookup uit om te controleren of het record inderdaad is aangemaakt en om DNS resolutie te testen:

dig +short -t A test1.ddns.your_domain @127.0.0.1

De uitvoer zou 1.1.1.1 moeten zijn.

Stap 6: Omgekeerde proxy

Omdat de API over HTTP werkt, kan je authenticatie geheim gesniffeld worden als je een verzoek over het netwerk stuurt. Een aanvaller zou dan je DNS records kunnen manipuleren met behulp van je geheim. We zetten een omgekeerde proxy op met Nginx en beveiligen die met HTTPS. Eerst verkrijg je een SSL certificaat van Let’s Encrypt met certbot:

certbot certonly --standalone --agree-tos -m [email protected] -d ns1.your_domain

Het eigendom van je domein wordt geverifieerd en een certificaat wordt uitgegeven. Installeer vervolgens Nginx en zorg ervoor dat het ingeschakeld is en draait:

apt install -y nginx systemctl enable --now nginx.service

Schakel dan het standaard server block bestand uit, want dat is niet nodig:

unlink /etc/nginx/sites-enabled/default

We maken nu een nieuw configuratiebestand voor de omgekeerde proxy, bijvoorbeeld:

$EDITOR /etc/nginx/sites-available/ddns-api-proxy.conf

En plak het volgende, let erop dat je de IP adressen en domeinnamen vervangt door je eigen:

server {
listen 192.0.2.2:8080;
server_name ns1.your_domain;
ssl on;
ssl_certificate /etc/letsencrypt/live/ns1.your_domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ns1.your_domain/privkey.pem;

location /update {
proxy_pass http://127.0.0.1:8080;
}
location / {
return 404;
}
access_log /var/log/nginx/ddns-api-access.log;
error_log /var/log/nginx/ddns-api-error.log;
}

Optioneel: Als je wilt dat de API toegankelijk is over IPv6, voeg dan de volgende regel toe na de bestaande listen richtlijn:

listen [2001:0db8::0db9]:8080;

Schakel deze configuratie in en pas de veranderingen toe door Nginx opnieuw te laden:

ln -s /etc/nginx/sites-available/ddns-api-proxy.conf /etc/nginx/sites-enabled/
systemctl reload nginx.service

De API zou nu over het internet bereikbaar moeten zijn, en zal alleen HTTPS verbindingen accepteren. Om het te testen, geef je het commando:

curl "https://ns1.your_domain:8080/update?secret=your_secret&domain=test2&addr=1.1.1.2"

Het zou het volgende moeten opleveren:

{"Success":true,"Message":"Updated A record for test2 to IP address 1.1.1.2","Domain":"test2","Domains":["test2"],"Address":"1.1.1.2","AddrType":"A"}

Stap 7: Cliënt configuratie

Je kunt automatische record updates instellen op elke router die aangepaste dynamische DNS providers ondersteunt, zoals Pfsense. Je kunt ze ook instellen op de meeste andere apparaten in je kantoor- of thuisnetwerk. Om een record bij te werken of aan te maken, moet een GET verzoek naar het volgende eindpunt gestuurd worden:

https://ns1.your_domain:8080/update?secret=your_secret&domain=your_subdomain&addr=your_ip_address

Je kunt ook de records van meerdere subdomeinen met een enkel verzoek bijwerken. Bijvoorbeeld, om records aan te maken/bij te werken voor sub1.ddns.your_domain en sub2.ddns.your_domain met IP adres 198.51.100.100, zou je een GET verzoek naar deze URL sturen:

https://ns1.your_domain:8080/update?secret=your_secret&domain=sub1,sub2&addr=198.51.100.100

De addr parameter kan ook een IPv6 adres bevatten om bijvoorbeeld AAAA DNS records aan te maken/bij te werken:

https://ns1.your_domain:8080/update?secret=your_secret&domain=cheese&addr=2001:0db8:aaaa::

Om deze updates op een Linux cliënt te automatiseren sla je het volgende bash script op als /opt/ddns-update.sh:

#!/bin/bash

while [ -z $CURRENTIP ] do
CURRENTIP=`dig -r +short myip.opendns.com @resolver1.opendns.com 2>/dev/null`
sleep 1
done
curl -s "https://ns1.your_domain:8080/update?secret=your_secret&domain=your_subdomain&addr=${CURRENTIP}"

Dit script gebruikt een while-lus gewikkeld rond een dig commando dat het publieke IP adres van de cliënt verkrijgt en het in een variabele opslaat. De lus verzekert dat het publieke IP correct opgehaald is. Dan wordt cURL gebruikt om een API verzoek te sturen om het DNS record met dit nieuw opgehaalde IP bij te werken. Zorg ervoor dat je de waarden voor your_secret en your_subdomain vervangt.

Maak vervolgens dit script uitvoerbaar:

chmod +x /opt/ddns-update.sh

Start dan de crontab editor:

crontab -e

Voeg de volgende regel toe aan het eind van je crontab:

*/2 * * * * /opt/ddns-update.sh

Opslaan en afsluiten. Het script zal nu om de twee minuten lopen, en zo je dynamische DNS record up-to-date houden met het laatste publieke IP adres van de cliënt.

Verder lezen