đ Executive Summary
TL;DR: Manual DNS record updates are a significant bottleneck in dynamic environments, leading to potential downtime and errors. This guide provides a robust, automated solution using a Python script and the Cloudflare API to detect and update âAâ records, ensuring domains always point to the correct public IP address.
đŻ Key Takeaways
- Secure API interaction is crucial: Use Cloudflareâs scoped API Tokens with minimal permissions (Zone:Zone:Read, Zone:DNS:Edit) and store credentials securely via environment variables.
- The Python scriptâs core logic involves fetching the current public IP (e.g., from api.ipify.org), retrieving the existing Cloudflare âAâ record, comparing the IPs, and updating the record via a Cloudflare API PUT request if a change is detected.
- Automation is achieved by scheduling the Python script using a cron job, ensuring the necessary environment variables (CF_API_TOKEN, CF_ZONE_ID, CF_DNS_RECORD_NAME) are defined within the cron entry for reliable execution at regular intervals.
Automating DNS Record Updates on Cloudflare using Python API
Introduction
In modern infrastructure, managing DNS records can be a repetitive and error-prone task, especially in dynamic environments where IP addresses change frequently. Whether youâre running a home server with a dynamic public IP, managing ephemeral staging environments, or simply aiming for infrastructure-as-code principles, manual DNS updates are a bottleneck. This process is not only tedious but also introduces a risk of downtime if an IP changes and the corresponding DNS record isnât updated promptly.
This tutorial solves that problem. We will walk you through building a robust, automated solution using Python and the powerful Cloudflare API. By the end, youâll have a script that can automatically detect your serverâs public IP address and update a specified Cloudflare DNS âAâ record, ensuring your domain always points to the correct location. This âset-it-and-forget-itâ approach saves time, enhances reliability, and is a foundational skill for any DevOps professional.
Prerequisites
Before we begin, ensure you have the following ready:
- A Cloudflare Account: You must have an active Cloudflare account with at least one domain name configured.
-
Python 3: Your system should have Python 3 installed. You can check this by running
python3 --version. -
Python
requestsLibrary: This library is essential for making HTTP requests to the Cloudflare API. We will install it in Step 2. - Administrative Access: Youâll need access to a terminal or command line on the machine whose public IP you want to track.
Step-by-Step Guide
Follow these steps to create and deploy your automated DNS updater.
Step 1: Obtain Your Cloudflare API Credentials
To interact with the Cloudflare API, you need three key pieces of information: your API Token, your Zone ID, and the DNS Record ID you wish to update.
1. Create an API Token:
For security, weâll create a scoped API Token instead of using the global API Key. This limits the scriptâs permissions to only what is necessary.
- Log in to your Cloudflare dashboard.
- Navigate to âMy Profileâ > âAPI Tokensâ.
- Click âCreate Tokenâ and use the âCreate Custom Tokenâ template.
- Give your token a descriptive name, like âDynamic DNS Updaterâ.
- Under âPermissionsâ, grant the following two permissions:
- Zone > Zone > Read
- Zone > DNS > Edit
- Under âZone Resourcesâ, select the specific zone (your domain) that you want this token to manage.
- Click âContinue to summaryâ and then âCreate Tokenâ.
Important: Cloudflare will show you the token only once. Copy it immediately and store it securely. We will use an environment variable to manage it.
2. Find Your Zone ID:
The Zone ID uniquely identifies your domain within Cloudflare. You can find it on the âOverviewâ page of your selected domain in the Cloudflare dashboard, on the right-hand side under the âAPIâ section.
3. Store Credentials Securely:
Never hardcode secrets in your script. We will use environment variables. Set them in your terminal session for now. We will make this permanent for automation later.
# Bash Script
export CF_API_TOKEN="your_copied_api_token_here"
export CF_ZONE_ID="your_zone_id_here"
export CF_DNS_RECORD_NAME="subdomain.yourdomain.com"
Step 2: Setting Up Your Python Environment
First, create a dedicated directory for your project and navigate into it. Itâs a best practice to use a Python virtual environment to manage dependencies and avoid conflicts.
# Bash Script
mkdir cloudflare_updater
cd cloudflare_updater
python3 -m venv venv
source venv/bin/activate
With the virtual environment active, install the requests library:
# Bash Script
python3 -m pip install requests
Step 3: Crafting the Python Update Script
Now, letâs write the core logic. Create a file named update_dns.py in your project directory and add the following code. The script is heavily commented to explain each part of the process.
# Python Script
import os
import requests
import json
import sys
# --- Configuration ---
# Load credentials and settings from environment variables for security.
API_TOKEN = os.getenv("CF_API_TOKEN")
ZONE_ID = os.getenv("CF_ZONE_ID")
RECORD_NAME = os.getenv("CF_DNS_RECORD_NAME")
# --- Validation ---
# Ensure all required configuration is present.
if not all([API_TOKEN, ZONE_ID, RECORD_NAME]):
print("Error: Missing required environment variables (CF_API_TOKEN, CF_ZONE_ID, CF_DNS_RECORD_NAME)")
sys.exit(1)
# --- API Setup ---
API_BASE_URL = f"https://api.cloudflare.com/client/v4/zones/{ZONE_ID}"
HEADERS = {
"Authorization": f"Bearer {API_TOKEN}",
"Content-Type": "application/json"
}
def get_public_ip():
"""Fetches the current public IP address from an external service."""
try:
response = requests.get("https://api.ipify.org?format=json", timeout=10)
response.raise_for_status()
return response.json()["ip"]
except requests.RequestException as e:
print(f"Error fetching public IP: {e}")
return None
def get_dns_record(record_name):
"""Fetches a specific DNS record from Cloudflare."""
try:
url = f"{API_BASE_URL}/dns_records?type=A&name={record_name}"
response = requests.get(url, headers=HEADERS, timeout=10)
response.raise_for_status()
records = response.json().get("result", [])
return records[0] if records else None
except requests.RequestException as e:
print(f"Error fetching DNS record: {e}")
return None
def update_dns_record(record_id, new_ip):
"""Updates the IP address for a given DNS record ID."""
try:
url = f"{API_BASE_URL}/dns_records/{record_id}"
payload = {
"type": "A",
"name": RECORD_NAME,
"content": new_ip,
"ttl": 1 # 1 = Automatic TTL
}
response = requests.put(url, headers=HEADERS, data=json.dumps(payload), timeout=10)
response.raise_for_status()
print(f"Successfully updated DNS record for {RECORD_NAME} to {new_ip}")
return True
except requests.RequestException as e:
print(f"Error updating DNS record: {e} - {e.response.text}")
return False
def main():
"""Main logic to check and update the DNS record if necessary."""
print("--- Starting DNS Update Check ---")
public_ip = get_public_ip()
if not public_ip:
return # Exit if we can't get the public IP
print(f"Current public IP: {public_ip}")
dns_record = get_dns_record(RECORD_NAME)
if not dns_record:
print(f"Error: DNS record for '{RECORD_NAME}' not found.")
return
current_dns_ip = dns_record["content"]
record_id = dns_record["id"]
print(f"Current DNS IP for {RECORD_NAME}: {current_dns_ip}")
if public_ip == current_dns_ip:
print("IP addresses match. No update needed.")
else:
print("IP addresses do not match. Initiating update...")
update_dns_record(record_id, public_ip)
print("--- DNS Update Check Finished ---")
if __name__ == "__main__":
main()
Step 4: Automating the Script with Cron
To make this truly automated, we need to schedule the script to run at regular intervals. A cron job is perfect for this task. Weâll set it to run every 5 minutes.
First, find the full path to your python executable within the virtual environment and the script itself.
# Bash Script
# In your project directory
which python3
pwd
This will give you paths like /home/user/cloudflare_updater/venv/bin/python3 and /home/user/cloudflare_updater.
Now, open your cron editor:
# Open your cron editor
crontab -e
Add the following line to the file. This line defines the necessary environment variables directly, ensuring the script can access them, and then executes the script. Replace the paths with the ones you found.
# Cron Job Example
CF_API_TOKEN="your_copied_api_token_here"
CF_ZONE_ID="your_zone_id_here"
CF_DNS_RECORD_NAME="subdomain.yourdomain.com"
*/5 * * * * /home/user/cloudflare_updater/venv/bin/python3 /home/user/cloudflare_updater/update_dns.py
Save and exit the editor. The cron daemon will now execute your script every five minutes, keeping your DNS record perfectly in sync with your public IP.
Common Pitfalls
If you run into issues, check these common problems first:
-
Insufficient API Token Permissions: A
403 Forbiddenerror from the API almost always means your API Token lacks the required permissions. Double-check that it has both âZone:Zone:Readâ and âZone:DNS:Editâ permissions for the correct zone. Regenerate the token if necessary. -
Incorrect Zone ID or Record Name: A
404 Not Founderror or the script reporting that the record canât be found usually points to a typo in yourCF\_ZONE\_IDorCF\_DNS\_RECORD\_NAMEenvironment variables. Ensure the record name is the fully qualified domain name (e.g.,subdomain.yourdomain.com, not justsubdomain).
Conclusion
Congratulations! You have successfully built a fully automated Dynamic DNS (DDNS) client using Python and the Cloudflare API. This script not only solves a practical problem but also serves as an excellent foundation for more advanced infrastructure automation. Youâve learned how to securely interact with a powerful API, manage credentials safely, and schedule tasks for reliable execution.
From here, you can expand the scriptâs capabilities. Consider adding more robust logging to a file, sending email or Slack notifications on failures, or adapting it to update other record types like AAAA for IPv6. This simple yet powerful automation is a key step toward managing your infrastructure as code.
đ Read the original article on TechResolve.blog
â Support my work
If this article helped you, you can buy me a coffee:

Top comments (0)