This article assumes you fave a few things:

  1. A Linux server with:
    • root SSH access
    • BIND installed
    • a domain already set up and working with BIND
  2. An OpenWrt router at home to send updates

The OpenWrt router isn’t strictly necessary.  You could, of course do the dynamic DNS updates with a cheap Linux firewall, but I’ll cover the configuration for OpenWrt.

DNS Server Configuration

The file naming conventions used here are for a BIND installation on Debian. Your distribution may use a different naming convention, however, the concepts should be the same.

On the DNS server (as root):

# dnssec-keygen -C -a HMAC-MD5 -b 512 -n HOST

You can use your domain name (or subdomain) as the key name if you’d like. That’s what I did in this example – it helps me keep things straight. The -C switch is for compatibility mode since it’s likely the nsupdate binary on OpenWrt will be older than the BIND installation on your DNS server. The contents of the key file will look something like this:

# cat IN KEY 512 3 157 GWruXog5QO20QSB2YvLJp60DwlfJhq0hQ9KiAXFRNDHlrhSSjGBtGlM8 wSJpWNlUbhdkBnV3Or41s1iedLoDwg==

I like to keep BIND’s key configuration in a separate file to make sure it doesn’t get overwritten with software upgrades, so I created a file called /etc/bind/keys.conf. Using the MD5 from the key file (the cryptic string(s) that ends in ‘==’, after the sets of numbers), create a keys.conf file:

	algorithm HMAC-MD5;
	secret "GWruXog5QO20QSB2YvLJp60DwlfJhq0hQ9KiAXFRNDHlrhSSjGBtGlM8 wSJpWNlUbhdkBnV3Or41s1iedLoDwg==";

Then in /etc/bind/named.conf, add this at the top:

include "/etc/bind/keys.conf";

In my /etc/bind/named.conf.local (which has all of the zones actually hosted on the server), the zone for the domain I want to make dynamic has the following:

zone "" IN {
        type master;
        file "/etc/bind/db.domain";
        update-policy {
               grant name A TXT;
        notify no;

You would substitute your domain for “” and “,” and have your own zone file in a different file named after your domain (/etc/bind/db.yourdomainname).

The “update-policy” section is the part that is added.  The first parameter to the “grant” statement is the name of the key, and the “name” parameter is the domain name – which I’ve made the same in this case. There’s nothing different about /etc/bind/db.domain than any of my other zone db files, except it’s owned by the “bind” user & group — that way when it receives a DNS update, it can change the file (dynamically!).

Also the /etc/bind directory should be owned by group “bind” so that it can create /etc/bind/db.domain.jnl — a journal file BIND will use.

OpenWrt Configuration

Install the “bind-client” package on your OpenWrt router.  I like to use the LuCI web interface.  In LuCI you can find it by searching under the software administration menu.

SCP the private & key files you created on your DNS server to your OpenWrt router.  I keep my DNS files in root’s home directory: /root.

Create a hotplug file to update the DNS when the WAN interface obtains an address. Put it in /etc/hotplug.d/iface/30-nsupdate:

[ "$INTERFACE" != "wan" ] && ( [ "$ACTION" != "ifup" ] || [ "$ACTION" != "update" ] ) && exit 0

rdate -s
include /lib/network
config_get ipaddr wan ipaddr

echo "server
update delete A
update add 86400 A $ipaddr
send" | nsupdate -k /root/ -v

Again, Replace “” with the name of your zone, and “” with the name of your dynamic domain (they could be named the same).  Replace “” with the name or IP of your DNS server.  The rdate command is in there to make sure your time is set correctly before running nsupdate.  BIND will complain if the time difference between the client & server differs too much.  While only the key file is referenced in the script, both files need to be present (usually in the same directory as each other) for nsupdate to make a valid request.

You can (and should) test the script without disrupting your network connection by SSHing into your OpenWrt router and running the following command:

# ACTION=update INTERFACE=wan /sbin/hotplug-call iface

Often BIND will complain about time, permissions, auth keys, etc. Running the test above is the best way to find out what’s going on. If there’s no output, the update probably went through. Try to ping your dynamic domain name and see if all is well.

8 thoughts on “DIY Dynamic DNS with OpenWrt & BIND

  1. Pingback: Updating DNS Entries (with nsupdate or alternative implementations) – Your Own DDNS

  2. Thanks for this script! I needed something like this and was able to adapt it to my (CeroWRT) router. See (crediting this page).

    I think the test in the first line of your script is incorrect. In particular, this part:

    [ “$ACTION” != “ifup” ] || [ “$ACTION” != “update” ]

    will *always* be true.

    Also, on my router, scan_interfaces didn’t put the (DHCP-assigned) IPv4 address of my WAN interface (called “ge00” rather than “wan”) in CONFIG_ge00_ipaddr. So I had to get that address using an alternative method.

    • I suppose it should be “not ifup AND not update” to make sure things don’t get called on “ifdown” – thank you! You should see if you could get your script added as an extra to the bind-client package of WRT.

    • Simon, do like like CeroWrt compared to OpenWrt? I’ve had to keep my routers at an old version of OpenWrt (8.09) because the newer “stable” versions have been extremely unreliable on my hardware. Wondering if it might be worth switching.

      • I cannot really compare with OpenWrt, because I went straight from the vendor firmware to CeroWrt. At the time I was interested in the anti-bufferbloat patches that were piloted on CeroWrt, but I also like its ambition to support IPv6 (and, for a while, DNSSEC). This is our home’s only WLAN, and though we sometimes have stability issues, it is quite usable.

  3. Pingback: Deploy Your Own Bind9 based DDNS Server

  4. Pingback: Debian Dynamic DNS | Leic's Blog

  5. Pingback: Dynamic DNS with OpenWrt 19.07 and - Justin Foell

Leave a Reply