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
@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