import requests import json import os # --- CONFIGURATION --- # Set these via environment variables or edit directly before use ZONE_ID = os.getenv("CF_ZONE_ID", "YOUR_ZONE_ID_HERE") API_TOKEN = os.getenv("CF_API_TOKEN", "YOUR_API_TOKEN_HERE") # --------------------- BASE_URL = "https://api.cloudflare.com/client/v4" HEADERS = { "Authorization": f"Bearer {API_TOKEN}", "Content-Type": "application/json" } def validate_config(): """Validates that credentials are configured""" if ZONE_ID == "YOUR_ZONE_ID_HERE" or not ZONE_ID: print("ERROR: Cloudflare Zone ID not configured!") print("Set CF_ZONE_ID environment variable or edit ZONE_ID in this script") print("Example: export CF_ZONE_ID='your_zone_id_here'") return False if API_TOKEN == "YOUR_API_TOKEN_HERE" or not API_TOKEN: print("ERROR: Cloudflare API Token not configured!") print("Set CF_API_TOKEN environment variable or edit API_TOKEN in this script") print("Example: export CF_API_TOKEN='your_token_here'") return False return True def get_paged_data(endpoint): """Generic function to handle pagination for lists (like DNS records)""" url = f"{BASE_URL}/{endpoint}" items = [] page = 1 while True: params = {'page': page, 'per_page': 100} try: response = requests.get(url, headers=HEADERS, params=params) response.raise_for_status() data = response.json() if not data['success']: print(f"Error fetching {endpoint}: {data['errors']}") break current_batch = data['result'] if not current_batch: break items.extend(current_batch) # Check pagination info if it exists if 'result_info' in data and page < data['result_info']['total_pages']: page += 1 else: break except Exception as e: print(f"Request failed for {endpoint}: {e}") break return items def get_zone_settings(zone_id): """Fetches key SSL and Network settings""" print(f"Fetching Zone Settings for {zone_id}...") url = f"{BASE_URL}/zones/{zone_id}/settings" try: response = requests.get(url, headers=HEADERS) response.raise_for_status() data = response.json() if not data['success']: print(f"Error fetching settings: {data['errors']}") return {} # We convert the list of settings into a dictionary for easier reading # The API returns a list like [{"id": "ssl", "value": "strict"}, ...] settings_map = {item['id']: item['value'] for item in data['result']} # Filter for the ones that actually matter for Homelabs relevant_keys = [ "ssl", # The encryption mode (off, flexible, full, strict) "always_use_https", # Force HTTPS redirect "min_tls_version", # Can break old hardware/OS "security_level", # "I'm Under Attack" mode breaks APIs "pseudo_ipv4", # Header modification "websockets", # Critical for some apps "cname_flattening" # DNS behavior ] return {k: settings_map.get(k, "UNKNOWN") for k in relevant_keys} except Exception as e: print(f"Failed to fetch settings: {e}") return {} def main(): # Validate configuration first if not validate_config(): return # 1. Fetch DNS Records print("Fetching DNS Records...") raw_dns = get_paged_data(f"zones/{ZONE_ID}/dns_records") clean_dns = [] for r in raw_dns: clean_dns.append({ "name": r.get("name"), "type": r.get("type"), "content": r.get("content"), "proxied": r.get("proxied"), "ttl": r.get("ttl") }) # 2. Fetch Zone Settings (SSL, etc.) zone_settings = get_zone_settings(ZONE_ID) # 3. Combine into one object full_export = { "metadata": { "zone_id": ZONE_ID, "export_date": "Now" }, "zone_settings": zone_settings, "dns_records": clean_dns } filename = "cloudflare_full_config.json" with open(filename, 'w') as f: json.dump(full_export, f, indent=2) print(f"\nSuccess! Configuration saved to {filename}") print(f"Found {len(clean_dns)} DNS records.") print(f"SSL Mode detected: {zone_settings.get('ssl', 'unknown')}") if __name__ == "__main__": main()