加载中...
clodflare Rest API 实现动态域名更新(DDNS)
发表于:2023-01-14 | 分类: cloudflare
字数统计: 2.3k | 阅读时长: 10分钟 | 阅读量:

背景

家中自建服务器或者树莓派或者软路由,需要搭建自己使用的一些系统,使用cloudflare实现穿透公网访问,由于自建服务器的不稳定性,并且网络提供商每周会重启网络设备(亦或者公网ip到期后会改变等原因)。但域名上解析的ip由于不能立刻被替换为新的ip导致服务不可用。

解决方案

配置动态脚本实现ip改变后自动更改解析即DDNS 具体可以看 这里的介绍 或者 国内版介绍
实现的前提:

实现前提

  1. 家里的网络需要是公网ip。 如何确认是否为公网IP? 这个比较简单,可以访问这个地址 页面返回的一个地址,然后再到自己的路由器中查看运营商分配的地址,若相同则是公网ip,若不同则是NAT ip, 具体怎么索要公网ip不同地区、不通运营商要求不同,请自行咨询.
  2. 需要有一台能够执行定时任务的机器,包括但不限于软路由插件、linux系统、docker服务等.
  3. cloudflare 中维护的一个域名

准备cloudflare账户token

由于要操作账户内的内容,我们需要生成一个api token,由于只需要操作dns解析,所以我们只需要生成一个操作dns权限的api token即可(一定要严格控制权限,千万不要使用账户的token)
首先进入个人账户中心
prfile.png
api-token.png
然后点击 API Tokens 进入token管理页面
create-token.png

找到DNS管理点击 “Use template”
dns-template.png

根据自己的需要填写权限信息,我这里指定了某域名的dns解析编辑权限
token-detail.png

点击 “continue to summary” 以后会展示生成的token和验证方案
验证token结果:
verify-token.png

注意:这个token只能显示这一次,一定要保存好!

我们在token管理页面可以看见这个token记录(看不见内容),当我们不想使用的时候删除即可

token-list.png

创建域名解析

我们需要在cloudflare先创建一个dns解析,即我们需要动态更新ip的域名解析
domain.png

实现动态更新DDNS

根据官方接口文档,我们需要以下参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
curl --request PUT \
--url https://api.cloudflare.com/client/v4/zones/zone_identifier/dns_records/identifier \
--header 'Content-Type: application/json' \
--header 'X-Auth-Email: ' \
--data '{
"comment": "Domain verification record",
"content": "127.0.0.1",
"name": "example.com",
"proxied": false,
"tags": [
"owner:dns-team"
],
"ttl": 3600
}'
字段名 字段描述 参数类型 是否获取/已知
Authorization 用户验证 token header 必填 已知
Content-Type 请求类型 header 必填 已知
X-Auth-Email 授权用户 header 必填 已知
identifier DNS 记录的id 路径参数 必填 未知
zone_identifier 域名的id 路径参数 必填 未知
comment 注释 body参数 不必填 已知
content 记录值(服务ip) body参数 必填 未知
name 记录名称 body参数 必填 已知
proxied 是否cdn代理 body 参数 不必填 已知
tags 标签 body 参数 不必填 已知
ttl 有效时间 body参数 必填 已知

根据上表统计,我们目前有三项是未知的,第一项就是当前服务的ip,第二项是dns记录id 第三项是域名记录id,我们一项一项来解决

获取当前服务的ip

这里提供一些网站用来获取自己当前公网解析ip,请根据自己的情况获取,我们的目标是拿到一个ipv4地址

1
2
3
4
5
6
7
8
9
$ curl ifconfig.me
$ curl icanhazip.com
$ curl ident.me
$ curl ipecho.net/plain
$ curl whatismyip.akamai.com
$ curl tnx.nl/ip
$ curl myip.dnsomatic.com
$ curl ip.appspot.com
$ curl -s checkip.dyndns.org | sed \'s/.*IP Address: \([0-9\.]*\).*/\1/g\'

我使用的是 http://ipv4.icanhazip.com/ 直接使用curl 就可以拿到

获取域名的id值

这个域名是维护在cloudflare上,那么我们肯定要通过官方文档介绍来获取
首先拿到用户ZoneID , 根据这篇文章 返回值中会有对应的域名的id

1
2
3
4
5
6
7
AUTH_EMAIL="cloudflare注册邮箱"
AUTH_TOKEN="账户中生成的token"
curl --request GET \
--url https://api.cloudflare.com/client/v4/zones \
--header 'Content-Type: application/json' \
--header "X-Auth-Email: ${AUTH_EMAIL}" \
--header "Authorization: Bearer ${AUTH_TOKEN}"

返回中我们需要找到对应的id
domainid.png

获取DNS记录的id值

上一步我们拿到了域名的id,可以通过域名id拿到记录id值, 参考 这篇文章

1
2
3
4
5
6
7
8
AUTH_EMAIL="cloudflare注册邮箱"
AUTH_TOKEN="账户中生成的token"
ZONE_ID="上一步获取的域名id"
curl --request GET \
--url "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records" \
--header 'Content-Type: application/json' \
--header "X-Auth-Email: ${AUTH_EMAIL}" \
--header "Authorization: Bearer ${AUTH_TOKEN}"

找到我们要的recordID
recordid.png

测试更新记录是否生效

上面我们拿到了所有未知的值,接下来就是更新解析的记录值了 , 根据官方文档 得到的更新接口如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
AUTH_EMAIL="cloudflare注册邮箱"
AUTH_TOKEN="账户中生成的token"
ZONE_ID="上一步获取的域名id"
RECORD_ID="上面获取的DNS记录的id"
CURRENT_IP="当前要更新的ip"

curl --request PUT \
--url "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records/${RECORD_ID}" \
--header 'Content-Type: application/json' \
--header "X-Auth-Email: ${AUTH_EMAIL}" \
--header "Authorization: Bearer ${AUTH_TOKEN}" \
--data '{
"comment": "Auto update",
"content": "${CURRENT_IP}",
"name": "mail.jaffee.cn",
"proxied": false,
"ttl": 600,
"type": "A"
}'

update-record.png
再看下记录
recordlist.png

动态更新脚本

上面我们已经搞定了如何获取当前ip,如何通过restful接口更新记录值,那么我们只需要动态实现实时获取并更新记录值就可以了,大致流程如下:
update-follow.png
逻辑清晰了,我们就来写一下脚本处理吧,完整的脚本如下:
注: 我们使用的jq 命令 需要进行安装 apt install jq (debian/ubuntu)或者 yum install jq (centos/readheat)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
set -e
#获取公网ip地址网站
GET_IP_SITE="http://ipv4.icanhazip.com/"
## 获取公网IP地址
CURRENT_IP=$(curl -s ${GET_IP_SITE})
# cloudflare 用户邮箱
AUTH_EMAIL="your cloudflare mail"
# cloudflare 用户接口操作token
AUTH_TOKEN="yout user token"
# 域名id
ZONE_ID="域名ID 上面已经拿到"
# 记录ID
RECORD_ID="DNS记录ID 上面已经拿到"
# 记录
RECORD_NAME="待更新的记录值"

RECORD_DETAIL_JSON=$(curl -s --request GET \
--url "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records/${RECORD_ID}" \
--header 'Content-Type: application/json' \
--header "X-Auth-Email: ${AUTH_EMAIL}" \
--header "Authorization: Bearer ${AUTH_TOKEN}")

RECORD_IP=$(echo ${RECORD_DETAIL_JSON} | jq .result.content | sed 's/\"//g')

if [ "${CURRENT_IP}" == "${RECORD_IP}" ];then
echo "IP not change.. no update action."
exit 0
fi
echo "Record ip = [${RECORD_IP}], Current ip = [${CURRENT_IP}], do update action!"
# 走到这就更新
UPDATE_RESULT=$(curl -s --request PUT \
--url "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records/${RECORD_ID}" \
--header 'Content-Type: application/json' \
--header "X-Auth-Email: ${AUTH_EMAIL}" \
--header "Authorization: Bearer ${AUTH_TOKEN}" \
--data "{
\"comment\": \"Auto ddns update\",
\"content\": \"${CURRENT_IP}\",
\"name\": \"${RECORD_NAME}\",
\"proxied\": false,
\"ttl\": 600,
\"type\": \"A\"
}")

UPDATE_SUCCESS=$(echo ${UPDATE_RESULT} | jq .success)
if [ "${UPDATE_SUCCESS}" == "true" ];then
echo "update success!"
echo "${UPDATE_RESULT}"
exit 0
else
echo "update fail !"
echo "${UPDATE_RESULT}"
exit 1
fi

部署方案

由于脚本没有实现定时,所以我们需要自行实现定时执行方案,这里例举几种方案

  1. linux crontab: 这种是最简方案,只需要我们将脚本放到服务器上并添加cron执行计划即可

假设脚本在用户家目录 ,名字为cloudflare-ddns.sh, 则可以这么写:
0/10 * * * * /bin/bash ~/cloudflare-ddns.sh >> /var/log/cloudflare-ddns.log

  1. 使用docker: 这就需要我们自己准备一个镜像,这里我提供一个dockerfile 脚本

假设构建目录下有一个cloudflare-ddns.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM ubuntu:22.04
COPY cloudflare-ddns.sh /opt/app/cloudflare-ddns.sh
RUN apt update \
&& apt install -y jq cron curl \
&& apt clean \
&& apt autoclean \
&& chmod +x /opt/app/cloudflare-ddns.sh \
&& mkdir -p /var/log/cloudflare-ddns \
&& echo "cloudflare ddns logs" > /var/log/cloudflare-ddns/cloudflare-ddns.log \
&& echo "*/10 * * * * /bin/bash /opt/app/cloudflare-ddns.sh >> /var/log/cloudflare-ddns/cloudflare-ddns.log" > /var/spool/cron/crontabs/root \
&& chown root:crontab /var/spool/cron/crontabs/root \
&& chmod 600 /var/spool/cron/crontabs/root
CMD service cron start && tail -f /var/log/cloudflare-ddns/cloudflare-ddns.log
  1. 使用K8S cron job: 将任务放在集群里定时执行,执行时间由集群控制,不需要人工操作定时任务

Dockerfile如下:

1
2
3
4
5
6
7
FROM ubuntu:22.04
COPY cloudflare-ddns.sh /opt/app/cloudflare-ddns.sh
RUN apt update \
&& apt install -y jq curl \
&& apt clean \
&& apt autoclean \
&& chmod +x /opt/app/cloudflare-ddns.sh

k8s deploy 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: batch/v1
kind: CronJob
metadata:
name: cloudflare-mail-ddns
namespace: production
spec:
schedule: "*/10 * * * *"
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 5
startingDeadlineSeconds: 60
jobTemplate:
spec:
template:
spec:
imagePullSecrets:
- name: harborsecret
containers:
- name: cloudflare-mail-ddns
image: xxxxxx.com:5000/base/cloudflare-ddns-mail:1.0.0
imagePullPolicy: IfNotPresent
command: ["/bin/bash", "-c"]
args: ["xxxxxxx"] #根据自己镜像情况去写
restartPolicy: OnFailure

cronJob.png
jobs.png

上一篇:
linux-基础命令
下一篇:
mysql索引导致慢查询
本文目录
本文目录