DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 966,155 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for [Cloudflare] Hosting a website with dynamic IP (dynamic DNS)
Jason K.
Jason K.

Posted on • Updated on

[Cloudflare] Hosting a website with dynamic IP (dynamic DNS)

Introduction

Recently I was given a Raspberry Pi, with nothing much to use it for, I decided to try and host my own website using the Raspberry Pi as a webserver.

Using Cloudflare's proxy service, I am able to host my own website with a custom domain I got from NameCheap.

There are just two problems though ...

  1. I have a dynamic public IP
  2. I am broke

Solution

As I am running everything on just my Raspberry Pi, I wanted something lightweight that can help solve this issue.

So after watching very insightful video from Keld Norman

I came up with a bash script that in conjunction with Crontab, fetches your lastest public IP address and updates it on Cloudflare using their APIs.

#!/bin/bash

auth_email=""                                      # The email used to login 'https://dash.cloudflare.com'
auth_key=""                                        # Top right corner, "My profile" > "Global API Key"
zone_identifier=""                                 # Can be found in the "Overview" tab of your domain
record_name=""                                     # Which record you want to be synced
proxy=true                                         # Set the proxy to true or false 

###########################################
## Check if we have an public IP
###########################################
ip=$(curl -s https://api.ipify.org || curl -s https://ipv4.icanhazip.com/)
if [ "${ip}" == "" ]; then 
  message="No public IP found."
  >&2 echo -e "${message}" >> ~/log
  exit 1
fi

###########################################
## Seek for the A record
###########################################
echo " Check Initiated" >> ~/log
record=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?name=$record_name" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json")

###########################################
## Check if the domain has an A record
###########################################
if [[ $record == *"\"count\":0"* ]]; then
  message=" Record does not exist, perhaps create one first? (${ip} for ${record_name})"
  >&2 echo -e "${message}" >> ~/log
  exit 1
fi

###########################################
## Get the existing IP 
###########################################
old_ip=$(echo "$record" | grep -Po '(?<="content":")[^"]*' | head -1)
# Compare if they're the same
if [[ $ip == $old_ip ]]; then
  message=" IP ($ip) for ${record_name} has not changed."
  echo "${message}" >> ~/log
  exit 0
fi

###########################################
## Set the record identifier from result
###########################################
record_identifier=$(echo "$record" | grep -Po '(?<="id":")[^"]*' | head -1)

###########################################
## Change the IP@Cloudflare using the API
###########################################
update=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records/$record_identifier" \
                     -H "X-Auth-Email: $auth_email" \
                     -H "X-Auth-Key: $auth_key" \
                     -H "Content-Type: application/json" \
              --data "{\"id\":\"$zone_identifier\",\"type\":\"A\",\"proxied\":${proxy},\"name\":\"$record_name\",\"content\":\"$ip\"}")

###########################################
## Report the status
###########################################
case "$update" in
*"\"success\":false"*)
  message="$ip $record_name DDNS failed for $record_identifier ($ip). DUMPING RESULTS:\n$update"
  >&2 echo -e "${message}" >> ~/log
  exit 1;;
*)
  message="$ip $record_name DDNS updated."
  echo "${message}" >> ~/log
  exit 0;;
esac
Enter fullscreen mode Exit fullscreen mode

GitHub logo K0p1-Git / cloudflare-ddns-updater

Cloudflare Dynamic DNS IP Updater script.

Cloudflare Dynamic DNS IP Updater

GitHub GitHub last commit (branch) GitHub contributors

This script is used to update dynamic DNS entries for accounts on Cloudflare.

Installation

git clone https://github.com/K0p1-Git/cloudflare-ddns-updater.git
Enter fullscreen mode Exit fullscreen mode

Usage

This script is used with crontab. Specify the frequency of execution through crontab.

# β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ minute (0 - 59)
# β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ hour (0 - 23)
# β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ day of the month (1 - 31)
# β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ month (1 - 12)
# β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ day of the week (0 - 6) (Sunday to Saturday 7 is also Sunday on some systems)
# β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ command to issue                               
# β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
# β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
# * * * * * /bin/bash {Location of the script}
Enter fullscreen mode Exit fullscreen mode

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Reference

This…

Conclusion

This is a free and lightweight dynamic DNS solution.

It's really easy to deploy. All the instructions are on my Github. If you have encountered any problems, do reach out to me and I'll try my best to help you out.

For those for are concerned with scheduling a Cron job that constantly checks for new IPs. Don't worry, it is not as resource intensive as it sounds.

Try it out and let me know what you think!


Thanks for reading!

Signing off

~Jason K.

Top comments (5)

Collapse
 
nanog6 profile image
NanoG6

Hello, what if I only need to update IPv6?

Collapse
 
k0p1 profile image
Jason K. Author

Hi, IPV6 is not supported as of now.

Collapse
 
k0p1 profile image
Jason K. Author

Hi, sorry for the late reply. The concept would still be the same but you would have to curl for IPV6 address and update via cloudflare's ipv6 API; which the script doesn't support.

Collapse
 
andrewjs18 profile image
andrewjs18

thanks for the script/tutorial. how do you make this work with several different records and varying levels of proxy statuses?

Collapse
 
k0p1 profile image
Jason K. Author

With several records, it is possible to configure on cloudflare's end to have those other records be CNAME and gave them point to the main A record. As for varying levels of proxy statues, I suggest running another instance of the script.

πŸ‘‹ New to DEV?

Head over to our Welcome Thread and tell us a bit about yourself!