View script Copied!
Update a Cloudflare DNS A record to match this machine's current outbound IP address -- a lightweight dynamic DNS solution for home servers, dev machines, or any host behind a changing IP.
Designed to run periodically from the target host (via cron or systemd timer). Fetches the machine's public IP from ipify.org, compares it to the domain's current DNS resolution via Google DNS, and updates Cloudflare only when they differ.
$ cf-ddns YOUR_API_TOKEN home.example.com
[INF][cf-ddns] Device's IP: 203.0.113.42
[INF][cf-ddns] Domain's IP: 198.51.100.8 (home.example.com)
[INF][cf-ddns] IP addresses do not match, updating DNS
[INF][cf-ddns] Deleting A record for 198.51.100.8 (abc123...)
[INF][cf-ddns] Creating A record for 203.0.113.42
The script deletes all existing A records for the domain before creating a new one pointing to the current IP. TTL is hardcoded to 60 seconds for fast propagation.
Create a Cloudflare API token:
Run from cron every 5 minutes:
# crontab entry
*/5 * * * * /path/to/cf-ddns YOUR_API_TOKEN home.example.com 2>&1 | logger -t cf-ddns
Enable debug output to see full curl logs and API call details:
$ DDNS_DEBUG=1 cf-ddns YOUR_API_TOKEN home.example.com
[DBG][cf-ddns] curl output logged to: /tmp/curl.12345.log
[DBG][cf-ddns] GET /zones
[INF][cf-ddns] Device's IP: 203.0.113.42
...
Pipe from the web (since this is published at toolio.sh):
curl -s https://toolio.sh/cf-ddns | bash -s -- YOUR_API_TOKEN home.example.com
curl https://api.ipify.orgdig @8.8.8.8 +tcp +short $domain (Google DNS, TCP mode to avoid UDP blocks)The delete-all-then-create approach ensures a clean state even if multiple A records exist (leftover from manual edits, migrations, etc.).
| Flag | Description |
|---|---|
-h, --help |
Show help message with synopsis, description, dependencies, and API token requirements |
| Argument | Description |
|---|---|
api_token |
Cloudflare API token (required permissions: Zone.Zone, Zone.DNS) |
domain |
Fully qualified domain name to update (e.g. home.example.com) |
| Variable | Description |
|---|---|
DDNS_DEBUG |
Set to any value to enable verbose curl and debug output. Logs API calls and curl traces to stderr. |
| Code | Meaning |
|---|---|
| 0 | Success (IP already matched or DNS updated successfully) |
| 1 | Runtime failure (IP fetch failed, zone not found, API error) |
| 2 | Usage error (missing API token or domain) |
| 3 | Dependency error (curl, jq, or dig missing) |
curl -- API calls to Cloudflare and ipify.orgjq -- JSON parsing for API responsesdig -- DNS lookup via Google DNS (uses TCP mode with +tcp flag)A_RECORD_TTL=60) for fast propagation during IP changes.https://api.cloudflare.com/client/v4).NO_COLOR. All diagnostic levels ([INF], [ERR], [DBG]) write to stderr in the shape [LVL][cf-ddns] message.DDNS_DEBUG is set, full curl stderr/stdout is logged to /tmp/curl.$$.log (where $$ is the process ID).dig +tcp to avoid issues on networks that block UDP DNS traffic.