Cloudflare+DDNS+Shell

懒的换 IP 地址了,于是研究了一下 Cloudflare 的 API,用着还可以,做成小脚本。


1、前言

服务器 IP 总是变,没事就会变个新的,这时候就需要一个 Dynamic Domain Name Server 来保证实时的 DNS 更换。
当然首先这个需要你的 DNS 解析商做配合,本文则采用 Cloudflare+DDNS+Shell


2、准备

准备工具

Cloudflare 的 Global API

Cloudflare 解析的域名一个

前提要素

Curl Wget 已安装


3、DDNS 获取新 IP 地址 Shell 脚本

#!/usr/bin/env bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
#
# Dynamic Domain Name Server (Cloudflare API)
#
# Author: StarryVoid <[email protected]>
# Intro:  https://blog.starryvoid.com/archives/313.html
#

# CloudFlare API
XAUTHEMAIL="YOUREMAILADDRESS"
XAUTHKEY="YOURCLOUDFLAREAPIKEY"

# Domain Name
ZONENAME="DOMAIN"
DOMAINNAME="DOMAINNAME"

# Ready
FILEPATH=$(pwd)
DATETIME=`date +%Y-%m-%d_%H:%M:%S`
OUTDATA="ddnsrun.data"
OUTLOG="ddnsrun.log"

get_zone_records(){
    ZONERECORDS=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=${ZONENAME}" -H "X-Auth-Email: ${XAUTHEMAIL}" -H "X-Auth-Key: ${XAUTHKEY}" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*' | head -1 ) if [[ ! ${ZONERECORDS} ]]; then echo Get zone_records Error >> ${FILEPATH}/${OUTLOG} ; exit 1; fi
}

get_dns_records(){
    DNSRECORDS=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${ZONERECORDS}/dns_records?type=A&name=${DOMAINNAME}" -H "X-Auth-Email: ${XAUTHEMAIL}" -H "X-Auth-Key: ${XAUTHKEY}" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*' | head -1 ) if [[ ! ${DNSRECORDS} ]]; then echo Get dns_records Error >> ${FILEPATH}/${OUTLOG}; exit 1; fi
}
    
get_old_ip(){
    IPOLD=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${ZONERECORDS}/dns_records/${DNSRECORDS}" -H "X-Auth-Email: ${XAUTHEMAIL}" -H "X-Auth-Key: ${XAUTHKEY}" -H "Content-Type: application/json" | grep -Po '(?<="content":")[^"]*' ) if [[ ! ${IPOLD} ]]; then echo Get old_ip Error >> ${FILEPATH}/${OUTLOG}; exit 1; fi
}

get_new_ip(){
    [ -z ${IPNEW} ] && IPNEW=$( wget -qO- -t1 -T2 ipv4.icanhazip.com )
    [ -z ${IPNEW} ] && IPNEW=$( wget -qO- -t1 -T2 ipinfo.io/ip )
    if [[ ! ${IPNEW} ]]; then echo Get ip_address Error >> ${FILEPATH}/${OUTLOG}; exit 1; fi
}

update_new_ip(){
    curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/${ZONERECORDS}/dns_records/${DNSRECORDS}" -H "X-Auth-Email: ${XAUTHEMAIL}" -H "X-Auth-Key: ${XAUTHKEY}" -H "Content-Type: application/json"  --data "{\"type\":\"A\",\"name\":\"${DOMAINNAME}\",\"content\":\"${IPNEW}\",\"ttl\":1,\"proxied\":false}"
}

set_ddnsrun.data(){
        touch ${FILEPATH}/${OUTDATA}
        get_zone_records
        get_dns_records
        get_old_ip
        echo Update Time ${DATETIME} >> ${FILEPATH}/${OUTDATA}
        sed -i '/ZONERECORDS=/d' ${FILEPATH}/${OUTDATA}
        echo ZONERECORDS=${ZONERECORDS} >> ${FILEPATH}/${OUTDATA}
        sed -i '/DNSRECORDS=/d' ${FILEPATH}/${OUTDATA}
        echo DNSRECORDS=${DNSRECORDS} >> ${FILEPATH}/${OUTDATA}
        sed -i '/OldIPAddress=/d' ${FILEPATH}/${OUTDATA}
        echo OldIPAddress=${IPOLD} >> ${FILEPATH}/${OUTDATA}
}

main(){
    echo Running Time is ${DATETIME} >> ${FILEPATH}/${OUTLOG}
    if [[ -f ${FILEPATH}/${OUTDATA} ]]; then
        ZONERECORDS=$(cat ${OUTDATA} | grep "ZONERECORDS=" | cut -c 13-)
        DNSRECORDS=$(cat ${OUTDATA} | grep "DNSRECORDS=" | cut -c 12-)
        IPOLD=$(cat ${OUTDATA} | grep "OldIPAddress=" | cut -c 14-)
        if [[ ! ${ZONERECORDS} ]]; then echo Get File zone_records Error >> ${FILEPATH}/${OUTLOG} ; exit 1; fi
        if [[ ! ${DNSRECORDS} ]]; then echo Get File dns_records Error >> ${FILEPATH}/${OUTLOG}; exit 1; fi
        if [[ ! ${IPOLD} ]]; then echo Get File old_ip Error >> ${FILEPATH}/${OUTLOG}; exit 1; fi
        rm -f ${FILEPATH}/ddnsrun.date
    else
        set_ddnsrun.data
    fi
    get_new_ip
    if [[ ${IPNEW} == ${IPOLD} ]]; then 
        echo The IP address is the same >> ${FILEPATH}/${OUTLOG}
        exit 0
    else 
        update_new_ip
        sed -i '/OldIPAddress=/d' ${FILEPATH}/${OUTDATA}
        echo OldIPAddress=${IPNEW} >> ${FILEPATH}/${OUTDATA}
        get_old_ip
        if [[ ${IPNEW} == ${IPOLD} ]]; then 
            echo IP address has been changed to ${IPNEW} >> ${FILEPATH}/${OUTLOG}
            exit 0
        else
            echo IP address has been changed failed >> ${FILEPATH}/${OUTLOG}
            exit 1
        fi
    fi
}

main

4、讲解

首先本文制作过程中参考过秋水逸冰的脚本,在此表示感谢


4.1、脚本配置

我们需要将所需的内容(Cloudflare API 和 DDNS 域名)填入对应位置

# CloudFlare API 
XAUTHEMAIL="[email protected]" #你的 Cloudflare 邮箱用户名
XAUTHKEY="123123123123" #你的 Cloudflare Global API Key
# Domain Name 
ZONENAME="example.com" #你的二级域名
DOMAINNAME="ddns.example.com" #你的 DDNS 域名

4.2、定时运行

如果需要定时运行,可以编辑/etc/crontab 实现定期运行,下例为 5min 运行一次
先 cd 进入目录是为了隔离不同 DDNS 脚本生成的数据和日志文件。否则默认放/root 目录下。

# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed

*/5 * * * * root cd /autoshell && bash ddns.sh

4.3、脚本输出

默认会在用户所在目录下生成两个文件 ddnsrun.data 和 ddnsrun.log ,前者是储存获取的 API 信息,后者是储存运行日志。

[[email protected] auto]# cat ddnsrun.data
Update Time 2018-12-02_11:43:01
ZONERECORDS=*
DNSRECORDS=*
OldIPAddress=*.*.*.*

[[email protected] auto]# cat ddnsrun.log
Running Time is 2018-12-02_11:43:01
IP address has been changed to *.*.*.*
Running Time is 2018-12-02_11:44:01
The IP address is the same
Running Time is 2018-12-02_11:45:01
The IP address is the same
Running Time is 2018-12-02_11:46:01
The IP address is the same

如果出现问题,可以在日志中查看问题原因。


4.4、获取 Cloudflare 的 Global API

首先进入 Cloudflare 的个人配置页面 [链接 ]

找到下面的 API Keys  (Keys used to access Cloudflare APIs.)

然后在 Global API Key 一行点击右侧的 View 查看你的 Global API Key

最后搭配你的邮箱账户名即可使用


5、后期修订

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注