DIY Debian Router - Part 10: Dynamic DNS with ddclient

Oct 12, 2025

Introduction

This is Part 10 of the DIY Debian Router series. See Part 1 for the series introduction and links to all parts.

Residential ISPs assign dynamic public IP addresses that change periodically. Dynamic DNS (DDNS) tracks these changes, automatically updating DNS records to point to the current IP. This enables reliable remote access to services without requiring a static IP address.

This part covers:

  • Dynamic DNS concepts and architecture
  • Porkbun API setup and configuration
  • ddclient installation and setup
  • Testing and troubleshooting
  • Security considerations

Dynamic DNS (DDNS) overview

Traditional DNS maps hostnames to static IP addresses:

example.com → 203.0.113.45 (static)

With dynamic IPs, this mapping becomes stale when the ISP reassigns addresses. DDNS solves this by:

  1. Detecting IP changes: Router monitors WAN interface for new IP
  2. Updating DNS records: Sends API request to DNS provider with new IP
  3. Propagating changes: DNS provider updates authoritative records
  4. Client resolution: External clients query DNS, receive current IP

Update frequency: Typically 5-15 minutes. DNS TTL should be low (1-5 minutes) for faster propagation.

Without DDNS: You must manually check and update IP address after each ISP change (impractical).

Porkbun API Setup

Porkbun is a domain registrar offering DNS hosting with full API access for DDNS updates. It is the registrar I use and will be covering in this post.

✏️ If you're using a different registrar you'll have to adjust certain steps specific to registrar DDNS configuration.

Enabling API access

  1. Log into Porkbun account
  2. Navigate to Account Settings → API Access
  3. Click Enable API Access (if not already enabled)
  4. Review and accept the API terms

⚠️ API access is account-wide. API keys will have access to all domains in the account, so protect them carefully.

Generating API keys

Per the official documentation:

  1. In API Access section, click Create API Key
  2. Save both keys securely
    • API Key: Public identifier
    • Secret Key: Private authentication credential

⚠️ HEY, READ THIS: These keys grant full DNS control over your domain. Never share them or commit them to version control. If compromised, an attacker can modify all DNS records for the domain.

Per-domain API enablement

Porkbun requires API access to be enabled per-domain:

  1. Navigate to Domain Management
  2. Go to your domain and click the Details button
  3. Click the API ACCESS button to enable

Without per-domain enablement, API requests will fail with authentication errors.

Porkbun DDNS configuration using ddclient

An example configuration file is given below:

⚠️ The Porkbun API endpoint has changed and it seems only ddclient version >=v4.0.0 supports the new endpoint. Make sure you have an up-to-date version of ddclient. See this issue for more information.

/etc/ddclient.conf

# ddclient configuration for Porkbun DDNS
daemon=300                  # Check every 300 seconds (5 minutes)
syslog=yes                  # Log to syslog
pid=/var/run/ddclient.pid   # PID file location

# Use web-based IP detection (query external service)
usev4=webv4, webv4=ipify-ipv4

# Porkbun configuration
protocol=porkbun
apikey=YOUR_PORKBUN_API_KEY
secretapikey=YOUR_PORKBUN_SECRET_API_KEY
absurdum.ca

Replace:

  • YOUR_PORKBUN_API_KEY with your API key
  • YOUR_PORKBUN_SECRET_API_KEY with your secret API key
  • absurdum.ca with your domain name

To update multiple hostnames (e.g., root domain and www subdomain):

...
protocol=porkbun
...
absurdum.ca,www.absurdum.ca,vpn.absurdum.ca,blog.absurdum.ca

All listed hostnames will be updated with the same IP address. Porkbun will create or update A records for each hostname.

Make sure to protect the configuration file (contains API credentials):

chmod 600 /etc/ddclient.conf
chown root:root /etc/ddclient.conf

Alternative IP detection methods

ddclient can detect public IP via multiple methods:

Query external service:

usev4=webv4, webv4=ipify-ipv4

Providers:

  • ipify-ipv4: https://api.ipify.org (default, recommended)
  • checkip.dyndns.org: http://checkip.dyndns.org
  • whatismyip.akamai.com: http://whatismyip.akamai.com

Advantages: Works behind any NAT, reliable, widely supported.

Disadvantages: Requires external dependency.

Interface-based detection

Read IP from WAN interface:

usev4=if, webv4=enp8s0

Replace enp8s0 with your WAN interface name.

Advantages: No external dependency, faster.

Disadvantages: Requires publicly routable IP on interface (doesn't work if router is behind ISP NAT).

Router status page

Query router's status page:

usev4=web, web-skip='IP Address'

Advantages: Works when router is behind another device.

Disadvantages: Requires parsing router's HTML (fragile, provider-specific).

Starting and enabling ddclient

Enable and start ddclient:

systemctl enable --now ddclient

Verify service status:

systemctl status ddclient

Check logs for IP updates:

journalctl -u ddclient -f

Testing and verification

Manual update test

Force an immediate update:

ddclient -daemon=0 -debug -verbose -noquiet

This runs ddclient once in foreground with debug output.

Common issues:

  • Authentication errors: Verify API key and secret are correct, per-domain API is enabled
  • "No update required": IP hasn't changed since last update (normal)
  • Network errors: Check Internet connectivity

DNS propagation verification

Query the updated DNS record:

dig +short absurdum.ca

This may not return your public IP address depending on how you've setup your internal DNS (unbound) settings. It's best to verify the records from an external host (e.g., VPS, mobile phone on cellular).

Verifying in Porkbun dashboard

Log into Porkbun and check DNS records:

  1. Navigate to Domain Management
  2. Select your domain
  3. Click DNS Records
  4. Verify A record for your hostname shows current public IP

This confirms updates are propagating to Porkbun's authoritative DNS servers.

IPv6 DDNS configuration

Update both IPv4 and IPv6 records:

# IPv4 configuration
...

# IPv6 configuration
usev6=webv6, webv6=ipify-ipv6
protocol=porkbun
apikey=YOUR_API_KEY
secretapikey=YOUR_SECRET_KEY
absurdum.ca

This updates both A (IPv4) and AAAA (IPv6) records. Requires separate configuration blocks.

Next Steps

With Dynamic DNS working, our router is now accessible via a consistent hostname regardless of IP changes.

This concludes our DIY Debian Router setup, see the epilogue for a recap and potential next steps.

RSS
https://yusefkarim.absurdum.ca/posts/feed.xml