Public release
Added removal of stable, duplicate records per subdomain.
This commit is contained in:
parent
b687c40314
commit
9487784876
59
README.md
Executable file
59
README.md
Executable file
@ -0,0 +1,59 @@
|
||||
# :rocket: Cloudflare DDNS
|
||||
|
||||
Dynamic DNS service based on Cloudflare! Access your home network remotely via a custom domain name without a static IP!
|
||||
|
||||
## :us: Origin
|
||||
|
||||
This script was written for the Raspberry Pi platform to enable low cost, simple self hosting to promote a more decentralized internet. On execution, the script fetches public IPv4 and IPv6 addresses and creates/updates DNS records for the subdomains in Cloudflare. Stale, duplicate DNS records are removed for housekeeping.
|
||||
|
||||
## :vertical_traffic_light: Getting Started
|
||||
|
||||
Edit config.json and replace the values with your own.
|
||||
|
||||
Values explained:
|
||||
|
||||
```json
|
||||
"api_key": "Your cloudflare API Key",
|
||||
"account_email": "The email address you use to sign in to cloudflare",
|
||||
"zone_id": "The ID of the zone that will get the records. From your dashboard click into the zone. Under the overview tab, scroll down and the zone ID is listed in the right rail",
|
||||
"subdomains": "Array of subdomaind you want to assign the IP(s) to (e.g. pi.example.com)",
|
||||
"proxied": false (defaults to false. Make it true if you want CDN/SSL benefits from cloudflare. This usually disables SSH)
|
||||
```
|
||||
|
||||
## :running: Running
|
||||
|
||||
This script requires Python 3.5+, which comes preinstalled on the latest version of Raspbian. Download/clone this repo and execute `./sync`, which will set up a virtualenv, pull in any dependencies, and fire the script.
|
||||
|
||||
## :alarm_clock: Scheduling
|
||||
|
||||
This script was written with the intention of cron managing it.
|
||||
|
||||
## :penguin: Linux instructions (all distros)
|
||||
|
||||
1. Upload the cloudflare-ddns folder to your home directory /home/your_username_here/
|
||||
|
||||
2. Run the following code in terminal
|
||||
|
||||
```bash
|
||||
crontab -e
|
||||
```
|
||||
|
||||
3. Add the following lines to sync your DNS records every 15 minutes
|
||||
|
||||
```bash
|
||||
*/15 * * * * /home/your_username_here/cloudflare-ddns/sync
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This Template is licensed under the GNU General Public License, version 3 (GPLv3) and is distributed free of charge.
|
||||
|
||||
## Author
|
||||
|
||||
Timothy Miller
|
||||
|
||||
GitHub: https://github.com/timothymiller 💡
|
||||
|
||||
Website: https://timknowsbest.com 💻
|
||||
|
||||
Donation: https://timknowsbest.com/donate 💸
|
||||
98
cloudflare-ddns.py
Executable file
98
cloudflare-ddns.py
Executable file
@ -0,0 +1,98 @@
|
||||
import requests
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
|
||||
PATH = os.getcwd() + "/"
|
||||
version = float(str(sys.version_info[0]) + "." + str(sys.version_info[1]))
|
||||
|
||||
if(version < 3.5):
|
||||
raise Exception("This script requires Python 3.5+")
|
||||
|
||||
with open(PATH + "config.json") as config_file:
|
||||
config = json.loads(config_file.read())
|
||||
|
||||
|
||||
def getIPs():
|
||||
a = requests.get("https://api.ipify.org?format=json").json().get("ip")
|
||||
aaaa = requests.get("https://api6.ipify.org?format=json").json().get("ip")
|
||||
ips = []
|
||||
|
||||
if(a.find(".") > -1):
|
||||
ips.append({
|
||||
"type": "A",
|
||||
"ip": a
|
||||
})
|
||||
|
||||
if(aaaa.find(":") > -1):
|
||||
ips.append({
|
||||
"type": "AAAA",
|
||||
"ip": aaaa
|
||||
})
|
||||
|
||||
return ips
|
||||
|
||||
|
||||
def commitRecord(ip):
|
||||
stale_record_ids = []
|
||||
for c in config["cloudflare"]:
|
||||
subdomains = c["subdomains"]
|
||||
response = cf_api("zones/" + c['zone_id'], "GET", c)
|
||||
base_domain_name = response["result"]["name"]
|
||||
for subdomain in subdomains:
|
||||
exists = False
|
||||
record = {
|
||||
"type": ip["type"],
|
||||
"name": subdomain,
|
||||
"content": ip["ip"],
|
||||
"proxied": c["proxied"]
|
||||
}
|
||||
list = cf_api("zones/" + c['zone_id'] + "/dns_records&per_page=100?type=" + ip["type"], "GET", c)
|
||||
full_subdomain = subdomain + "." + base_domain_name
|
||||
dns_id = ""
|
||||
for r in list["result"]:
|
||||
if (r["name"] == full_subdomain):
|
||||
exists = True
|
||||
if (r["content"] != ip["ip"]):
|
||||
if (dns_id == ""):
|
||||
dns_id = r["id"]
|
||||
else:
|
||||
stale_record_ids.append(r["id"])
|
||||
if(exists == False):
|
||||
print("Adding new record " + str(record))
|
||||
response = cf_api(
|
||||
"zones/" + c['zone_id'] + "/dns_records", "POST", c, {}, record)
|
||||
elif(dns_id != ""):
|
||||
# Only update if the record content is different
|
||||
print("Updating record " + str(record))
|
||||
response = cf_api(
|
||||
"zones/" + c['zone_id'] + "/dns_records/" + dns_id, "PUT", c, {}, record)
|
||||
|
||||
# Delete duplicate, stale records
|
||||
for identifier in stale_record_ids:
|
||||
print("Deleting stale record " + str(identifier))
|
||||
response = cf_api("zones/" + c['zone_id'] + "/dns_records/" + identifier, "DELETE", c)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def cf_api(endpoint, method, config, headers={}, data=False):
|
||||
headers = {
|
||||
"X-Auth-Email": config['account_email'],
|
||||
"X-Auth-Key": config['api_key'],
|
||||
**headers
|
||||
}
|
||||
|
||||
if(data == False):
|
||||
response = requests.request(
|
||||
method, "https://api.cloudflare.com/client/v4/" + endpoint, headers=headers)
|
||||
else:
|
||||
response = requests.request(
|
||||
method, "https://api.cloudflare.com/client/v4/" + endpoint, headers=headers, json=data)
|
||||
|
||||
return response.json()
|
||||
|
||||
|
||||
for ip in getIPs():
|
||||
print("Checking " + ip["type"] + " records")
|
||||
commitRecord(ip)
|
||||
14
config.json
Executable file
14
config.json
Executable file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"cloudflare": [
|
||||
{
|
||||
"api_key": "api_key_here",
|
||||
"account_email": "your_email_here",
|
||||
"zone_id": "your_zone_id_here",
|
||||
"subdomains": [
|
||||
"one.example.com",
|
||||
"two.example.com"
|
||||
],
|
||||
"proxied": false
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user