Initial Commit
This commit is contained in:
21
README.md
Normal file
21
README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Cloudflare Updater
|
||||
Python script to update Cloudflare DNS records when a server's IP address changes
|
||||
|
||||
## Installation:
|
||||
Get the script and make it executable:
|
||||
|
||||
git clone https://github.com/jcharman/Cloudflare-Updater
|
||||
chmod +x ./updateCloudflare.py
|
||||
Copy the example config file into place:
|
||||
|
||||
cp ./updateCloudflare.conf.example updateCloudflare.conf
|
||||
Edit the file with values for your setup.
|
||||
|
||||
Run the script:
|
||||
|
||||
./updateCloudflare.py
|
||||
|
||||
## Usage
|
||||
This script is designed to be run by cron periodically. On each run it will get the server's current IP, check it against the IP last time the script ran and update Cloudflare if necessary. If the script has not been run before it will get the current IP address from Cloudflare.
|
||||
|
||||
NOTE: This script WILL NOT detect manual changes to cloudflare and will only update the IP when it detects that the server's IP address has changed. To force the script to check the current IP in Cloudflare, delete the updateCloudflare.lastip file.
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@@ -0,0 +1 @@
|
||||
tldextract==2.2.2
|
6
updateCloudflare.conf.example
Normal file
6
updateCloudflare.conf.example
Normal file
@@ -0,0 +1,6 @@
|
||||
# Email to authenticate against cloudlflare
|
||||
email=your@email.address
|
||||
# Cloudflare API key.
|
||||
apiKey=aaabbbcccdddeeefffggghhhiiijjjkkklllm
|
||||
# Host to be updated.
|
||||
host=subdomain.domain.tld
|
145
updateCloudflare.py
Executable file
145
updateCloudflare.py
Executable file
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
try:
|
||||
import requests
|
||||
import json
|
||||
import tempfile
|
||||
import tldextract
|
||||
import os
|
||||
except ModuleNotFoundError:
|
||||
print("Missing module, see requirements.txt")
|
||||
exit(1)
|
||||
|
||||
def getZone(email, apiKey, host):
|
||||
listZones = requests.get(f"https://api.cloudflare.com/client/v4/zones/",
|
||||
headers={"X-Auth-Email": f"{email}","X-Auth-Key": f"{apiKey}","Content-Type": "application/json"}).json()
|
||||
|
||||
if listZones["success"] != True:
|
||||
print("Could not get Zone ID from Cloudflare. Errors were: " + str(listZones["errors"]))
|
||||
exit(1)
|
||||
|
||||
# Extract the root domain from the full host.
|
||||
extractedHost = tldextract.extract(host)
|
||||
domain = (extractedHost.domain + "." + extractedHost.suffix)
|
||||
|
||||
for zone in listZones["result"]:
|
||||
if zone["name"] == domain:
|
||||
return zone["id"]
|
||||
|
||||
print("Could not find a Zone ID for the specified domain.")
|
||||
exit(1)
|
||||
|
||||
def storeIP(ip):
|
||||
# Store the given IP in the lastip file.
|
||||
file = open(scriptDir + 'updateCloudflare.lastip', 'w+')
|
||||
file.write(ip)
|
||||
|
||||
def checkCloudflare(zone, email, apiKey, host):
|
||||
# Get all the records in the zone.
|
||||
allRecords = requests.get(f"https://api.cloudflare.com/client/v4/zones/{zone}/dns_records",
|
||||
headers={"X-Auth-Email": f"{email}","X-Auth-Key": f"{apiKey}","Content-Type": "application/json"}).json()
|
||||
|
||||
# Search for the defined zone in the list and get it's IP.
|
||||
for currentRecord in allRecords["result"]:
|
||||
if currentRecord["name"] == host:
|
||||
recordIP = currentRecord["content"]
|
||||
print(f"IP of {host} is " + recordIP)
|
||||
return(recordIP)
|
||||
|
||||
def updateCloudflare(zone, email, apiKey, host, ip):
|
||||
# Get all records for the given zone.
|
||||
allRecords = requests.get(f"https://api.cloudflare.com/client/v4/zones/{zone}/dns_records",
|
||||
headers={"X-Auth-Email": f"{email}","X-Auth-Key": f"{apiKey}","Content-Type": "application/json"}).json()
|
||||
|
||||
# Find the record for the domain we want to work on.
|
||||
for currentRecord in allRecords["result"]:
|
||||
if currentRecord["name"] == host:
|
||||
recordID = currentRecord["id"]
|
||||
print(f"ID for {host} is " + recordID)
|
||||
|
||||
# Update our record with the new IP.
|
||||
result = requests.patch(f"https://api.cloudflare.com/client/v4/zones/{zone}/dns_records/" + recordID,
|
||||
headers={"X-Auth-Email": f"{email}","X-Auth-Key": f"{apiKey}","Content-Type": "application/json"},
|
||||
data='{"content":"%s"}' % ip).json()
|
||||
|
||||
# Check if Cloudflare returned any errors.
|
||||
if result["success"] == True:
|
||||
print("Cloudflare was successfully updated")
|
||||
else:
|
||||
print("Updating failed, errors were: " + str(result["errors"]))
|
||||
|
||||
print(
|
||||
'''
|
||||
------------------------------
|
||||
Cloudflare updater
|
||||
www.jakecharman.co.uk
|
||||
------------------------------
|
||||
'''
|
||||
)
|
||||
|
||||
# Get the directory of the script.
|
||||
scriptDir = os.path.dirname(os.path.realpath(__file__)) + "/"
|
||||
|
||||
# Read in parameters from the config file.
|
||||
try:
|
||||
configFile = open(scriptDir + "updateCloudflare.conf", "r")
|
||||
except FileNotFoundError:
|
||||
print("Configuration file does not exist.")
|
||||
exit(1)
|
||||
|
||||
configLines = configFile.readlines()
|
||||
for line in configLines:
|
||||
if line[0] == "#":
|
||||
continue
|
||||
# Remove any spaces from the line then split it to an array on the = sign.
|
||||
splitLn = line.replace(" ", "").strip().split('#')[0].split("=")
|
||||
|
||||
# Pull in the known config lines.
|
||||
if (splitLn[0] == "email"):
|
||||
authEmail = splitLn[1]
|
||||
elif (splitLn[0] == "apiKey"):
|
||||
apiKey = splitLn[1]
|
||||
elif (splitLn[0] == "host"):
|
||||
hostToUpdate = splitLn[1]
|
||||
else:
|
||||
# Error out on an unknown config line.
|
||||
print("Unknown config: " + splitLn[0])
|
||||
exit(1)
|
||||
|
||||
# Get the Zone ID for the given hostname.
|
||||
zoneID = getZone(authEmail, apiKey, hostToUpdate)
|
||||
|
||||
# Open the temp file.
|
||||
try:
|
||||
file = open(scriptDir + 'updateCloudflare.lastip', 'r')
|
||||
lastip = file.read()
|
||||
except FileNotFoundError:
|
||||
lastip = ""
|
||||
|
||||
if lastip == "":
|
||||
storedIP = False
|
||||
print("No stored IP... checking Cloudflare API")
|
||||
cloudflareIP = checkCloudflare(zoneID, authEmail, apiKey, hostToUpdate)
|
||||
else:
|
||||
storedIP = lastip
|
||||
print("Stored IP is " + lastip)
|
||||
|
||||
# Get our external IP
|
||||
ip = requests.get('https://api.ipify.org').text
|
||||
print("Our current IP is " + ip)
|
||||
if storedIP:
|
||||
if ip == storedIP:
|
||||
print("IP has not changed since last run... Exiting")
|
||||
exit(0)
|
||||
else:
|
||||
print("IP has changed since last run... Updating Cloudflare")
|
||||
storeIP(ip)
|
||||
updateCloudflare(zoneID, authEmail, apiKey, hostToUpdate, ip)
|
||||
else:
|
||||
storeIP(ip)
|
||||
if ip == cloudflareIP:
|
||||
print("Cloudflare matches our current IP... Exiting")
|
||||
exit(0)
|
||||
else:
|
||||
print("Cloudflare IP does not match our current IP... Updating Cloudflare.")
|
||||
updateCloudflare(zoneID, authEmail, apiKey, hostToUpdate, ip)
|
Reference in New Issue
Block a user