Skip to content

Instantly share code, notes, and snippets.

@dd-han
Last active January 15, 2022 19:12
Show Gist options
  • Save dd-han/09853f07efdf67f0f4af3f7531ac7abf to your computer and use it in GitHub Desktop.
Save dd-han/09853f07efdf67f0f4af3f7531ac7abf to your computer and use it in GitHub Desktop.
using Cloudflare as DDNS in ASUSWRT-Merlin firmware

ASUSWRT-MERLIN custom DDNS Script for Cloudflare

for Cloudflare as DDNS

using Cloudflare API v4

Using

put ddns-start at /jffs/scripts/, setting values and set DDNS type to Custom at web Admin panel.

setting

EMAIL is your Cloudflare account

API is your Cloudflare API Key. You can find at My Profile -> API Tokens -> Global API Key -> View

TOKEN is your Cloudflare API Token. You can create one at My Profile -> API Tokens -> Create Token

Only require API OR TOKEN. Use TOKEN instead API make more safe for your Cloudflare account.

ZONEID can find by following command using Global Key

curl -X GET "https://api.cloudflare.com/client/v4/zones" \
    -H "X-Auth-Email: $EMAIL" \
    -H "X-Auth-Key: $API" \
    -H "Content-Type: application/json"

or using API Tokens (require All zones permission for list)

curl -X GET "https://api.cloudflare.com/client/v4/zones" \
    -H "X-Auth-Email: $EMAIL" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json"

RECORDID can find by following command using Global Key

curl -X GET "https://api.cloudflare.com/client/v4/zones/${ZONE}/dns_records?page=1&per_page=1000&order=type&direction=asc" \
     -H "Content-Type:application/json" \
     -H "X-Auth-Key: $API" \
     -H "X-Auth-Email: $EMAIL"

or using API Tokens (your token setting may has problem if fail)

curl -X GET "https://api.cloudflare.com/client/v4/zones/${ZONE}/dns_records?page=1&per_page=1000&order=type&direction=asc" \
     -H "Content-Type:application/json" \
     -H "Authorization: Bearer $TOKEN" \
     -H "X-Auth-Email: $EMAIL"

RECORDNAME is target domain name like ddns.dd-han.tw

RECORDTTL is record TTL in second (1=auto, Must be between 120 and 2147483647)

if you don't want skip SSL check, run opkg install ca-certificates and change command from curl -ks to curl -s

Reference

#!/bin/sh
EMAIL="Your CloudFlare E-mail address"
## uncomment next line if you using Global API Key
#API="Your Cloudflare API Key"
## comment next line if you using Global API Key
TOKEN="Your Cloudflare API Token with just enough permission"
ZONEID="Your zone id, hex16 string"
RECORDID="You DNS record ID, hex16 string"
RECORDNAME="Your DNS record name, e.g. sub.example.com"
RECORDTTL="Your DNS record TTL in second (1=auto, Must be between 120 and 2147483647)"
IP=${1}
if [ "$TOKEN" != "" ]; then
AUTH_HEADER="Authorization: Bearer ${TOKEN}"
else
AUTH_HEADER="X-Auth-Key: ${API}"
fi
RES=`curl -ks -X PUT "https://api.cloudflare.com/client/v4/zones/${ZONEID}/dns_records/${RECORDID}" \
-H "X-Auth-Email: ${EMAIL}" \
-H "${AUTH_HEADER}" \
-H "X-Auth-Key: ${API}" \
-H "Content-Type: application/json" \
--data "{\"type\":\"A\",\"name\":\"${RECORDNAME}\",\"content\":\"${IP}\",\"ttl\":${RECORDTTL},\"proxied\":false}"`
# accroding to docs, it OK to remove ttl and proxied parameters
# https://api.cloudflare.com/#dns-records-for-a-zone-update-dns-record
echo $RES | grep '"success":\ *true' > /dev/null
if [ $? -eq 0 ]; then
/sbin/ddns_custom_updated 1
else
/sbin/ddns_custom_updated 0
fi
@mrmtb
Copy link

mrmtb commented Aug 22, 2019

Thanks, this is exactly what I'd been wanting to find since migrating to CF. As the commenter noted, though, you should avoid using your global API key in the script. I created a key with only the ability to edit DNS within the specific scope of the domain I'm updating. To use this key, change the "X-Auth-Key" header to be:

-H "Authorization: Bearer ${API}"

@dd-han
Copy link
Author

dd-han commented Aug 22, 2019

Hi @d00m3dd00d, @mrmtb

Thanks for you let me known CloudFlare has limited API Token now. Maybe only Global API key available at 2016 or I missed that.

I update both file for API Token, but I sold my N66u and no more MERLIN firmware device to test (using Mikrotik RouterOS now). New script only particular test on my ArchLinux Laptop.

If any problem let me know.

@d00m3dd00d
Copy link

Glad to help @dd-han and thanks for the helpful tools :)

@zlhdd108
Copy link

Can support IPv6?

@mrmtb
Copy link

mrmtb commented Jan 15, 2022

I don't have ipv6 set up on my network (nor am I using Merlin anymore), but I would start with changing the following line to target the AAAA record instead of the A record:

`--data "{"type":"A","name":"${RECORDNAME}","content":"${IP}","ttl":${RECORDTTL},"proxied":false}"``

I think that should work with just the one change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment