Oups the script was not complete :( Here an updated version :)
#!/var/www/cloudflare/venv/bin/python3
# -*- coding: utf-8 -*-
import requests
import json
import re
import os
# Cloudflare API settings
API_TOKEN = 'my_api_token'
ZONE_ID = 'my_zone_id'
# TTL constant (120 = "Auto" on Cloudflare)
AUTO = 120
# DNS records to update
RECORDS_TO_UPDATE = [
{'name': 'domain.org', 'type': 'A', 'proxied': True, 'ttl': AUTO},
{'name': '*.domain.org', 'type': 'A', 'proxied': True, 'ttl': AUTO},
{'name': 'minecraft.domain.org', 'type': 'A', 'proxied': False, 'ttl': AUTO}
]
# API headers
HEADERS = {
'Authorization': f'Bearer {API_TOKEN}',
'Content-Type': 'application/json',
}
# File path to store last known IP
LAST_IP_FILE = os.path.join(os.path.dirname(__file__), 'last_ip.txt')
def get_public_ip():
"""Fetch current public IP from checkip.dyndns.org"""
try:
response = requests.get("http://checkip.dyndns.org/")
ip = re.search(r"Current IP Address: ([\d.]+)", response.text).group(1)
return ip
except Exception as e:
raise RuntimeError(f"Failed to detect public IP: {e}")
def load_last_ip():
"""Read the last saved public IP address"""
try:
with open(LAST_IP_FILE, 'r') as f:
return f.read().strip()
except FileNotFoundError:
return None
def save_current_ip(ip):
"""Save the current public IP address"""
with open(LAST_IP_FILE, 'w') as f:
f.write(ip)
def get_all_dns_records():
"""Fetch all DNS records in the Cloudflare zone"""
url = f'https://api.cloudflare.com/client/v4/zones/{ZONE_ID}/dns_records'
response = requests.get(url, headers=HEADERS)
if response.status_code != 200:
raise RuntimeError(f"Failed to fetch DNS records: {response.text}")
return response.json().get('result', [])
def update_dns_record(record_id, name, record_type, proxied, ttl, new_ip):
"""Update a DNS record on Cloudflare"""
url = f'https://api.cloudflare.com/client/v4/zones/{ZONE_ID}/dns_records/{record_id}'
payload = { 'type': record_type, 'name': name, 'content': new_ip, 'ttl': ttl, 'proxied': proxied }
response = requests.put(url, headers=HEADERS, data=json.dumps(payload))
if response.status_code == 200:
print(f"✅ Updated {name} to {new_ip}")
else:
raise RuntimeError(f"Failed to update {name}: {response.text}")
def main():
# Output HTTP header (for CGI)
print('Content-Type: text/plain; charset=utf-8\n')
try:
current_ip = get_public_ip()
last_ip = load_last_ip()
print(f"🌍 Current Public IP: {current_ip}")
if current_ip == last_ip:
print("⏸️ Public IP has not changed. Skipping update.")
return
all_records = get_all_dns_records()
record_id_map = {(rec['name'], rec['type']): rec['id'] for rec in all_records}
all_success = True
for record in RECORDS_TO_UPDATE:
key = (record['name'], record['type'])
record_id = record_id_map.get(key)
if not record_id:
print(f"⚠️ No record ID found for {record['name']} ({record['type']})")
all_success = False
continue
try:
update_dns_record(record_id, record['name'], record['type'], record['proxied'], record['ttl'], current_ip)
except Exception as e:
print(f"❌ Failed to update {record['name']}: {e}")
all_success = False
if all_success:
save_current_ip(current_ip)
print("✅ All records updated successfully. IP saved.")
else:
print("⚠️ Some updates failed. IP not saved to ensure retry next time.")
except Exception as e:
print(f"🚫 Script failed: {e}")
if __name__ == '__main__':
main()