Created
February 22, 2025 22:59
-
-
Save stypr/b6fe79891f82e3b656c00bb7fa1df446 to your computer and use it in GitHub Desktop.
Cloudflare 4.0.0 Automatic DDNS renewal
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 -u | |
# make sure to set crontab | |
# 0 0 * * * python3 /root/cf.py | |
import sys | |
import logging | |
from collections import Counter | |
import requests | |
import cloudflare | |
# Configure logging | |
logging.basicConfig( | |
level=logging.INFO, | |
format="%(asctime)s - %(levelname)s - %(message)s" | |
) | |
HEADERS = {"User-Agent": "curl/7.88.1"} | |
def get_ip_address(timeout=3): | |
""" | |
Retrieve the public IP address by querying multiple external services. | |
Returns the IP address that appears most frequently among the sources. | |
Raises a RuntimeError if no IP address can be obtained. | |
""" | |
url_list = [ | |
"https://ifconfig.me/ip", | |
"https://ipinfo.io/ip", | |
"https://ipecho.net/plain", | |
"https://icanhazip.com/", | |
"https://ident.me/", | |
"https://checkip.amazonaws.com/", | |
"http://whatismyip.akamai.com/", | |
"https://myexternalip.com/raw" | |
] | |
ips = [] | |
for url in url_list: | |
try: | |
response = requests.get(url, headers=HEADERS, timeout=timeout) | |
response.raise_for_status() | |
ip = response.text.strip() | |
ips.append(ip) | |
logging.info("Fetched IP from %s: %s", url, ip) | |
except requests.RequestException as e: | |
logging.warning("Error fetching IP from %s: %s", url, e) | |
if not ips: | |
raise RuntimeError("Failed to obtain IP address from all sources") | |
ip_counter = Counter(ips) | |
most_common_ip, _ = ip_counter.most_common(1)[0] | |
return most_common_ip | |
def set_ip_address(api_token, zone_name, target_domain_name, current_ip): | |
""" | |
Update the DNS record for the target domain using the Cloudflare API. | |
Parameters: | |
api_token (str): Cloudflare API token. | |
zone_name (str): The DNS zone name (e.g., 'stypr.com'). | |
target_domain_name (str): The full domain name to update. | |
current_ip (str): The IP address to set. | |
Returns: | |
tuple: (status, message) where status 0 indicates success and -1 indicates an error. | |
""" | |
cf = cloudflare.Cloudflare(api_token=api_token) | |
# Find the target zone id | |
target_zone_id = None | |
for zone in cf.zones.list(): | |
if zone.name == zone_name: | |
target_zone_id = zone.id | |
break | |
if not target_zone_id: | |
return (-1, f"Zone {zone_name} not found") | |
# Find the DNS record for the target domain | |
dns_records = cf.dns.records.list(zone_id=target_zone_id) | |
dns_records_found = None | |
for record in dns_records: | |
if record.name == target_domain_name: | |
dns_records_found = record | |
break | |
if not dns_records_found: | |
return(-1, f"DNS record for {target_domain_name} not found") | |
if dns_records_found.content == current_ip: | |
return(0, "IP not changed") | |
cf.dns.records.update( | |
zone_id=target_zone_id, | |
dns_record_id=dns_records_found.id, | |
type=dns_records_found.type, | |
name=dns_records_found.name, | |
content=current_ip | |
) | |
return (0, f"IP changed to {current_ip}") | |
def main(api_token, zone_name, target_domain): | |
""" | |
Runs main | |
""" | |
try: | |
current_ip = get_ip_address() | |
logging.info("Current IP: %s", current_ip) | |
except Exception as e: | |
logging.error("Failed to retrieve IP address: %s", e) | |
return 1 | |
status, message = set_ip_address( | |
api_token, | |
zone_name, | |
target_domain, | |
current_ip | |
) | |
logging.info("DNS Update Result: %s - %s", status, message) | |
sys.exit(status) | |
if __name__ == "__main__": | |
# API Token can be retrieved from dash.cloudflare.com. | |
# Edit:DNS should be enough. | |
API_TOKEN = "___" | |
ZONE_NAME = "example.com" | |
TARGET_DOMAIN = "sub.example.com" | |
# Run Main | |
sys.exit(main(API_TOKEN, ZONE_NAME, TARGET_DOMAIN)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment