A dynamic DNS update client for BIND-compatible nameservers. Updates A, AAAA,
CNAME and PTR records using nsupdate with TSIG key authentication.
When no IP address is provided on the command line, the script automatically detects the external address via ifconfig.me.
bashnsupdate(part of BIND orbind-utils)dig(part of BIND orbind-utils)curl(for external IP detection)- A TSIG key file for authenticating DNS updates
curl -O https://raw.githubusercontent.com/brendanbank/ddns-update-sh/master/ddns-update.sh
chmod +x ddns-update.shOr clone the repository:
git clone https://github.com/brendanbank/ddns-update-sh.git
cd ddns-update-shusage: ddns-update.sh [-h HOSTNAME] [-k keyfile] [-c TARGET] [-6] [-4]
[-I INTERFACE] [-n NAMESERVER] [-F] [-v] [-D] [-r] [-l logfile]
[-H] [IP ADDRESS]
| Option | Description |
|---|---|
-h HOSTNAME |
Hostname to set the resource record for |
-k KEYFILE |
Path to the BIND TSIG key file |
-c TARGET |
Create a CNAME record pointing to TARGET |
-6 |
Use IPv6 (AAAA record) |
-4 |
Use IPv4 (A record; default) |
-I INTERFACE |
Network interface for external IP lookup |
-n NAMESERVER |
IP address of the authoritative nameserver |
-F |
Force update even if the record already matches |
-v |
Verbose output |
-D |
Delete the resource record |
-r |
Create a reverse (PTR) record |
-l LOGFILE |
Redirect all output to a log file |
-H |
Show help message |
Update an A record with auto-detected external IPv4:
./ddns-update.sh -h myhost.example.com -n 10.0.0.1 -k /path/to/key.confUpdate an AAAA record on a specific interface:
./ddns-update.sh -h myhost.example.com -n 10.0.0.1 -k /path/to/key.conf -6 -I eth0Set a specific IP address (skip auto-detection):
./ddns-update.sh -h myhost.example.com -n 10.0.0.1 -k /path/to/key.conf 203.0.113.42Create a CNAME record:
./ddns-update.sh -h alias.example.com -c target.example.com -n 10.0.0.1 -k /path/to/key.confCreate a reverse PTR record:
./ddns-update.sh -h myhost.example.com -n 10.0.0.1 -k /path/to/key.conf -r 203.0.113.42Delete a record:
./ddns-update.sh -h myhost.example.com -n 10.0.0.1 -k /path/to/key.conf -DForce update (even if the record hasn't changed):
./ddns-update.sh -h myhost.example.com -n 10.0.0.1 -k /path/to/key.conf -FInstead of passing -n and -k on every invocation, you can create a .env
file in the same directory as the script:
NAMESERVER=10.0.0.1
KEYFILE=/path/to/key.confAny variable that corresponds to a command-line option can be set here (e.g.
HOSTNAME, INTERFACE, IPCLASS). Command-line arguments always override
.env values.
With a .env in place, the examples above simplify to:
./ddns-update.sh -h myhost.example.com
./ddns-update.sh -h myhost.example.com -6 -I eth0
./ddns-update.sh -h alias.example.com -c target.example.comThe .env file is gitignored by default to prevent accidental commits of
credentials.
The key file is a standard BIND TSIG key in the format:
key "keyname" {
algorithm hmac-sha512;
secret "base64-encoded-secret";
};
Generate one with tsig-keygen:
tsig-keygen -a hmac-sha512 keyname > /path/to/key.confRun every 5 minutes to keep a dynamic DNS record up to date:
*/5 * * * * /usr/local/bin/ddns-update.sh -h myhost.example.com -n 10.0.0.1 -k /path/to/key.conf -l /var/log/ddns-update.logThe unit test suite validates option parsing, IP validation, IPv6 expansion, reverse-IP generation, and interface checking without requiring a live DNS server:
./tests/run_tests.shThe live test suite performs real DNS updates against a nameserver and verifies
the results with dig. It covers A, AAAA, CNAME, PTR (IPv4 and IPv6) records,
idempotency checks, force updates, deletes, and external IP auto-detection via
-I INTERFACE.
- Copy the example config and fill in your values:
cp tests/live_tests.conf.example tests/live_tests.conf- Edit
tests/live_tests.confwith your nameserver, TSIG key path, test domain, reverse delegation prefixes, and network interface:
LIVE_NAMESERVER="10.0.0.1"
LIVE_KEYFILE="/path/to/tsig.key"
LIVE_DOMAIN="test.example.com"
LIVE_PTR_NET="10.99.99"
LIVE_PTR6_PREFIX="2001:db8:1:2:3:4"
LIVE_INTERFACE="en0"
- Run the tests:
./tests/live_tests.shThe config file (*.conf) is gitignored and will not be committed.
See tests/README.md for details.
BSD 2-Clause "Simplified" License. See LICENSE for the full text.