A Python tool that automatically updates Cloudflare DNS records with your current public IP address. This is a simplified, user-friendly version of the original bash script.
- Automatic Discovery: Automatically finds zones and DNS records - no need to manually look up zone IDs or record IDs
- IPv4 & IPv6 Support: Automatically detects and updates both A (IPv4) and AAAA (IPv6) records
- SQLite Database: Stores all data in a SQLite database for reliable tracking and history
- Update History: Complete audit trail of all update attempts with timestamps and success/failure status
- Simple Configuration: Just list the subdomains you want to update
- IP Change Detection: Only updates DNS when your IP address changes
- Timestamped Updates: Adds timestamps to Cloudflare record comments showing when each record was last updated
- System Logging: Logs to syslog and systemd journal (when available) for easy monitoring
- Error Handling: Comprehensive error handling and logging
- Multiple Subdomains: Update multiple DNS records in a single run
pip install -r requirements.txtCreate a .env file in the ./data/ directory with your Cloudflare API credentials.
Example .env file:
# Cloudflare API Credentials
# Required: Your Cloudflare account email address
[email protected]
# Required: Your Cloudflare API key or token
# Option 1: Global API Key (found in My Profile → API Tokens)
CF_API_KEY=your-global-api-key-here
# Option 2: API Token (recommended for better security)
# Create a token with DNS:Edit permissions at:
# https://dash.cloudflare.com/profile/api-tokens
# CF_API_KEY=your-api-token-hereGetting your Cloudflare API credentials:
-
Using Global API Key (simpler, less secure):
- Log in to Cloudflare Dashboard
- Go to My Profile → API Tokens
- Scroll down to API Keys section
- Click View next to "Global API Key"
- Copy the key and paste it as
CF_API_KEYin your.envfile
-
Using API Token (recommended, more secure):
- Log in to Cloudflare Dashboard
- Go to My Profile → API Tokens
- Click Create Token
- Use the "Edit zone DNS" template or create a custom token with:
- Permissions:
Zone→DNS→Edit - Zone Resources: Include → All zones (or specific zones)
- Permissions:
- Copy the token and paste it as
CF_API_KEYin your.envfile
Security Notes:
- Never commit your
.envfile to version control - The
.envfile is already in.gitignore(if using git) - API Tokens are preferred over Global API Keys as they can be scoped to specific permissions
- Keep your API credentials secure and rotate them periodically
You have two options:
Option A: Edit core.py
subdomains_config = [
"home.example.com", # Will update both A and AAAA records if available
"vpn.example.com:A", # Only update A (IPv4) record
"server.example.com:AAAA", # Only update AAAA (IPv6) record
"api.example.com:A,AAAA", # Explicitly update both
# Add more entries as needed
]Option B: Use ./data/dnsrecords.txt
Create or edit ./data/dnsrecords.txt with one subdomain per line:
home.example.com
vpn.example.com:A
server.example.com:AAAA
api.example.com:A,AAAA
Record Type Options:
subdomain.example.com- Updates both A and AAAA records (default)subdomain.example.com:A- Only updates A (IPv4) recordsubdomain.example.com:AAAA- Only updates AAAA (IPv6) recordsubdomain.example.com:A,AAAA- Explicitly updates both record types
python3 core.pyCreate a systemd service file (e.g., /etc/systemd/system/cloudflare-dns.service):
[Unit]
Description=Cloudflare Dynamic DNS Updater
After=network.target
[Service]
Type=oneshot
User=your-username
WorkingDirectory=/path/to/cloudflare-dynamic-dns
ExecStart=/usr/bin/python3 /path/to/cloudflare-dynamic-dns/core.py
Environment="PATH=/usr/bin:/usr/local/bin"
[Install]
WantedBy=multi-user.targetCreate a timer to run it periodically (e.g., /etc/systemd/system/cloudflare-dns.timer):
[Unit]
Description=Run Cloudflare DNS updater every 5 minutes
Requires=cloudflare-dns.service
[Timer]
OnBootSec=1min
OnUnitActiveSec=5min
[Install]
WantedBy=timers.targetEnable and start the timer:
sudo systemctl enable cloudflare-dns.timer
sudo systemctl start cloudflare-dns.timer- The script automatically detects your current public IPv4 and IPv6 addresses
- For each configured subdomain:
- Automatically finds the Cloudflare zone
- Locates the DNS A and/or AAAA records (based on configuration)
- Compares the current IP with the DNS record value
- Updates the record if the IP has changed
- Adds a timestamped comment to the Cloudflare record showing when it was updated
- Stores all data in a SQLite database (
./data/cloudflare_dns.db):- Last known IP addresses for each subdomain/record type
- Complete update history with timestamps
- Success/failure tracking
- Logs all activities to syslog/systemd journal for monitoring
The script uses SQLite to store data in ./data/cloudflare_dns.db. The database includes:
-
last_ips: Stores the last known IP address for each subdomain and record type
subdomain: The subdomain namerecord_type: A or AAAAip: The last known IP addressupdated_at: Timestamp of last update
-
update_history: Complete history of all update attempts
subdomain: The subdomain namerecord_type: A or AAAAold_ip: Previous IP address (if known)new_ip: New IP addressupdated_at: Timestamp of the updatesuccess: Whether the update was successful (1 or 0)error_message: Error message if the update failed
You can query the database using any SQLite client:
# View last known IPs
sqlite3 ./data/cloudflare_dns.db "SELECT * FROM last_ips;"
# View recent update history
sqlite3 ./data/cloudflare_dns.db "SELECT * FROM update_history ORDER BY updated_at DESC LIMIT 10;"
# View failed updates
sqlite3 ./data/cloudflare_dns.db "SELECT * FROM update_history WHERE success = 0;"
# Get statistics
sqlite3 ./data/cloudflare_dns.db "SELECT COUNT(*) as total, SUM(success) as successful, SUM(1-success) as failed FROM update_history;"The database is automatically created on first run and requires no additional configuration.
The script automatically logs to:
- Console/STDOUT: Human-readable output
- Syslog: Available on Unix-like systems (Linux, macOS, etc.)
- Systemd Journal: Available on systemd-based Linux systems (if
systemdPython package is installed)
View logs with:
# Systemd journal
journalctl -u cloudflare-dns.service -f
# Syslog (varies by system)
tail -f /var/log/syslog | grep cloudflare-dynamic-dns
# or
tail -f /var/log/messages | grep cloudflare-dynamic-dnsThe script automatically detects your public IPv6 address if available. If IPv6 is not available, the script will:
- Skip AAAA record updates for that subdomain
- Log a warning message
- Continue processing other records
IPv6 detection uses multiple services for reliability:
- Primary:
ipv6.icanhazip.com - Fallback:
api64.ipify.org
- Python 3.6+
requestslibrarypython-dotenvlibrarysystemdlibrary (optional, for systemd journal logging on Linux)sqlite3(included with Python standard library)
See requirements.txt for details.
Optional: For systemd journal logging on Linux systems:
pip install systemd- Make sure the subdomain exists in Cloudflare
- Verify the subdomain is spelled correctly
- Ensure you have the correct API permissions
- Check your internet connection
- The IP service (ip.me) might be temporarily unavailable
- Verify your API credentials are correct
- Check that your API token has DNS:Edit permissions
- Ensure the subdomain belongs to a zone in your Cloudflare account
See LICENSE file for details.