Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,46 @@ This script is used to update Dynamic DNS (DDNS) service based on Cloudflare! Ac
git clone https://github.com/K0p1-Git/cloudflare-ddns-updater.git
```

## Configuration

The scripts can be configured either by editing the configuration section inside the script or by providing environment variables.

Environment variables override values configured in the script.

### Common environment variables

| Variable | Description |
| --- | --- |
| `AUTH_EMAIL` | Cloudflare account email |
| `AUTH_METHOD` | Authentication method (`token` or `global`) |
| `AUTH_KEY` | Cloudflare API Token or Global API Key |
| `ZONE_IDENTIFIER` | Cloudflare Zone ID |
| `RECORD_NAME` | DNS record to update |
| `TTL` | DNS TTL in seconds |
| `PROXY` | Enable Cloudflare proxy (`true`/`false`) |
| `SITENAME` | Site name used in notifications |
| `SLACK_CHANNEL` | Slack notification channel |
| `SLACK_URI` | Slack webhook URL |
| `DISCORD_URI` | Discord webhook URL |

### IPv6-specific environment variables

| Variable | Description |
| --- | --- |
| `STATIC_IPV6_MODE` | Enable static IPv6 mode |
| `LAST_NOTABLE_HEXES` | IPv6 suffix pattern used in static IPv6 mode |

Example:

```bash
export AUTH_EMAIL="user@example.com"
export AUTH_KEY="your-api-token"
export ZONE_IDENTIFIER="your-zone-id"
export RECORD_NAME="home.example.com"

./cloudflare-ddns.sh
```

## Usage
This script is used with crontab. Specify the frequency of execution through crontab.

Expand Down
50 changes: 42 additions & 8 deletions cloudflare-template.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,41 @@ sitename="" # Title of site "Example Sit
slackchannel="" # Slack Channel #example
slackuri="" # URI for Slack WebHook "https://hooks.slack.com/services/xxxxx"
discorduri="" # URI for Discord WebHook "https://discordapp.com/api/webhooks/xxxxx"
log_header_name="DDNS Updater"

###########################################
## Environment variable overrides
###########################################

auth_email="${AUTH_EMAIL:-$auth_email}"
auth_method="${AUTH_METHOD:-$auth_method}"
auth_key="${AUTH_KEY:-$auth_key}"
zone_identifier="${ZONE_IDENTIFIER:-$zone_identifier}"
record_name="${RECORD_NAME:-$record_name}"
ttl="${TTL:-$ttl}"
proxy="${PROXY:-$proxy}"
sitename="${SITENAME:-$sitename}"
slackchannel="${SLACK_CHANNEL:-$slackchannel}"
slackuri="${SLACK_URI:-$slackuri}"
discorduri="${DISCORD_URI:-$discorduri}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I usually expect command-line arguments or configuration provided directly by the user to win over environment variables. Is this precedence intentional?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review. Yes, this is intentional.
The main goal of this change is to allow using the script without modifying it, especially for automated environments where configuration is provided externally.
For this reason, environment variables currently take precedence over the values defined in the script. The script values act as defaults and preserve the existing behavior for users who still configure the script directly.
That said, I'm open to changing the precedence if you prefer explicitly configured script values to have higher priority.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be my preference. Also I recognize I'm not the owner of this repository just a user. So I will defer to their judgement.


###########################################
## Validate required configuration
###########################################

required_config=(
auth_email
auth_key
zone_identifier
record_name
)

for config in "${required_config[@]}"; do
if [[ -z "${!config}" ]]; then
logger -s "$log_header_name: Missing required configuration: $config"
exit 1
fi
done

###########################################
## Check if we have a public IP
Expand All @@ -29,16 +63,16 @@ for service in ${IP_SERVICES[@]}; do
RAW_IP=$(curl -s $service)
if [[ $RAW_IP =~ $REGEX_IPV4 ]]; then
CURRENT_IP=$BASH_REMATCH
logger -s "DDNS Updater: Fetched IP $CURRENT_IP"
logger -s "$log_header_name: Fetched IP $CURRENT_IP"
break
else
logger -s "DDNS Updater: IP service $service failed."
logger -s "$log_header_name: IP service $service failed."
fi
done

# Exit if IP fetching failed
if [[ -z "$CURRENT_IP" ]]; then
logger -s "DDNS Updater: Failed to find a valid IP."
logger -s "$log_header_name: Failed to find a valid IP."
exit 2
fi

Expand All @@ -55,7 +89,7 @@ fi
## Seek for the A record
###########################################

logger "DDNS Updater: Check Initiated"
logger "$log_header_name: Check Initiated"
record=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?type=A&name=$record_name" \
-H "X-Auth-Email: $auth_email" \
-H "$auth_header $auth_key" \
Expand All @@ -65,7 +99,7 @@ record=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identi
## Check if the domain has an A record
###########################################
if [[ $record == *"\"count\":0"* ]]; then
logger -s "DDNS Updater: Record does not exist, perhaps create one first? (${CURRENT_IP} for ${record_name})"
logger -s "$log_header_name: Record does not exist, perhaps create one first? (${CURRENT_IP} for ${record_name})"
exit 1
fi

Expand All @@ -75,7 +109,7 @@ fi
old_ip=$(echo "$record" | sed -E 's/.*"content":"(([0-9]{1,3}\.){3}[0-9]{1,3})".*/\1/')
# Compare if they're the same
if [[ $CURRENT_IP == $old_ip ]]; then
logger "DDNS Updater: IP ($CURRENT_IP) for ${record_name} has not changed."
logger "$log_header_name: IP ($CURRENT_IP) for ${record_name} has not changed."
exit 0
fi

Expand All @@ -98,7 +132,7 @@ update=$(curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/$zone_iden
###########################################
case "$update" in
*"\"success\":false"*)
echo -e "DDNS Updater: $CURRENT_IP $record_name DDNS failed for $record_identifier ($CURRENT_IP). DUMPING RESULTS:\n$update" | logger -s
echo -e "$log_header_name: $CURRENT_IP $record_name DDNS failed for $record_identifier ($CURRENT_IP). DUMPING RESULTS:\n$update" | logger -s
if [[ $slackuri != "" ]]; then
curl -L -X POST $slackuri \
--data-raw '{
Expand All @@ -114,7 +148,7 @@ case "$update" in
fi
exit 1;;
*)
logger "DDNS Updater: $CURRENT_IP $record_name DDNS updated."
logger "$log_header_name: $CURRENT_IP $record_name DDNS updated."
if [[ $slackuri != "" ]]; then
curl -L -X POST $slackuri \
--data-raw '{
Expand Down
39 changes: 38 additions & 1 deletion cloudflare-templatev6.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,44 @@ slackchannel=""
slackuri=""
discorduri=""


###########################################
## Environment variable overrides
###########################################

auth_email="${AUTH_EMAIL:-$auth_email}"
auth_method="${AUTH_METHOD:-$auth_method}"
auth_key="${AUTH_KEY:-$auth_key}"
zone_identifier="${ZONE_IDENTIFIER:-$zone_identifier}"

record_name="${RECORD_NAME:-$record_name}"
ttl="${TTL:-$ttl}"
proxy="${PROXY:-$proxy}"

static_IPv6_mode="${STATIC_IPV6_MODE:-$static_IPv6_mode}"
last_notable_hexes="${LAST_NOTABLE_HEXES:-$last_notable_hexes}"

sitename="${SITENAME:-$sitename}"
slackchannel="${SLACK_CHANNEL:-$slackchannel}"
slackuri="${SLACK_URI:-$slackuri}"
discorduri="${DISCORD_URI:-$discorduri}"

###########################################
## Validate required configuration
###########################################

required_config=(
auth_email
auth_key
zone_identifier
record_name
)

for config in "${required_config[@]}"; do
if [[ -z "${!config}" ]]; then
logger -s "$log_header_name: Missing required configuration: $config"
exit 1
fi
done

################################################
## Make sure we have a valid IPv6 connection
Expand Down