Imagine you self-host most of your services and have to move. Then you find out new ISP's services are not exactly stellar, say your external IP changes more often than you'd like it to (hello BT).
I have found myself in this exact situation recently. Wanting my primary server to be always accessible, this was a challenge I could not refuse even if I wanted to. Luckily I had all I needed to be successful, a DNS zone I fully control on a server that implements DNSSEC.
The way it works is that whenever the external address changes, a signed DNS update is sent to the DNS server to replace the old address.
Set up of the service is quite easy and the following is very verbose:
dnssec-keygen -a HMAC-SHA512 -b 512 -n USER ddns-keyTwo files will be created in the current directory — Kddns-key.+165+random.key and Kddns-key.+165+random.private, their contents will look like this, but you want to keep yours secret:
ddns-key. IN KEY 0 3 165 bMyHJ/P3NvfPSAa6fuXCxR8duF+0vsHMzwRnSc2NrPZBu/Qq9tSzpeyY GH8IIjCu7u8j5KCOGfl6IROPdAxWMg==
Private-key-format: v1.3 Algorithm: 165 (HMAC_SHA512) Key: bMyHJ/P3NvfPSAa6fuXCxR8duF+0vsHMzwRnSc2NrPZBu/Qq9tSzpeyYGH8IIjCu7u8j5KCOGfl6IROPdAxWMg== Bits: AAA= Created: 20130530165503 Publish: 20130530165503 Activate: 20130530165503
root
or bind
user only:
key ddns-key { algorithm HMAC-SHA512; secret "bMyHJ/P3NvfPSAa6fuXCxR8duF+0vsHMzwRnSc2NrPZBu/Qq9tSzpeyY GH8IIjCu7u8j5KCOGfl6IROPdAxWMg=="; };
0400
.
include "ddns-key.conf";
) and add the following section in the zone definition:
allow-update { key ddns-key; };Your zone configuration might look like this now:
include "ddns-key.conf"; zone "example.com" { type master; [...] allow-update { key ddns-key; }; };If you only want to allow updates to certain parts of the zone, check out the update-policy section of the zone config.
root
or bind
user and watch out for errors:
named-checkconf
When the update is successful, the zone information will be updated and the zone's serial incremented by one. If you omit the
server
line, the master server specified in your zone's SOA will be contacted by default.
conn_details=( $SSH_CONNECTION ) new_ip="${conn_details[0]}"
crontab -l
: */15 * * * * /usr/bin/ssh -T -i $HOME/.ssh/nsupdate ssh.example.com ./bin/update-domain
Only if the A record for www.example.com does not contain the new value, perform the update.
Since we do not care that much about race conditions here, we give up atomicity and check, then update. The final script, including logging, looks like this:
/dev/null server $name_server prereq yxrrset $host A $ip send END } if is_up_to_date "$record_name" "$new_ip"; then logger -t update-domain -p user.info "Domain is still up to date, exiting" exit 0; fi logger -t update-domain -p user.info "Updating entry for '$record_name' to $new_ip" nsupdate -k "$keyfile" <
This setup seems usable enough so as not to feel like an atrocious hack, yet it still leaves something to wish for, like being notified when the IP changes and not having to poll for it. Sadly the BT HomeHub can only push the new IP address to a predefined set of DDNS providers and nothing more.