Cloudflare DDNS
This guide provides a detailed explanation of how to set up Cloudflare Dynamic DNS (DDNS) for your self-hosted server. By following these steps, you’ll be able to maintain a consistent connection to your server, even if your IP address changes.
Note: If you’re interested in creating a live website, please refer to my separate article on Nginx Manager for guidance.
1. Setting up Cloudflare:
- Sign up for a Cloudflare account if you don’t have one.
- Add your domain to Cloudflare and update your nameservers.
2. Getting Cloudflare Zone ID:
- Log in to your Cloudflare dashboard.
- Select your domain.
- On the overview page, scroll down to the “API” section.
- Your Zone ID will be displayed there.
3. Creating Cloudflare API Token:
- Go to your Cloudflare dashboard.
- Click on “My Profile” in the top right corner.
- Select “API Tokens” from the left sidebar.
- Click “Create Token”.
- Use the “Edit zone DNS” template or create a custom token with the following permissions:
- Zone - DNS - Edit
- Zone - Zone - Read
- Set the zone resources to include your specific domain.
- Create the token and copy it for later use.
4. Adding DNS Records:
- In your Cloudflare dashboard, go to the “DNS” tab.
- Click “Add record”.
- For the root domain:
- Type: A
- Name: @
- IPv4 address: Your current IP (you can use a placeholder for now)
- For subdomains:
- Type: A
- Name: your subdomain (e.g., “blog” for blog.yourdomain.com)
- IPv4 address: Your current IP (you can use a placeholder for now)
- Repeat for all desired subdomains.
5. Setting up the DDNS script:
This script offers the following benefits:
- All DDNS-related files are contained within the
$HOME/.ddns/
directory. - The script automatically creates the `.ddns
- Getting the current IP:
The script uses
curl -s http://ipv4.icanhazip.com
to get the current IP. Alternatives include:curl -s https://api.ipify.org
dig +short myip.opendns.com @resolver1.opendns.com
- Running the script:
- Save the script to a file, e.g.,
ddns.sh
- Save the script to a file, e.g.,
#!/bin/bash
# Set the base directory
DDNS_DIR="$HOME/.ddns"
# Ensure the DDNS directory exists
mkdir -p "$DDNS_DIR"
# Load environment variables
source "$DDNS_DIR/.env"
# Cloudflare settings
ZONE_ID="${CF_ZONE_ID}"
API_TOKEN="${CF_API_TOKEN}"
DOMAIN="${CF_DOMAIN}"
SUBDOMAINS=(${CF_SUBDOMAINS})
# Log file location
LOG_FILE="$DDNS_DIR/ddns.log"
# Function to log messages
log_message() {
echo "$(date): $1" >> "$LOG_FILE"
}
# Fetch the current public IP
CURRENT_IP=$(curl -s http://ipv4.icanhazip.com)
if [ -z "$CURRENT_IP" ]; then
log_message "ERROR: Failed to obtain current public IP."
exit 1
fi
# Function to update DNS record
update_dns_record() {
local record_name=$1
local record_id=$2
local ip=$3
UPDATE_RESPONSE=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$record_id" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
--data "{\"type\":\"A\",\"name\":\"$record_name\",\"content\":\"$ip\"}")
if echo $UPDATE_RESPONSE | jq -e '.success'; then
log_message "DNS record for $record_name updated successfully to $ip."
else
log_message "ERROR: Failed to update DNS record for $record_name."
log_message "Response: $UPDATE_RESPONSE"
fi
}
# Process each subdomain
for subdomain in "${SUBDOMAINS[@]}"; do
FULL_DOMAIN="$subdomain.$DOMAIN"
log_message "Processing $FULL_DOMAIN..."
# Fetch the existing DNS record ID
RECORD_RESPONSE=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?type=A&name=$FULL_DOMAIN" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json")
RECORD_ID=$(echo $RECORD_RESPONSE | jq -r '.result[0].id')
EXISTING_IP=$(echo $RECORD_RESPONSE | jq -r '.result[0].content')
if [ -z "$RECORD_ID" ] || [ -z "$EXISTING_IP" ]; then
log_message "ERROR: Failed to fetch existing DNS record for $FULL_DOMAIN."
continue
fi
# Compare and update if necessary
if [ "$CURRENT_IP" != "$EXISTING_IP" ]; then
update_dns_record $FULL_DOMAIN $RECORD_ID $CURRENT_IP
else
log_message "IP has not changed for $FULL_DOMAIN. No update required."
fi
done
Now, you need to create a .env
file in the $HOME/.ddns/
directory ($HOME/.ddns/.env
) with the following content:
CF_ZONE_ID='your_zone_id_here'
CF_API_TOKEN='your_api_token_here'
CF_DOMAIN='yourdomain.com'
CF_SUBDOMAINS='subdomain1 subdomain2 subdomain3'
Make it executable:
chmod +x ddns.sh
Run the script:
./ddns.sh
Automating the script: To run the script automatically, you can add it to your crontab:
- Open the crontab editor:
crontab -e
- Add a line to run the script every 5 minutes (adjust as needed):
*/5 * * * * /path/to/your/ddns.sh
- Open the crontab editor:
Checking the logs: You can view the log file to see the script’s activity:
cat $HOME/.ddns/ddns.log
This setup allows you to easily update multiple subdomains with your current IP address, keeping your dynamic DNS records up to date with Cloudflare.