How to Set Up a DNS Updater in 10 Minutes (Step‑by‑Step)

DNS Updater: Keep Your Dynamic IPs Synced Automatically

If you run services from a network with a dynamic public IP (home servers, CCTV, remote desktops, or small business apps), keeping DNS records updated is essential for reliable access. A DNS updater automates that process: it detects IP changes and updates your DNS provider so your domain always points to the right address. This article explains how DNS updaters work, why you need one, common approaches, and a practical setup you can complete in under 20 minutes.

Why a DNS updater matters

  • Continuity: Without updates, your domain can point to an old IP after your ISP changes it, breaking remote access.
  • Automation: Saves manual DNS edits and reduces downtime.
  • Security & control: Modern updaters use provider APIs and tokens instead of sharing account passwords.

How DNS updaters work (high level)

  1. The updater fetches your current public IP (via a web check or router query).
  2. It compares the current IP to the last-known IP.
  3. If changed, it calls your DNS provider’s API to update the A/AAAA or dynamic DNS record.
  4. Optionally logs the change and retries on failures.

Common updater types

  • Provider-built dynamic DNS services: Many DNS hosts (Cloudflare, Namecheap, Duck DNS, Dynu, etc.) offer DDNS endpoints or client apps. Best for ease of use.
  • Standalone clients: Open-source tools (ddclient, acme-dns-updater, inadyn) that support multiple providers and run on routers, NAS, or servers.
  • Custom scripts: Lightweight curl or Python scripts scheduled with cron/systemd timers for full control.
  • Router-integrated updaters: Some home routers support DDNS natively and can update records directly.

Choosing the right approach

  • Use your DNS provider’s native DDNS if available—simplest and most reliable.
  • For multi-provider or advanced needs, use ddclient or a dedicated client.
  • For learning or minimal dependencies, use a short script with secure API tokens.
  • Ensure provider API support for A/AAAA record updates and token-based authentication.

Quick practical setup (example: Cloudflare + simple script)

Prerequisites:

  • Cloudflare account with domain added.
  • An API token with DNS edit permissions for the zone.
  • A Linux machine or NAS with curl and cron.
  1. Create an API token in Cloudflare restricted to: Zone.Zone, Zone.DNS (Edit) for the specific zone. Save the token.
  2. Save this script as /usr/local/bin/cloudflare-ddns.sh and mark executable (chmod +x):

bash

#!/usr/bin/env bash ZONE=“example.com” RECORD=“home.example.com” TOKEN=“YOUR_CF_API_TOKEN” EMAIL=[email protected] # not required if token has permissions # Fetch current public IP IP=\((</span><span class="token" style="color: rgb(57, 58, 52);">curl</span><span class="token" style="color: rgb(54, 172, 170);"> -s https://ipv4.icanhazip.com</span><span class="token" style="color: rgb(54, 172, 170);">)</span><span> </span><span></span><span class="token" style="color: rgb(0, 0, 255);">if</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">[</span><span> -z </span><span class="token" style="color: rgb(163, 21, 21);">"</span><span class="token" style="color: rgb(54, 172, 170);">\)IP ]; then echo \((</span><span class="token" style="color: rgb(57, 58, 52);">date</span><span class="token" style="color: rgb(54, 172, 170);">)</span><span class="token" style="color: rgb(163, 21, 21);"> - Failed to get public IP"</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">></span><span class="token file-descriptor" style="color: rgb(238, 153, 0); font-weight: bold;">&2</span><span> </span><span> </span><span class="token builtin" style="color: rgb(43, 145, 175);">exit</span><span> </span><span class="token" style="color: rgb(54, 172, 170);">1</span><span> </span><span></span><span class="token" style="color: rgb(0, 0, 255);">fi</span><span> </span> <span></span><span class="token" style="color: rgb(0, 128, 0); font-style: italic;"># Get record ID</span><span> </span><span></span><span class="token assign-left" style="color: rgb(54, 172, 170);">RECORD_ID</span><span class="token" style="color: rgb(57, 58, 52);">=</span><span class="token" style="color: rgb(54, 172, 170);">\)(curl -s -X GET https://api.cloudflare.com/client/v4/zones?name=\(ZONE</span><span class="token" style="color: rgb(163, 21, 21);">"</span><span class="token" style="color: rgb(54, 172, 170);"> </span><span class="token" style="color: rgb(57, 58, 52);"></span><span class="token" style="color: rgb(54, 172, 170);"> </span><span class="token" style="color: rgb(54, 172, 170);"> -H </span><span class="token" style="color: rgb(163, 21, 21);">"Authorization: Bearer </span><span class="token" style="color: rgb(163, 21, 21);">\)TOKEN -H “Content-Type: application/json” | jq -r ’.result[0].id’) DNS_ID=\((</span><span class="token" style="color: rgb(57, 58, 52);">curl</span><span class="token" style="color: rgb(54, 172, 170);"> -s -X GET </span><span class="token" style="color: rgb(163, 21, 21);">"https://api.cloudflare.com/client/v4/zones/</span><span class="token" style="color: rgb(163, 21, 21);">\)RECORD_ID/dns_records?name=\(RECORD</span><span class="token" style="color: rgb(163, 21, 21);">&type=A"</span><span class="token" style="color: rgb(54, 172, 170);"> </span><span class="token" style="color: rgb(57, 58, 52);"></span><span class="token" style="color: rgb(54, 172, 170);"> </span><span class="token" style="color: rgb(54, 172, 170);"> -H </span><span class="token" style="color: rgb(163, 21, 21);">"Authorization: Bearer </span><span class="token" style="color: rgb(163, 21, 21);">\)TOKEN -H “Content-Type: application/json” | jq -r ’.result[0].id’) # Get current DNS IP CURRENT=\((</span><span class="token" style="color: rgb(57, 58, 52);">curl</span><span class="token" style="color: rgb(54, 172, 170);"> -s -X GET </span><span class="token" style="color: rgb(163, 21, 21);">"https://api.cloudflare.com/client/v4/zones/</span><span class="token" style="color: rgb(163, 21, 21);">\)RECORD_ID/dns_records/\(DNS_ID</span><span class="token" style="color: rgb(163, 21, 21);">"</span><span class="token" style="color: rgb(54, 172, 170);"> </span><span class="token" style="color: rgb(57, 58, 52);"></span><span class="token" style="color: rgb(54, 172, 170);"> </span><span class="token" style="color: rgb(54, 172, 170);"> -H </span><span class="token" style="color: rgb(163, 21, 21);">"Authorization: Bearer </span><span class="token" style="color: rgb(163, 21, 21);">\)TOKEN -H “Content-Type: application/json” | jq -r ’.result.content’) if [ \(IP</span><span class="token" style="color: rgb(163, 21, 21);">"</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">=</span><span> </span><span class="token" style="color: rgb(163, 21, 21);">"</span><span class="token" style="color: rgb(54, 172, 170);">\)CURRENT ]; then echo \((</span><span class="token" style="color: rgb(57, 58, 52);">date</span><span class="token" style="color: rgb(54, 172, 170);">)</span><span class="token" style="color: rgb(163, 21, 21);"> - IP unchanged: </span><span class="token" style="color: rgb(54, 172, 170);">\)IP exit 0 fi # Update DNS record UPDATE=\((</span><span class="token" style="color: rgb(57, 58, 52);">curl</span><span class="token" style="color: rgb(54, 172, 170);"> -s -X PUT </span><span class="token" style="color: rgb(163, 21, 21);">"https://api.cloudflare.com/client/v4/zones/</span><span class="token" style="color: rgb(163, 21, 21);">\)RECORD_ID/dns_records/\(DNS_ID</span><span class="token" style="color: rgb(163, 21, 21);">"</span><span class="token" style="color: rgb(54, 172, 170);"> </span><span class="token" style="color: rgb(57, 58, 52);"></span><span class="token" style="color: rgb(54, 172, 170);"> </span><span class="token" style="color: rgb(54, 172, 170);"> -H </span><span class="token" style="color: rgb(163, 21, 21);">"Authorization: Bearer </span><span class="token" style="color: rgb(163, 21, 21);">\)TOKEN -H “Content-Type: application/json” –data ”{type:A,name:\(RECORD</span><span class="token" style="color: rgb(255, 0, 0);">"</span><span class="token" style="color: rgb(163, 21, 21);">,</span><span class="token" style="color: rgb(255, 0, 0);">"</span><span class="token" style="color: rgb(163, 21, 21);">content</span><span class="token" style="color: rgb(255, 0, 0);">"</span><span class="token" style="color: rgb(163, 21, 21);">:</span><span class="token" style="color: rgb(255, 0, 0);">"</span><span class="token" style="color: rgb(163, 21, 21);">\)IP,ttl:1,proxied:false}”) if echo \(UPDATE</span><span class="token" style="color: rgb(163, 21, 21);">"</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">|</span><span> jq -e </span><span class="token" style="color: rgb(163, 21, 21);">'.success'</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">></span><span>/dev/null</span><span class="token" style="color: rgb(57, 58, 52);">;</span><span> </span><span class="token" style="color: rgb(0, 0, 255);">then</span><span> </span><span> </span><span class="token builtin" style="color: rgb(43, 145, 175);">echo</span><span> </span><span class="token" style="color: rgb(163, 21, 21);">"</span><span class="token" style="color: rgb(54, 172, 170);">\)(date) - Updated \(RECORD</span><span class="token" style="color: rgb(163, 21, 21);"> -> </span><span class="token" style="color: rgb(54, 172, 170);">\)IP else echo \((</span><span class="token" style="color: rgb(57, 58, 52);">date</span><span class="token" style="color: rgb(54, 172, 170);">)</span><span class="token" style="color: rgb(163, 21, 21);"> - Update failed: </span><span class="token" style="color: rgb(54, 172, 170);">\)UPDATE >&2 exit 1 fi
  1. Install jq (for JSON parsing) and replace placeholders (ZONE, RECORD, TOKEN).
  2. Add a cron job to run every 5 minutes:
  • Run: crontab -e
  • Add: */5 * * * * /usr/local/bin/cloudflare-ddns.sh >> /var/log/ddns.log 2>&1

Best practices

  • Use API tokens with minimal scopes, not account passwords.
  • Limit update frequency to avoid rate limits (every 5–15 minutes).
  • Log changes and failures; rotate tokens periodically.
  • Use IPv6 A/AAAA handling if your ISP provides IPv6.
  • Protect scripts and tokens with restrictive file permissions.

Troubleshooting checklist

  • Verify the API token has DNS edit permissions for the zone.
  • Confirm the machine’s public IP matches what an external IP check returns.
  • Check provider rate limits and error messages in logs.
  • Ensure correct record type (A vs AAAA) and fully-qualified record name.

When to consider a managed DDNS

  • If you don’t want to maintain scripts/clients or worry about tokens, choose a managed DDNS or provider-integrated solution. They handle reliability, scaling, and often offer installers for routers and NAS.

A DNS updater is a small investment that prevents frustrating outages and manual edits. Whether you pick a provider DDNS, an open-source client, or a custom script, follow the security best practices above and automate regular checks—your domain will stay reliably reachable even as your IP changes.

Comments

Leave a Reply