Docs / DNS & Domains / Dynamic DNS with TSIG Keys

Dynamic DNS with TSIG Keys

By Admin · Mar 15, 2026 · Updated Apr 24, 2026 · 403 views · 3 min read

Dynamic DNS (DDNS) allows automated updates to DNS records, essential for servers with changing IP addresses, auto-scaling infrastructure, and service discovery. TSIG (Transaction Signature) keys provide secure authentication for these updates, preventing unauthorized DNS modifications. This guide covers configuring DDNS with BIND and nsupdate using TSIG authentication.

Generating TSIG Keys

# Generate a TSIG key for DDNS updates
tsig-keygen -a hmac-sha256 ddns-key > /etc/bind/ddns-key.conf

# Output looks like:
# key "ddns-key" {
#     algorithm hmac-sha256;
#     secret "base64-encoded-secret==";
# };

BIND Configuration

# /etc/bind/named.conf
include "/etc/bind/ddns-key.conf";

zone "example.com" {
    type master;
    file "/var/lib/bind/example.com.zone";
    allow-update { key "ddns-key"; };       # Allow DDNS with TSIG
    journal "/var/lib/bind/example.com.jnl"; # Journal file for changes
};

# For reverse DNS
zone "0.168.192.in-addr.arpa" {
    type master;
    file "/var/lib/bind/192.168.0.rev";
    allow-update { key "ddns-key"; };
};

Sending Updates with nsupdate

# Interactive mode
nsupdate -k /etc/bind/ddns-key.conf
> server ns1.example.com
> zone example.com
> update delete myhost.example.com A
> update add myhost.example.com 300 A 192.168.0.100
> send
> quit

# One-liner for scripts
nsupdate -k /etc/bind/ddns-key.conf /dev/null)

if [ "$CURRENT_IP" = "$LAST_IP" ]; then
    exit 0  # No change
fi

echo "[$(date)] IP changed from $LAST_IP to $CURRENT_IP" >> /var/log/ddns.log

nsupdate -k "$KEY_FILE"  "$IP_FILE"
    echo "[$(date)] DNS updated successfully" >> /var/log/ddns.log
else
    echo "[$(date)] DNS update FAILED" >> /var/log/ddns.log
fi
# Crontab: check every 5 minutes
*/5 * * * * /usr/local/bin/ddns-update.sh

Per-Host TSIG Keys

# Generate separate keys for each host
tsig-keygen -a hmac-sha256 host1-key > /etc/bind/host1-key.conf
tsig-keygen -a hmac-sha256 host2-key > /etc/bind/host2-key.conf

# Restrict updates per host
zone "example.com" {
    type master;
    file "/var/lib/bind/example.com.zone";
    update-policy {
        grant host1-key name host1.example.com A AAAA;
        grant host2-key name host2.example.com A AAAA;
    };
};

PowerDNS DDNS

# PowerDNS supports DDNS via the API
# Enable API in pdns.conf
api=yes
api-key=your-api-key
webserver=yes

# Update via API
curl -X PATCH http://localhost:8081/api/v1/servers/localhost/zones/example.com. \
    -H "X-API-Key: your-api-key" \
    -H "Content-Type: application/json" \
    -d '{"rrsets": [{"name": "myhost.example.com.", "type": "A", "ttl": 300, "changetype": "REPLACE", "records": [{"content": "192.168.0.100", "disabled": false}]}]}'

Best Practices

  • Use TSIG keys (not IP-based ACLs) for DDNS authentication
  • Generate separate TSIG keys per host using update-policy to limit what each key can modify
  • Set low TTL (60-300 seconds) on dynamically updated records
  • Log all DDNS updates for audit purposes
  • Secure TSIG key files with restrictive permissions (600)
  • Use the journal file system in BIND for efficient incremental updates

Was this article helpful?