Skip to content

Commit

Permalink
update to latest cf ddns
Browse files Browse the repository at this point in the history
  • Loading branch information
Your Name committed Jan 21, 2024
1 parent bc0d7ce commit 9036ff4
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 153 deletions.
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ ENV USE_LETSENCRYPT '1'
ENV USE_CLOUDFLARE_DDNS '1'
ENV USE_DKIM_PARSING '1'
RUN apt-get update -y \
&& apt-get install --no-install-recommends -y curl cron &&\
&& apt-get install --no-install-recommends -y curl cron bind9-host &&\
apt-get clean &&\
mkdir -p /etc/crontabs &&\
echo "*/10 * * * * sleep \$((\`od -vAn -N2 -tu2 < /dev/urandom\` %300)) ; /update-cloudflare-dns.sh" >> /etc/crontabs/root &&\
Expand All @@ -20,4 +20,5 @@ RUN chmod ugo+x /update-cloudflare-dns.sh \
&& chmod ugo+x /docker-init.db/dkim-parsing.sh \
&& chmod ugo+x /docker-init.db/init-cloudflare.sh \
&& chmod ugo+x /docker-init.db/init-letsencrypt.sh
RUN curl https://get.acme.sh | sh
RUN curl https://get.acme.sh | sh \
&& mv /root/.acme.sh/acme.sh /usr/local/bin/acme.sh
4 changes: 4 additions & 0 deletions scripts/dkim-parsing.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ EOF
echo "*****************************************************************************************************"
echo "Please make sure to update your DNS records for $DOMAIN! You need to add the following details:"
fold -w 80 /etc/opendkim/keys/$DOMAIN.txt
echo "*****************************************************************************************************"
echo "Same record is available at /etc/opendkim/keys/$DOMAIN.txt"
echo "In one line it looks like this:"
cat /etc/opendkim/keys/$DOMAIN.txt | tr -d '\n'
done
postfix_setup_dkim
fi
18 changes: 9 additions & 9 deletions scripts/init-letsencrypt.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@
. /scripts/common.sh
. /scripts/common-run.sh
if [[ $USE_LETSENCRYPT -eq '1' ]]; then
CERT_DIR=/listmonk/backups/certs
CERT_DIR=/etc/ssl
if [ ! -f $CERT_DIR/$POSTFIX_HOSTNAME.key ]; then
sleep $(($(od -vAn -N2 -tu2 </dev/urandom) % 60))
mkdir -p $CERT_DIR/config
mkdir -p $CERT_DIR/acme.config
export CF_Token="$CLOUDFLARE_API_KEY"
acme.sh --issue -d $POSTFIX_HOSTNAME --dns dns_cf --ocsp-must-staple --config-home $CERT_DIR/config \
--keylength 4096 --server letsencrypt \
--cert-file $CERT_DIR/$POSTFIX_HOSTNAME.pem --key-file $CERT_DIR/$POSTFIX_HOSTNAME.key \
--fullchain-file $CERT_DIR/$POSTFIX_HOSTNAME-full.pem
--cert-file $CERT_DIR/certs/$POSTFIX_HOSTNAME.pem --key-file $CERT_DIR/private/$POSTFIX_HOSTNAME.key \
--fullchain-file $CERT_DIR/cert/$POSTFIX_HOSTNAME-full.pem
else
echo "CERT: $POSTFIX_HOSTNAME.pem exists…"
acme.sh --renew-all --config-home $CERT_DIR/config
postconf -e "smtpd_tls_cert_file=$CERT_DIR/$POSTFIX_HOSTNAME-full.pem"
postconf -e "smtpd_tls_key_file=$CERT_DIR/$POSTFIX_HOSTNAME.key"
postconf -e "smtp_tls_cert_file=$CERT_DIR/$POSTFIX_HOSTNAME-full.pem"
postconf -e "smtp_tls_key_file=$CERT_DIR/$POSTFIX_HOSTNAME.key"
acme.sh --renew-all --config-home $CERT_DIR/acme.config
postconf -e "smtpd_tls_cert_file=$CERT_DIR/certs/$POSTFIX_HOSTNAME-full.pem"
postconf -e "smtpd_tls_key_file=$CERT_DIR/private/$POSTFIX_HOSTNAME.key"
postconf -e "smtp_tls_cert_file=$CERT_DIR/certs/$POSTFIX_HOSTNAME-full.pem"
postconf -e "smtp_tls_key_file=$CERT_DIR/private/$POSTFIX_HOSTNAME.key"
postconf -P submission/inet/smtpd_tls_wrappermode=yes
fi
fi
295 changes: 154 additions & 141 deletions scripts/update-cloudflare-dns.sh
Original file line number Diff line number Diff line change
@@ -1,173 +1,186 @@
#!/bin/bash
if [[ $USE_CLOUDFLARE_DDNS -eq '1' ]]; then
### Create .update-cloudflare-dns.log file of the last run for debug
parent_path="$(dirname "${BASH_SOURCE[0]}")"
FILE=${parent_path}/update-cloudflare-dns.log
if ! [ -x "$FILE" ]; then
touch "$FILE"
fi
#!/usr/bin/env bash

LOG_FILE=${parent_path}'/update-cloudflare-dns.log'
### Create .update-cloudflare-dns.log file of the last run for debug
parent_path="$(dirname "${BASH_SOURCE[0]}")"
FILE=${parent_path}/update-cloudflare-dns.log
if ! [ -x "$FILE" ]; then
touch "$FILE"
fi

### Write last run of STDOUT & STDERR as log file and prints to screen
#exec > >(tee $LOG_FILE) 2>&1
exec 1> >(logger -s -t $(basename $0)) 2>&1
echo "==> $(date "+%Y-%m-%d %H:%M:%S")"
LOG_FILE=${parent_path}'/update-cloudflare-dns.log'

### Validate if config file exists
### Write last run of STDOUT & STDERR as log file and prints to screen
exec > >(tee $LOG_FILE) 2>&1
echo "==> $(date "+%Y-%m-%d %H:%M:%S")"

if [[ -z "$1" ]]; then
if ! source ${parent_path}/update-cloudflare-dns.conf; then
echo 'Error! Missing configuration file update-cloudflare-dns.conf or invalid syntax!'
exit 0
fi
else
if ! source ${parent_path}/"$1"; then
echo 'Error! Missing configuration file '$1' or invalid syntax!'
exit 0
fi
fi
### Validate if config-file exists

### Check validity of "ttl" parameter
if [ "${ttl}" -lt 120 ] || [ "${ttl}" -gt 7200 ] && [ "${ttl}" -ne 1 ]; then
echo "Error! ttl out of range (120-7200) or not set to 1"
exit
fi

### Check validity of "proxied" parameter
if [ "${proxied}" != "false" ] && [ "${proxied}" != "true" ]; then
echo 'Error! Incorrect "proxied" parameter choose "true" or "false"'
if [[ -z "$1" ]]; then
if ! source ${parent_path}/update-cloudflare-dns.conf; then
echo 'Error! Missing configuration file update-cloudflare-dns.conf or invalid syntax!'
exit 0
fi

### Check validity of "what_ip" parameter
if [ "${what_ip}" != "external" ] && [ "${what_ip}" != "internal" ]; then
echo 'Error! Incorrect "what_ip" parameter choose "external" or "internal"'
else
if ! source ${parent_path}/"$1"; then
echo 'Error! Missing configuration file '$1' or invalid syntax!'
exit 0
fi
fi

### Check if set to internal ip and proxy
if [ "${what_ip}" == "internal" ] && [ "${proxied}" == "true" ]; then
echo 'Error! Internal IP cannot be Proxied'
exit 0
fi
### Check validity of "ttl" parameter
if [ "${ttl}" -lt 120 ] || [ "${ttl}" -gt 7200 ] && [ "${ttl}" -ne 1 ]; then
echo "Error! ttl out of range (120-7200) or not set to 1"
exit
fi

### Get External ip from https://checkip.amazonaws.com
if [ "${what_ip}" == "external" ]; then
ip=$(curl -4 -s -X GET https://checkip.amazonaws.com --max-time 10)
if [ -z "$ip" ]; then
echo "Error! Can't get external ip from https://checkip.amazonaws.com"
exit 0
fi
echo "==> External IP is: $ip"
fi
### Check validity of "proxied" parameter
if [ "${proxied}" != "false" ] && [ "${proxied}" != "true" ]; then
echo 'Error! Incorrect "proxied" parameter, choose "true" or "false"'
exit 0
fi

### Get Internal ip from primary interface
if [ "${what_ip}" == "internal" ]; then
### Check if "IP" command is present, get the ip from interface
if which ip >/dev/null; then
### "ip route get" (linux)
interface=$(ip route get 1.1.1.1 | awk '/dev/ { print $5 }')
ip=$(ip -o -4 addr show ${interface} scope global | awk '{print $4;}' | cut -d/ -f 1)
### if no "IP" command use "ifconfig", get the ip from interface
else
### "route get" (macOS, Freebsd)
interface=$(route get 1.1.1.1 | awk '/interface:/ { print $2 }')
ip=$(ifconfig ${interface} | grep 'inet ' | awk '{print $2}')
fi
if [ -z "$ip" ]; then
echo "Error! Can't read ip from ${interface}"
exit 0
fi
echo "==> Internal ${interface} IP is: $ip"
fi
### Check validity of "what_ip" parameter
if [ "${what_ip}" != "external" ] && [ "${what_ip}" != "internal" ]; then
echo 'Error! Incorrect "what_ip" parameter, choose "external" or "internal"'
exit 0
fi

### Build coma separated array fron dns_record parameter to update multiple A records
IFS=',' read -d '' -ra dns_records <<<"$dns_record,"
unset 'dns_records[${#dns_records[@]}-1]'
declare dns_records

for record in "${dns_records[@]}"; do
### Get IP address of DNS record from 1.1.1.1 DNS server when proxied is "false"
if [ "${proxied}" == "false" ]; then
### Check if "nsloopup" command is present
if which nslookup >/dev/null; then
dns_record_ip=$(nslookup ${record} 1.1.1.1 | awk '/Address/ { print $2 }' | sed -n '2p')
else
### if no "nslookup" command use "host" command
dns_record_ip=$(host -t A ${record} 1.1.1.1 | awk '/has address/ { print $4 }' | sed -n '1p')
fi
### Check if set to internal ip and proxy
if [ "${what_ip}" == "internal" ] && [ "${proxied}" == "true" ]; then
echo 'Error! Internal IP cannot be proxied'
exit 0
fi

if [ -z "$dns_record_ip" ]; then
echo "Error! Can't resolve the ${record} via 1.1.1.1 DNS server"
exit 0
fi
is_proxed="${proxied}"
fi
### Valid IPv4 Regex
REIP='^((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])\.){3}(25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])$'

### Get the dns record id and current proxy status from cloudflare's api when proxied is "true"
if [ "${proxied}" == "true" ]; then
dns_record_info=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records?type=A&name=$record" \
-H "Authorization: Bearer $cloudflare_zone_api_token" \
-H "Content-Type: application/json")
if [[ ${dns_record_info} == *"\"success\":false"* ]]; then
echo ${dns_record_info}
echo "Error! Can't get dns record info from cloudflare's api"
### Get external ip from https://checkip.amazonaws.com
if [ "${what_ip}" == "external" ]; then
ip=$(curl -4 -s -X GET https://checkip.amazonaws.com --max-time 10)
if [ -z "$ip" ]; then
echo "Error! Can't get external ip from https://checkip.amazonaws.com"
ip=$(curl -4 -s -X GET https://ip.kiik.cf/ip --max-time 10)
if [ -z "$ip" ]; then
echo "Error! Can't get external ip from https://ip.kiik.cf/ip"
ip=$(curl -4 -s -X GET https://api.ipify.org --max-time 10)
if [ -z "$ip" ]; then
echo "Error! Can't get external ip from https://api.ipify.org"
exit 0
fi
is_proxed=$(echo ${dns_record_info} | grep -o '"proxied":[^,]*' | grep -o '[^:]*$')
dns_record_ip=$(echo ${dns_record_info} | grep -o '"content":"[^"]*' | cut -d'"' -f 4)
fi
fi
if ! [[ "$ip" =~ $REIP ]]; then
echo "Error! IP Address returned was invalid!"
exit 0
fi
echo "==> External IP is: $ip"
fi

### Get Internal ip from primary interface
if [ "${what_ip}" == "internal" ]; then
### Check if "IP" command is present, get the ip from interface
if which ip >/dev/null; then
### "ip route get" (linux)
interface=$(ip route get 1.1.1.1 | awk '/dev/ { print $5 }')
ip=$(ip -o -4 addr show ${interface} scope global | awk '{print $4;}' | cut -d/ -f 1)
### If no "ip" command use "ifconfig" instead, to get the ip from interface
else
### "route get" (macOS, Freebsd)
interface=$(route get 1.1.1.1 | awk '/interface:/ { print $2 }')
ip=$(ifconfig ${interface} | grep 'inet ' | awk '{print $2}')
fi
if [ -z "$ip" ]; then
echo "Error! Can't read ip from ${interface}"
exit 0
fi
echo "==> Internal ${interface} IP is: $ip"
fi

### Check if ip or proxy have changed
if [ ${dns_record_ip} == ${ip} ] && [ ${is_proxed} == ${proxied} ]; then
echo "==> DNS record IP of ${record} is ${dns_record_ip}", no changes needed.
continue
### Build coma separated array fron dns_record parameter to update multiple A records
IFS=',' read -d '' -ra dns_records <<<"$dns_record,"
unset 'dns_records[${#dns_records[@]}-1]'
declare dns_records

for record in "${dns_records[@]}"; do
### Get IP address of DNS record from 1.1.1.1 DNS server when proxied is "false"
if [ "${proxied}" == "false" ]; then
### Check if "nslookup" command is present
if which nslookup >/dev/null; then
dns_record_ip=$(nslookup ${record} 1.1.1.1 | awk '/Address/ { print $2 }' | sed -n '2p')
else
### if no "nslookup" command use "host" command
dns_record_ip=$(host -t A ${record} 1.1.1.1 | awk '/has address/ { print $4 }' | sed -n '1p')
fi

echo "==> DNS record of ${record} is: ${dns_record_ip}. Trying to update..."
if [ -z "$dns_record_ip" ]; then
echo "Error! Can't resolve the ${record} via 1.1.1.1 DNS server"
exit 0
fi
is_proxed="${proxied}"
fi

### Get the dns record information from cloudflare's api
cloudflare_record_info=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records?type=A&name=$record" \
### Get the dns record id and current proxy status from Cloudflare API when proxied is "true"
if [ "${proxied}" == "true" ]; then
dns_record_info=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records?type=A&name=$record" \
-H "Authorization: Bearer $cloudflare_zone_api_token" \
-H "Content-Type: application/json")
if [[ ${cloudflare_record_info} == *"\"success\":false"* ]]; then
echo ${cloudflare_record_info}
echo "Error! Can't get ${record} record inforamiton from cloudflare API"
if [[ ${dns_record_info} == *"\"success\":false"* ]]; then
echo ${dns_record_info}
echo "Error! Can't get dns record info from Cloudflare API"
exit 0
fi
is_proxed=$(echo ${dns_record_info} | grep -o '"proxied":[^,]*' | grep -o '[^:]*$')
dns_record_ip=$(echo ${dns_record_info} | grep -o '"content":"[^"]*' | cut -d'"' -f 4)
fi

### Get the dns record id from response
cloudflare_dns_record_id=$(echo ${cloudflare_record_info} | grep -o '"id":"[^"]*' | cut -d'"' -f4)
### Check if ip or proxy have changed
if [ ${dns_record_ip} == ${ip} ] && [ ${is_proxed} == ${proxied} ]; then
echo "==> DNS record IP of ${record} is ${dns_record_ip}", no changes needed.
continue
fi

### Push new dns record information to cloudflare's api
update_dns_record=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records/$cloudflare_dns_record_id" \
-H "Authorization: Bearer $cloudflare_zone_api_token" \
-H "Content-Type: application/json" \
--data "{\"type\":\"A\",\"name\":\"$record\",\"content\":\"$ip\",\"ttl\":$ttl,\"proxied\":$proxied}")
if [[ ${update_dns_record} == *"\"success\":false"* ]]; then
echo ${update_dns_record}
echo "Error! Update Failed"
exit 0
fi
echo "==> DNS record of ${record} is: ${dns_record_ip}. Trying to update..."

echo "==> Success!"
echo "==> $record DNS Record Updated To: $ip, ttl: $ttl, proxied: $proxied"
### Get the dns record information from Cloudflare API
cloudflare_record_info=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records?type=A&name=$record" \
-H "Authorization: Bearer $cloudflare_zone_api_token" \
-H "Content-Type: application/json")
if [[ ${cloudflare_record_info} == *"\"success\":false"* ]]; then
echo ${cloudflare_record_info}
echo "Error! Can't get ${record} record information from Cloudflare API"
exit 0
fi

### Telegram notification
if [ ${notify_me_telegram} == "no" ]; then
exit 0
fi
### Get the dns record id from response
cloudflare_dns_record_id=$(echo ${cloudflare_record_info} | grep -o '"id":"[^"]*' | cut -d'"' -f4)

### Push new dns record information to Cloudflare API
update_dns_record=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records/$cloudflare_dns_record_id" \
-H "Authorization: Bearer $cloudflare_zone_api_token" \
-H "Content-Type: application/json" \
--data "{\"type\":\"A\",\"name\":\"$record\",\"content\":\"$ip\",\"ttl\":$ttl,\"proxied\":$proxied}")
if [[ ${update_dns_record} == *"\"success\":false"* ]]; then
echo ${update_dns_record}
echo "Error! Update failed"
exit 0
fi

if [ ${notify_me_telegram} == "yes" ]; then
telegram_notification=$(
curl -s -X GET "https://api.telegram.org/bot${telegram_bot_API_Token}/sendMessage?chat_id=${telegram_chat_id}" --data-urlencode "text=${record} DNS record updated to: ${ip}"
)
if [[ ${telegram_notification=} == *"\"ok\":false"* ]]; then
echo ${telegram_notification=}
echo "Error! Telegram notification failed"
exit 0
fi
echo "==> Success!"
echo "==> $record DNS Record updated to: $ip, ttl: $ttl, proxied: $proxied"

### Telegram notification
if [ ${notify_me_telegram} == "no" ]; then
exit 0
fi

if [ ${notify_me_telegram} == "yes" ]; then
telegram_notification=$(
curl -s -X GET "https://api.telegram.org/bot${telegram_bot_API_Token}/sendMessage?chat_id=${telegram_chat_id}" --data-urlencode "text=${record} DNS record updated to: ${ip}"
)
if [[ ${telegram_notification=} == *"\"ok\":false"* ]]; then
echo ${telegram_notification=}
echo "Error! Telegram notification failed"
exit 0
fi
done
fi
fi
done
2 changes: 1 addition & 1 deletion scripts/update-letsencrypt.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
if [[ $USE_LETSENCRYPT -eq '1' ]]; then
acme.sh --renew-all --config-home /listmonk/backups/certs/config
fi

0 comments on commit 9036ff4

Please sign in to comment.