Do you want to update your DNS when your IP changes? Are you using a router running OpenWRT and Cloudflare? Then this short guide is perfect for you!
Let’s dive right into it. The OpenWRT router needs to modify your DNS settings on Cloudflare, so we need to create an API token. We could use the global API token, but we’ll use an API token with more limited access instead.
Creating a token on Cloudflare
Head to Cloudflare and go to My profile -> API Tokens -> Create Token -> Create custom token.
Give your token a name, e.g., OpenWRT DDNS and add the following permissions:
- Zone, Zone: Read
- Zone, DNS: Edit
Under Zone Resources, select Include, then Specific Zone and choose your domain, e.g., example.com. Hit Continue to summary and then Create Token.
Remember to take note of this token as you’ll need it later.
Next up is configuring OpenWRT to work with Cloudflare. We’ll mostly use the Web GUI, but we’ll also SSH into the router to make a small change to how authentication is done with Cloudflare.
In the Web GUI, do the following:
- Go to System -> Software and press Update lists.
- Enter “ddns” into the filter field, and press Install on the
- Log out of the GUI and back in. You should now have a Services -> Dynamic DNS option. Go to it.
- Press Edit on
- Set DDNS Service provider to
cloudflare.com-v4and click Switch service.
- Then set Lookup Hostname and Domain to the domain you want to update, e.g.,
example.com. Check the Enable and the Use HTTP Secure checkbox, set Path to CA-Certificate to
- Finally, set the Username to
Bearerand paste the Cloudflare token you created into the Password field and hit Save and Apply.
If you want to update a subdomain instead, use the following format in the Domain field:
[email protected] and
sub.example.com in the Lookup field.
The settings should now look something like this:
Great work. We’re almost done.
Change how your current IP is determined
If you head to Network -> Interfaces and you can see an IPV4-address under WAN, then OpenWRT knows what your current IP is, and you can skip this step.
However, if you don’t see an IP address there, you’ll have to go to Services -> Dynamic DNS -> press Edit on myddns_ipv4 -> Go to Advanced Settings tab and change IP address source to something else.
Start using it
Now, head to Services -> Dynamic DNS and press Restart DDns.
Congratulations! 🎉 It should now be up and running. You can press Edit -> Log file viewer to view the log of what it’s doing.
If you have any questions, feel free to ask! 🙂
Questions and answers
Not all situations are the same, so here are some hopefully helpful answers where the problem is slightly different.
What if I’m using Cloudflare to proxy traffic for the domain I’m using with DDNS?
The setup above works by using DNS to check what IP the domain
example.com points to. If the domain doesn’t point to your current IP, then it’s updated.
But what if you’re also using Cloudflare to proxy requests? When Cloudflare is proxying the requests,
example.com no longer points at your IP address directly. Instead,
example.com points to Cloudflare, and Cloudflare becomes a middleman between your IP and the user.
Proxying can be helpful for multiple things: It hides your IP address from the user, and Cloudflare can cache things like images for you.
The issue arises when you now compare the IP of
example.com with your IP. Since you’ll no longer get your own IP when checking the DNS record of
example.com, OpenWRT will think that the IP for the domain is wrong and start interacting with Cloudflare to update it.
The thing is that the IP is most likely correct, but it can’t know for sure without using Cloudflare’s API to check.
It goes something like this:
- OpenWRT gets the IP of
example.com, and Cloudflare returns its own IP’s as the real IP is hidden behind Cloudflare.
- OpenWRT thinks that DNS needs to be updated as you got Cloudflare’s IP and not your own.
- It connects to Cloudflare using the API and gains access to see the real IP the domain points to through Cloudflare.
- If the real IP is wrong, it’s updated to your current IP.
So, as you can see, it will still work, but you’ll have unnecessary interactions with the Cloudflare API.
So you might wonder: How do we avoid unnecessary interactions with Cloudflare?
There is a clever solution to this problem that is possible thanks to Cloudflare supporting CNAME flattening. Let me show you how.
First, create a new subdomain that is mostly random by going to DNS settings for your domain on Cloudflare. If you want to hide your IP, the domain should not be guessable. I’m going to use the subdomain
top-secret.example.com in this example. Replace it with your own.
Press the Add record -> choose Type A -> enter
top-secret.example.com in the Name field -> enter a incorrect IP like
188.8.131.52 in the IPv4 field. Make sure it’s not proxied and press Save.
Next, remove the record for the proxied domain. In my case, that’s
example.com. Now, create a new DNS record, for
example.com, but this time with the Type CNAME. Point it to
top-secret.example.com and enable proxying, then Save.
Adding this CNAME will make Cloudflare redirect
top-secret.example.com internally, without exposing the actual IP of your server.
You’re now done with the Cloudflare part. The only thing you need to do now is to make two small changes to your DDNS settings in OpenWRT.
Go to the Basic settings for DDNS, change the Lookup Hostname to
top-secret.example.com, and set the Domain to
[email protected] (note the @). Click Save and Apply.
Now, head to Services -> Dynamic DNS and press the Start/Stop button twice to restart the service.
This way, DDNS will interact with the secret subdomain(
top-secret.example.com) to keep your DNS updated, while the actual domain(
example.com) points to the subdomain without exposing the domain or real IP.
You should now have a setup that only talks to Cloudflare when the IP has changed, even if you’re using proxying. Congratulations!⭐
Note that it, by default, might take up to 10 minutes to update the IP. You can view the logs to see what’s going on. (Dynamic DNS -> Log File Viewer tab)😊
10 replies on “Dynamic DNS(DDNS) with OpenWRT and Cloudflare”
In the new RC (21.02) of OpenWRT, the script has been updated. Now, if you set the username field to “Bearer” (captial B) it will automatically authenticate using the token — no script mods needed!
Really? That’s great! I’ll update the post when 21.02 is released.
Thanks for the heads up 👍
UPDATE: The post is now updated to work with 21.02. 😊
I mean, without this blgo post, I wouldnt have got it right. so can you explain how you determined this way? There is no documentation about it in openwrt?
You can check what the Cloudflare provider script does to figure out how the entered values are used.
If the webpage I want to serve is proxied by cloudflare, then it somehow doesnt work correctly, since nslookup will report the cloudflare proxy servers IP. Is there a way to make it work so that it updates the cloudflare internal DNS to my host instead of checking the nslookup of my webpage?
192732 : ************ ************** ************** **************
192732 note : PID ‘5138’ started at 2021-07-16 19:27
192732 : ddns version : 2.7.8-13
192732 : uci configuration:
192733 : verbose mode : 0 – run normal, NO console output
192733 : check interval: 600 seconds
192733 : force interval: 259200 seconds
192733 : retry interval: 60 seconds
192733 : retry counter : 0 times
192733 : No old process
192733 : last update: never
192733 : Detect registered/public IP
192733 : #> /usr/bin/nslookup mydomain.com >/var/run/ddns/cloudflare_ipv4_mydomain.dat 2>/var/run/ddns/cloudflare_ipv4_mydomain.err
192733 : Registered IP ‘184.108.40.206
192733 info : Starting main loop at 2021-07-16 19:27
192733 : Detect local IP on ‘web’
192733 : #> /usr/bin/curl -RsS -o /var/run/ddns/cloudflare_ipv4_mydomain.dat –stderr /var/run/ddns/cloudflare_ipv4_mydomain.err –noproxy ‘*’ ‘http://checkip.dyndns.com’
192733 : Local IP ‘X:X:X:X (MyHomeIP)’ detected on web at ‘http://checkip.dyndns.com’
192734 : Update needed – L: ‘X:X:X:X (MyHomeIP)’ R: ‘220.127.116.11 (CLOUDFLARES IP)
192734 : parsing script ‘/usr/lib/ddns/update_cloudflare_com_v4.sh’
192734 : #> /usr/bin/curl -RsS -o /var/run/ddns/cloudflare_ipv4_mydomain.dat –stderr /var/run/ddns/cloudflare_ipv4_mydomain.err –noproxy ‘*’ –header ‘Authorization:Bearer ***PW***’ –header ‘Content-Type: application/json’ –request GET ‘https://api.cloudflare.com/client/v4/zones?name=mydomain.com’
192735 : #> /usr/bin/curl -RsS -o /var/run/ddns/cloudflare_ipv4_mydomain.dat –stderr /var/run/ddns/cloudflare_ipv4_mydomain.err –noproxy ‘*’ –header ‘Authorization:Bearer ***PW***’ –header ‘Content-Type: application/json’ –request GET ‘https://api.cloudflare.com/client/v4/zones/37a6f1a0762fec47713a9c55e49abebf/dns_records?name=mydomain.com&type=A’
192737 : IPv4 at CloudFlare.com already up to date
192737 info : Update successful – IP ‘X:X:X:X (MyHomeIP)’ send
192737 info : Forced update successful – IP: ‘X:X:X:X (MyHomeIP)’ send
192737 : Waiting 600 seconds (Check Interval)
It should also work when proxying the domain(as seen by “Update successful” in your logs).
However, OpenWRT will have to check with Cloudflare by interacting with their API every single time to check what IP Cloudflare is proxying it to.
I’ve added a workaround(post updated) that eliminates these unnecessary requests if you don’t want them while still hiding your IP. I hope it helps. 😉
at least with the package “ddns-scripts_cloudflare.com-v4″ version 2.7.8-14, the authentication header sent to cloudflare does not conform to the expected header lines.
The script in /usr/bin/ddns/update_cloudflare_com_v4.sh is installed through that package, and forms it’s header lines as:
__PRGBASE=”$__PRGBASE –header ‘X-Auth-Email: $username’ ”
__PRGBASE=”$__PRGBASE –header ‘X-Auth-Key: $password’ ”
__PRGBASE=”$__PRGBASE –header ‘Content-Type: application/json’ ”
The cloudflare api does not want X-Auth-Email and X-Auth-Key as separate lines, and should not have a space character between “Content-Type:” and “application/json”. The proper API form of the header is:
__PRGBASE=”$__PRGBASE –header ‘Content-Type: application/json’ ”
__PRGBASE=”$__PRGBASE –header ‘Authorization: $username $password’ ”
where $username is expecting to be “Bearer” and $password the [api token] string, both set in the ddns configuration.
This is rewritten with OpenWrt 21.02 in mind. Editing the Cloudflare script is no longer needed. 🙂
Thank you for this, Alex. It worked like a charm with 21.02!