Skip to content

Dynamic DNS Update Tool

The Dynamic DNS Update Tool (/tool dns-update) enables MikroTik routers to automatically update DNS records on authoritative DNS servers when IP addresses change. This functionality is essential for maintaining domain name resolution when using dynamic IP addresses assigned by ISPs.

The tool implements RFC 2136 (Dynamic Updates in the DNS) and RFC 3007 (Secure DNS Dynamic Update) standards, using HMAC-MD5 authentication to securely update DNS zones. Unlike commercial DDNS services that use HTTP-based APIs, this tool performs direct DNS protocol updates against your BIND nameserver.

This documentation covers configuration, authentication, troubleshooting, and practical deployment scenarios for the Dynamic DNS Update Tool.

Dynamic DNS Update Tool provides a mechanism to keep domain names pointing to dynamic IP addresses. When your router’s WAN IP changes (common with residential ISP connections), the tool sends DNS UPDATE requests to your authoritative DNS server, modifying the appropriate A or AAAA records to reflect the new IP address.

StandardDescription
RFC 2136Dynamic Updates in the DNS - Defines the DNS UPDATE opcode and message format
RFC 3007Secure DNS Dynamic Update - Specifies TSIG-style HMAC-MD5 authentication for DNS updates

The Dynamic DNS Update Tool supports a single cryptographic algorithm: HMAC-MD5. This algorithm, defined in RFC 4635, uses shared secret keys to authenticate DNS update messages. Each update request is signed with the HMAC-MD5 hash computed using the shared secret key.

HMAC-MD5 was chosen for DNS security because:

  • It provides message authentication and integrity verification
  • It is widely supported by BIND and other DNS server implementations
  • It has lower computational overhead than more modern algorithms
  • It operates correctly with DNS packet timing requirements

The Dynamic DNS Update Tool works exclusively with BIND (Berkeley Internet Name Domain) DNS servers. This tool will NOT work with:

  • Commercial DDNS services (DynDNS, No-IP, EveryDNS, etc.)
  • Cloud DNS providers (Cloudflare, Amazon Route 53, Google Cloud DNS)
  • Microsoft DNS Server (uses different authentication mechanisms)
  • PowerDNS (requires different configuration for TSIG)

For commercial DDNS services, use RouterOS’s built-in Cloud DDNS feature or custom scripts with HTTP API calls.

Before configuring the Dynamic DNS Update Tool, ensure your environment meets these requirements.

Your DNS server must meet these conditions to accept Dynamic DNS updates:

  1. BIND Version: Running BIND 9.x (any recent version)
  2. Zone Configuration: The zone must be configured to allow dynamic updates
  3. TSIG Key: A shared secret key must be configured on both client and server
  4. Clock Synchronization: Router and DNS server clocks must be within 5 minutes of each other
  5. Network Connectivity: Router must be able to reach the DNS server on port 53 (TCP/UDP)
WARNING: The system clock time on your router cannot differ from the DNS server's
time by more than 5 minutes. Otherwise, the DNS server will ignore update requests.

DNS TSIG authentication relies on timestamps to prevent replay attacks. If the clock skew exceeds 5 minutes, the DNS server will reject all update requests as expired or replayed.

Ensure NTP is configured on your MikroTik router:

/system ntp client
set enabled=yes primary-ntp=time.google.com secondary-ntp=time.cloudflare.com

Your BIND server must have the following configuration elements:

1. TSIG Key Definition:

Terminal window
key "dns-update-key" {
algorithm HMAC-MD5;
secret "your-shared-secret-key-here";
};

2. Zone Configuration:

Terminal window
zone "myzone.com" {
type master;
file "/var/named/myzone.com.zone";
allow-update { key "dns-update-key"; };
};

3. Optional: Access Control:

Terminal window
acl "trusted-routers" {
192.168.1.0/24;
10.0.0.0/8;
};
zone "myzone.com" {
type master;
file "/var/named/myzone.com.zone";
allow-update { trusted-routers; key "dns-update-key"; };
};

The following properties configure the Dynamic DNS Update Tool.

PropertyTypeDefaultDescription
addressIPNoneThe IP address (A record) or IPv6 address (AAAA record) to associate with the domain name
dns-serverIPNoneIP address of the authoritative DNS server to send updates to
keystringNoneThe HMAC-MD5 shared secret key value (corresponds to secret in BIND key statement)
key-namestringNoneThe key identifier (corresponds to key "name" in BIND configuration)
namestringNoneThe hostname (relative to the zone) to update
ttlintegerNoneTime-to-live value for the DNS record in seconds
zonestringNoneThe DNS zone name in which to update the record

address: Specifies the new IP address to assign to the DNS record. This can be an IPv4 address (for A records) or IPv6 address (for AAAA records). The address should be in standard dotted-decimal (IPv4) or colon-separated (IPv6) format.

dns-server: The IP address of the master or slave DNS server authoritative for the zone. This is typically the master server but can be a slave if it accepts dynamic updates (less common). The router must have IP connectivity to this server.

key: The shared secret string configured in the BIND secret statement. This value must match exactly on both client and server. Base64 encoding is not required—the key string should be the raw shared secret.

key-name: The key identifier configured in the BIND key "identifier" statement. This name must match exactly between client and server configuration.

name: The relative hostname within the zone to update. For host.example.com in the example.com zone, specify name=host. Do not include the zone name itself.

ttl: The TTL value for the updated DNS record. Lower values (300-900 seconds) allow faster propagation of changes but increase DNS query load. Higher values (3600+) reduce query load but delay propagation. Omitting this uses the zone’s default TTL.

zone: The fully qualified domain name of the DNS zone to update. This must match a zone configured on the target DNS server.

To update a single hostname in a zone with a new IP address:

Terminal window
/tool dns-update dns-server=192.0.2.1 name=router zone=example.com \
address=203.0.113.45 key-name=ddns-key key=MySecretKey123

This command:

  • Sends an update request to DNS server 192.0.2.1
  • Updates the router record in the example.com zone
  • Sets the A record to 203.0.113.45
  • Authenticates using the ddns-key TSIG key

Many deployments update DNS with the router’s current WAN IP address:

Terminal window
/tool dns-update dns-server=192.0.2.1 name=home zone=example.com \
address=[/ip address get [find interface=ether1] address]

The address can be dynamically retrieved from an interface, extracting only the IP address portion.

To update an AAAA record with an IPv6 address:

Terminal window
/tool dns-update dns-server=2001:db8::1 name=ipv6host zone=example.com \
address=2001:db8:abcd:1234::5678 key-name=ipv6-key key=IPv6SecretKey

To explicitly set a TTL value for the updated record:

Terminal window
/tool dns-update dns-server=192.0.2.1 name=server zone=mydomain.com \
address=203.0.113.100 ttl=600 key-name=update-key key=SecureKey456

This sets a 10-minute TTL on the updated record.

After running the update command, check the logs for confirmation:

Terminal window
/log print where message~"dns-update"

Successful updates show messages like:

  • dns-update: updating zone: example.com: updating RR set for home
  • dns-update: update successful

Failed updates show error messages explaining the rejection reason.

Create a script that checks if the IP has changed and updates DNS only when necessary:

Terminal window
/system script add name=ddns-update source={
:local lastIP "";
:local currentIP [/ip address get [find interface=ether1] address];
:local currentIP [:pick $currentIP 0 ([:len $currentIP] - 3)];
:if ($currentIP != $lastIP) do={
/tool dns-update dns-server=192.0.2.1 name=home zone=example.com \
address=$currentIP key-name=ddns-key key=MySecretKey123;
:set lastIP $currentIP;
:log info "DDNS updated to $currentIP";
};
}
/system scheduler add name=ddns-check interval=5m on-event=ddns-update

Update multiple hostnames in a single script execution:

Terminal window
/system script add name=update-all-hosts source={
:local wanIP [/ip address get [find interface=pppoe-out1] address];
:local wanIP [:pick $wanIP 0 ([:len $wanIP] - 3)];
:local dnsServer="192.0.2.1";
:local keyName="router-key";
:local keySecret="SharedSecretHere";
:foreach host in={"router";"server";"camera";"nas"} do={
/tool dns-update dns-server=$dnsServer name=$host zone=example.com \
address=$wanIP key-name=$keyName key=$keySecret;
:delay 1s;
};
}

Conditional Update Based on Interface Status

Section titled “Conditional Update Based on Interface Status”

Only update DNS when the WAN interface comes online:

Terminal window
/system script add name=ddns-wan-up source={
:if ([/interface get [find name=pppoe-out1] running]) do={
:local wanIP [/ip address get [find interface=pppoe-out1] address];
:local wanIP [:pick $wanIP 0 ([:len $wanIP] - 3)];
/tool dns-update dns-server=192.0.2.1 name=dynamic zone=example.com \
address=$wanIP key-name=ddns-key key=MySecretKey123;
}
}
/interface pppoe-client add name=pppoe-out1 user=username password=password \
interface=ether1 add-default-route=yes dial-on-demand=no \
on-up=":delay 2s; /system script run ddns-wan-up;"

Proper key management is essential for securing dynamic DNS updates:

  1. Use Long, Random Keys: Generate keys using a secure random generator. Minimum 32 characters of random data.

    Terminal window
    /tool generate random length=32
  2. Rotate Keys Periodically: Change TSIG keys every 90-180 days.

  3. Use Different Keys per Router: If multiple routers update the same zone, use separate keys for each router. This allows key revocation without affecting all devices.

  4. Restrict Key Usage: Configure BIND to only allow the specific IP address to use each key:

    Terminal window
    key "router1-key" {
    algorithm HMAC-MD5;
    secret "router1-secret-here";
    };
    acl "router1-ips" { 203.0.113.10; };
    zone "example.com" {
    ...
    update-policy {
    grant router1-key name router1.example.com A ...;
    };
    };
  1. Use VPN Tunnels: If the DNS server is on an external network, tunnel the update traffic through VPN:

    /ip route add dst-address=192.0.2.0/24 gateway=10.0.0.1
  2. Firewall Rules: Restrict DNS server access:

    /ip firewall filter add chain=forward dst-port=53 protocol=udp \
    dst-address=192.0.2.1 action=accept comment="Allow DDNS updates"
  3. Monitor Updates: Log successful and failed update attempts for audit purposes.

“TSIG error: Server rejected”

Cause: Clock synchronization issue or key mismatch.

Solution:

  • Verify NTP is working on both router and DNS server
  • Check that the key-name and key values match exactly on both sides
  • Ensure both systems use the same time zone

“Zone not found”

Cause: The specified zone does not exist on the target DNS server.

Solution:

  • Verify the zone name spelling
  • Confirm the DNS server IP is authoritative for the zone
  • Check that the zone allows dynamic updates

“Name not found”

Cause: The hostname to update does not exist in the zone.

Solution:

  • Create the record manually first (with any IP) if using update-policy
  • Or use BIND’s allow-update to create new records

“Permission denied”

Cause: The TSIG key is not authorized to update the specified zone or record.

Solution:

  • Check BIND’s allow-update or update-policy configuration
  • Verify the key exists in BIND’s configuration
  • Check that the router’s IP is permitted in the ACL

Test DNS Server Connectivity:

Terminal window
ping 192.0.2.1

Verify DNS Server Responds:

Terminal window
[:resolve dns-server=192.0.2.1 name=example.com]

Check TSIG Key Format:

Terminal window
:put "Key name: ddns-key, Secret length: [:len \"MySecretKey123\"]"

Enable Debug Logging:

Terminal window
/system logging add topics=dns,debug action=memory

On the BIND server, check the following:

1. Verify key configuration:

Terminal window
named-checkconf -t /etc/bind

2. Check zone file syntax:

Terminal window
named-checkzone example.com /var/named/example.com.zone

3. View BIND query log:

Terminal window
tail -f /var/log/named/query.log

4. View BIND update log:

Terminal window
tail -f /var/log/named/update.log

For granular control over which records a key can update, use BIND’s update-policy statement instead of allow-update:

Terminal window
key "router-key" {
algorithm HMAC-MD5;
secret "router1-secret";
};
zone "example.com" {
type master;
file "/var/named/example.com.zone";
update-policy {
# Allow router1 to update only its own A record
grant router-key name router1.example.com A;
# Allow router1 to update only its own AAAA record
grant router-key name router1.example.com AAAA;
# Deny updates to other records
deny *;
};
};

For high availability, maintain a list of DNS servers and try each until one succeeds:

Terminal window
/system script add name=ddns-failover source={
:local wanIP [/ip address get [find interface=ether1] address];
:local wanIP [:pick $wanIP 0 ([:len $wanIP] - 3)];
:local dnsServers={192.0.2.1; 192.0.2.2; 192.0.2.3};
:local success false;
:foreach server in=$dnsServers do={
:if (!$success) do={
:do {
/tool dns-update dns-server=$server name=home zone=example.com \
address=$wanIP key-name=ddns-key key=MySecretKey123;
:set success true;
:log info "DDNS update successful via $server";
} on-error={
:log warning "DDNS update failed via $server, trying next...";
};
};
};
}

Managing IPv6 addresses requires additional considerations:

Terminal window
/system script add name=ddns-ipv6 source={
:local ipv6Addr [/ipv6 address get [find interface=ether1] address];
# Remove prefix length from address
:local ipv6Addr [:pick $ipv6Addr 0 [:find $ipv6Addr "/"]];
/tool dns-update dns-server=2001:db8::1 name=ipv6host zone=example.com \
address=$ipv6Addr key-name=ipv6-key key=IPv6SecretKey;
}