====== Bind dns server ====== * http://www.zytrax.com/books/dns/ very good documentation about dns and bind ===== Configuration ===== options { auth-nxdomain no; recursion no; listen-on-v6 port 53 { any; }; listen-on port 53 { any; }; notify explicit; rate-limit { responses-per-second 10; }; }; ===== Zone configuration ===== key schwarz.in.philpep.org. { algorithm hmac-sha512; secret "XXX XXX=="; }; zone "philpep.org" { type master; file "zones/philpep.org.db"; allow-transfer { key schwarz.in.philpep.org.; }; also-notify { 192.168.96.5 key schwarz.in.philpep.org.; }; }; This configure zone "philpep.org" with one secondary dns server on "192.168.96.5". Primary and secondary master use a symetric hmac-sha512 keys. Theses keys can be generated with ''dnssec-keygen -a HMAC-SHA512 -b 512 -n HOST keyname.'' DNS zone transfer occur in two times: - Master notifies all secondary servers about the new zone serial - Secondary issue a AXFR (full) or IXFR (incremental) zone transfer Bind can be used for secondary servers as well, but you might consider using [[soft:nsd|NSD]] instead. ===== Dynamic DNS update ===== You can dynamically modify a zone using [[https://tools.ietf.org/html/rfc2136|RFC 2136]], at time of writting, only bind and [[https://www.knot-dns.cz/|knot]] server implement this. But only Bind implement fine grained update policy. ==== DNS update script ==== I use this script running in crontab every minutes on a router behind a dynamic ip address. #!/bin/sh set -e PATH=/sbin:/bin:/usr/sbin:/usr/bin export PATH IFACE="pppoe-wan" DNS_SERVER="5.39.85.37" DNS_NAME="foo.philpep.org" DNS_TTL="300" # 5 minutes DNS_KEY="/root/K0foo.philpep.org.+157+00000.private" LOGGER="logger -t dyndns" # address on $IFACE # addr=$(ip a show $PPP_IFACE | awk '$1 = "inet" && $3 == "peer" { print $2 }') # use an external service # addr=$(wget -O - https://ifconfig.co/ip) old_addr=$(dig @$DNS_SERVER +short +time=1 +tries=3 $DNS_NAME) # WAIT max 3 seconds if [ "$addr" != "$old_addr" ]; then $LOGGER "update dns from '$old_addr' to '$addr'" cat << EOF | nsupdate -t 5 -k $DNS_KEY server $DNS_SERVER update delete $DNS_NAME A update add $DNS_NAME $DNS_TTL A $addr send EOF $LOGGER "update dns from '$old_addr' to '$addr': done" fi On server side, only allow the key to update A entry for "foo.example.com" key foo.philpep.org. { algorithm hmac-sha512; secret "XXX XXX=="; }; zone "philpep.org" { # [...] update-policy { grant foo.philpep.org. name foo.philpep.org. a; }; }; ==== letsencrypt acme dns challenge ==== This is useful to issue letsencrypt certificates for internal domain names (belong a public domain), or for wildcard certificates. * https://certbot-dns-rfc2136.readthedocs.io/en/stable/ On client side, install and configure certbot-dns-rfc2136: apt-get install certbot python3-certbot-dns-rfc2136 dns_rfc2136_server = 192.168.62.2 dns_rfc2136_port = 53 dns_rfc2136_name = foo.in.philpep.org. dns_rfc2136_secret = XXX XXX== dns_rfc2136_algorithm = HMAC-SHA512 Ensure to ''chmod 600 /etc/letsencrypt/rfc2136.ini'' On server side, configure the secret key and add a grant policy: key foo.in.philpep.org. { algorithm hmac-sha512; secret "XXX XXX=="; }; zone "philpep.org" { # [...] update-policy { # allow foo.in.philpep.org and/or *.foo.in.philpep.org grant foo.philpep.org. name _acme-challenge.foo.in.philpep.org. txt; # allow all subdomain of in.philpep.org # grant foo.in.philpep.org. zonesub txt; }; }; Then back on client, issue the certificate with: certbot certonly --dns-rfc2136 --dns-rfc2136-credentials /etc/letsencrypt/rfc2136.ini -d foo.in.philpep.org -d '*.foo.in.philpep.org'