e10.jpg

一、前言:DNS和DDNS概念,需求场景

DNS(Domain Name System)域名解析系统,各大DNS服务商提供的dns解析,方便大家将朗朗上口的域名与公网ip绑定,让网站访问更加人性化;
普通DNS解析规则,无法时刻检测内网NAT映射的机器的公网ip变动,所以DDNS(Dynamic DNS)动态DNS解析应运而生,主要原理就是NAT内网vps机器通过代码获得自己当前映射的外网(公网)IP,然后通过各大DNS服务商提供的DNS 解析API接口,将当前公网IP传回DNS服务商,动态修改对应的域名解析IP,达到动态公网IP绑定域名效果,使得NAT小鸡也可以绑定域名建站。

二、腾讯云DNS为例,通过API接口创建DDNS服务

请求腾讯云API前,建议你按着官方文档申请安全凭证,参考:
腾讯云官方文档之API部分
申请时,建议新建一个专用的API访问子账号,如果你账号资产不重要,直接用你的主号来操作就行,此段可以略过

创建专用API子账号流程

  • A_1.首先登录API密钥页面:

API密钥页面
1_create api.png
选择新建子账号

  • A_2.这里我选择自定义创建:

2_create sub user.jpg

  • A_3.选择可访问资源类型:

3_choose sub user type .png

  • A_4.填写子账号用户细节

用户名,手机号,邮箱等信息,注意勾选“编程访问”方式
4_sub user details .png

  • A_5.授权子账号策略为完整的云资源授权

如果需要其他授权,可以搜索对应关键字快速寻找
授权:QCloudResourceFullAccess
或者留空,创建完毕后,再去
控制台用户预览
用户列表选择授权需要的权限也行
5_sub user policies .png

  • A_6.最后确认用户细节和策略清单

如果没问题就提交下一步
6_sub user last confirm .png

  • A_7.保存你的API Secret ID信息

我们在此页面可以拿到对应的API ID和KEY密钥相关信息,请务必妥善保存,如果怕遗忘可以点选发送到可靠邮箱备份。
7_sub user secret details .png

创建完毕后在你的控制台访问管理>概览页面,标记着子账号登录信息备忘:
控制台概览页面
复制保存好你的API信息:
UserName AKxxxxxxxxxxxxx Qwxxxxxxxxxxxxxxx
我们再次参阅API接口之解析记录相关接口中关于修改解析记录的文档描述:
修改解析记录官方文档说明
可以尝试着使用域名API,达到修改域名解析目的:

  • 节选公共请求参数示例:
https://cvm.api.qcloud.com/v2/index.php?
Action=DescribeInstances
&SecretId=AKIDkIcmkTqWqshHcghUhr8C1d5h4A3tA2kF
&Region=ap-guangzhou
&Timestamp=1465055529
&Nonce=59485
&Signature=mysignature
&SignatureMethod=HmacSHA256
&<接口请求参数>

那么我们的脚本第一步功能:获取解析记录可以这样写:

#!/bin/bash
domain='你的域名,例如qq.com'
subDomain='你希望解析的子域名,例如wx.qq.com,则只输入wx'
sId='你的云API秘钥SecretId'
sKey='你的云API秘钥SecretKey'
signatureMethod='HmacSHA1'#常用的HmacSHA256和HmascSHA1加密都可以的
timestamp=`date +%s`#当前Unix系统时间戳,不得与腾讯云服务器时间相差超过2小时
nonce=`head -200 /dev/urandom | cksum | cut -f2 -d" "`#随机正整数,配合时间戳配对,验证每次请求的身份,防止重放攻击,类似阅后即焚,防止截取请求数据再次发送到腾讯服务器获得返回的敏感参数。
region=bj
url="https://cns.api.qcloud.com/v2/index.php"
#获取域名解析条目ID:recordId
action='RecordList'
src=`printf "GETcns.api.qcloud.com/v2/index.php?Action=%s&Nonce=%s&Region=%s&SecretId=%s&SignatureMethod=%s&Timestamp=%s&domain=%s" $action $nonce $region $sId $signatureMethod $timestamp $domain`
#echo 'src: ' $src
signature=`echo -n $src|openssl dgst -sha1 -hmac $sKey -binary |base64`
#echo 'signature: ' $signature
params=`printf "Action=%s&domain=%s&Nonce=%s&Region=%s&SecretId=%s&Signature=%s&SignatureMethod=%s&Timestamp=%s" $action $domain $nonce $region $sId "$signature" $signatureMethod $timestamp `
#echo 'params: ' $params
curl -G -d "$params" --data-urlencode "Signature=$signature" "$url"

参考:https://blog.csdn.net/dragon2k/article/details/88016755

  • 提供我的脚本范例供参阅:

我的脚本范本

#!/bin/bash
domain='lolimoe.ltd'
subDomain='ddns'
sId='AKxxxxxxxxxxxxxxxxx'
sKey='Qwxxxxxxxxxxxxxxxx'
signatureMethod='HmacSHA1'
timestamp=`date +%s`
nonce=`head -200 /dev/urandom | cksum | cut -f2 -d" "`
region=bj
url="https://cns.api.qcloud.com/v2/index.php"
#获取域名解析条目ID:recordId
action='RecordList'
src=`printf "GETcns.api.qcloud.com/v2/index.php?Action=%s&Nonce=%s&Region=%s&SecretId=%s&SignatureMethod=%s&Timestamp=%s&domain=%s" $action $nonce $region $sId $signatureMethod $timestamp $domain`
#echo 'src: ' $src
signature=`echo -n $src|openssl dgst -sha1 -hmac $sKey -binary |base64`
#echo 'signature: ' $signature
params=`printf "Action=%s&domain=%s&Nonce=%s&Region=%s&SecretId=%s&Signature=%s&SignatureMethod=%s&Timestamp=%s" $action $domain $nonce $region $sId "$signature" $signatureMethod $timestamp `
#echo 'params: ' $params
curl -G -d "$params" --data-urlencode "Signature=$signature" "$url"


vi test.sh 新建sh脚本文件,按i键编辑,粘贴,然后按esc,输入:wq保存,再通过bash test.sh执行,获得返回数据,拿到你需要修改的域名解析条目对应的9位数字ID,保存后,接下来的脚本需要用到。

第二个功能,修改域名解析记录,则可以这样:

#!/bin/bash
#/usr/bin/ddns
recordId='根据上面返回结果9位数字'
domain='你的域名,例如qq.com'
subDomain='你希望解析的子域名,例如wx.qq.com,则只输入wx'
sId='你的云API秘钥SecretId'
sKey='你的云API秘钥SecretKey'
signatureMethod='HmacSHA1'
timestamp=`date +%s`
nonce=`head -200 /dev/urandom | cksum | cut -f2 -d" "`#从urandom设备获取随机数,取前200位,整型输出后,取filed2区块的五位数
#关于随机数产生有多种方式,可以参考https://blog.csdn.net/wy1550365215/article/details/77446501
region=bj
url="https://cns.api.qcloud.com/v2/index.php"
#获取ip
ip=`curl ip.sb`
action='RecordModify'
recordType='A'
recordLine='默认'
value=$ip

src=`printf "GETcns.api.qcloud.com/v2/index.php?Action=%s&Nonce=%s&Region=%s&SecretId=%s&SignatureMethod=%s&Timestamp=%s&domain=%s&recordId=%s&recordLine=%s&recordType=%s&subDomain=%s&value=%s" $action $nonce $region $sId $signatureMethod $timestamp $domain $recordId $recordLine $recordType $subDomain $value`

#echo 'src: ' $src
signature=`echo -n $src|openssl dgst -sha1 -hmac $sKey -binary |base64`
#echo 'signature: ' $signature

params=`printf "Action=%s&Nonce=%s&Region=%s&SecretId=%s&SignatureMethod=%s&Timestamp=%s&domain=%s&recordId=%s&recordLine=%s&recordType=%s&subDomain=%s&value=%s" $action $nonce $region $sId $signatureMethod $timestamp $domain $recordId $recordLine $recordType $subDomain $value`

#echo 'params: ' $params

curl -G -d "$params" --data-urlencode "Signature=$signature" "$url"

原文参考链接

  • 同时我提供下自己的范本供参考:

修改DNS解析脚本范例

#!/bin/bash
#/usr/bin/ddns
recordId='525537912'
domain='lolimoe.ltd'
subDomain='ddns'
sId='AKxxxxxxxxxxxxxxxxxxx'
sKey='Qwxxxxxxxxxxxxxxxxxxx'
signatureMethod='HmacSHA1'
timestamp=`date +%s`
nonce=`head -200 /dev/urandom | cksum | cut -f2 -d" "`
region=bj
url="https://cns.api.qcloud.com/v2/index.php"
#获取ip
ip=`curl ip.sb`
action='RecordModify'
recordType='A'
recordLine='默认'
value=$ip

src=`printf "GETcns.api.qcloud.com/v2/index.php?Action=%s&Nonce=%s&Region=%s&SecretId=%s&SignatureMethod=%s&Timestamp=%s&domain=%s&recordId=%s&recordLine=%s&recordType=%s&subDomain=%s&value=%s" $action $nonce $region $sId $signatureMethod $timestamp $domain $recordId $recordLine $recordType $subDomain $value`

#echo 'src: ' $src
signature=`echo -n $src|openssl dgst -sha1 -hmac $sKey -binary |base64`
#echo 'signature: ' $signature

params=`printf "Action=%s&Nonce=%s&Region=%s&SecretId=%s&SignatureMethod=%s&Timestamp=%s&domain=%s&recordId=%s&recordLine=%s&recordType=%s&subDomain=%s&value=%s" $action $nonce $region $sId $signatureMethod $timestamp $domain $recordId $recordLine $recordType $subDomain $value`

#echo 'params: ' $params

curl -G -d "$params" --data-urlencode "Signature=$signature" "$url"

获取vps当前公网ip的网站:

dynamic_ip=`curl ip.sb`

参考自南晴浪大佬的Github脚本
同时还有其他网站可以使用,比如:

dynamic_ip=$(curl -s http://myip.dnsomatic.com/)

参考文章

touch DDNS_TX.sh,vi 编辑,i编辑状态,粘贴,:wq保存脚本以你喜欢的脚本命名,bash执行一遍回到你的域名列表,查看是否修改正确,确定没问题了,再赋予脚本执行权限:

chmod +x DDNS_TX.sh

然后crontab -e新建自动执行任务:

* * * * * /bin/bash /home/backup/DDNS_TX.sh >/dev/null 2>&1

每分钟执行一次检测,算是顺利完成了。

三、以CloudFlare的DNS服务为例,通过API接口创建DDNS服务

如果是灰产大佬,只用国外域名和国外的DNS解析服务商的话,cloudflare算是一个典型代表,我们也做一个演示,让大家看看怎么利用cloudflare的API调用,做相应的DDNS检测脚本:
登录cloudflare,

如果没有账号的,可以参考这篇文章第五步注册一个免费的:


以下是CloudFlare API创建过程,感兴趣的可以点开查看:
CloudFlare API创建流程

  • B_1.点击create tokens创建新的API

CF_create_tokens.png

  • B_2.取个喜欢的命名,选择必要的授权

ZONE范围,DNS解析项目,Edit编辑权限即可:
CF_tokens_define.png

  • B_3.最后确认下信息

CF_tokens_confirm.png

  • B_4.获得我们的API Key,保存好你的API key

Mnxxxxxxxxxxxxxxxxxxx
CF_tokens_get&test.png
同时注意页面会给你一个形如下列的测试指令:

curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
     -H "Authorization: Bearer MnLX1qFiX-DMZD2nj1To2zW4Xupd4d9bgPNp5Dgn" \
     -H "Content-Type:application/json"

粘贴到ssh执行看看返回数据,如果类似以下语句

{"code":10000,"message":"This API Token is valid and active"

则ok


创建完毕,点击COPY保存好
然后类似咱们tencent的DDNS获取更新脚本,可以书写如下:
Cloud Flare DDNS自动获取脚本范例

#!/bin/bash
 
###############  授权信息(需修改成你自己的) ################ 
# CloudFlare 注册邮箱
auth_email="user@example.com" 
# CloudFlare Global API Key,下一节会说到
auth_key="c2547eb745079dac9320b638f5e225cf483cc5cfdda41"  
# 做 DDNS 的根域名
zone_name="example.com" 
# 做 DDNS 的域名,创建成功后就是通过该域名访问内网资源
record_name="www.example.com"
 
######################  修改配置信息 ####################### 
# 域名类型,IPv4 为 A,IPv6 则是 AAAA
record_type="AAAA"
# IPv6 检测服务
ip=$(curl -s https://ipv6.vircloud.net)
# IPv4 检测服务
#ip=$(curl -s https://ipv4.vircloud.net)
# 变动前的公网 IP 保存位置
ip_file="ip.txt"
# 域名识别信息保存位置
id_file="cloudflare.ids"
# 监测日志保存位置
log_file="cloudflare.log"
 
######################  监测日志格式 ######################## 
log() {
    if [ "$1" ]; then
        echo -e "[$(date)] - $1"  $log_file
    fi
}
log "Check Initiated"
 
######################  判断 IP 是否变化 #################### 
if [ -f $ip_file ]; then
    old_ip=$(cat $ip_file)
    if [ "$ip" == "$old_ip" ]; then
        echo "IP has not changed."
        exit 0
    fi
fi
 
######################  获取域名及授权 ###################### 
if [ -f $id_file ]  [ $(wc -l $id_file | cut -d " " -f 1) == 2 ]; then
    zone_identifier=$(head -1 $id_file)
    record_identifier=$(tail -1 $id_file)
else
    zone_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$zone_name" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" | grep -Po '(?&lt;="id":")[^"]*' | head -1 )
    record_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?name=$record_nametype=$record_type" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json"  | grep -Po '(?&lt;="id":")[^"]*')
    echo "$zone_identifier"  $id_file
    echo "$record_identifier"  $id_file
fi
 
######################  更新 DNS 记录 ###################### 
update=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records/$record_identifier" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" --data "{\"id\":\"$zone_identifier\",\"type\":\"$record_type\",\"name\":\"$record_name\",\"content\":\"$ip\"}")
 
#########################  更新反馈 ######################### 
if [[ $update == *"\"success\":false"* ]]; then
    message="API UPDATE FAILED. DUMPING RESULTS:\n$update"
    log "$message"
    echo -e "$message"
    exit 1 
else
    message="IP changed to: $ip"
    echo "$ip"  $ip_file
    log "$message"
    echo "$message"
fi

编辑保存为ddns.sh,主要修改auth_email为你的CF邮箱、auth_key为API KEY、zone_name为你的主域名,record_name为你要作为DDNS的二级域名(之前做好解析,解析记录随便填127.0.0.1就可以)

bash ddns.sh

测试看看cloudflare是否更改成功,没问题后赋予执行权限同时加入自动执行任务清单:
chmod +x ddns.sh
crontab -e配置Crontab任务
添加如下代码

*/5 * * * * bash /root/ddns.sh

每个5分钟检测一次(每间隔4分钟),IP是否改变。
crontab基本用法参考我这篇文章第二部分:


CF的脚本暂时用不着未亲测,感兴趣的可以去原作者南晴浪大佬探讨:

https://blog.sometimesnaive.org/article/5

或者参考:

https://op.ci/618.html

希望能对囊中羞涩或者爱折腾购买NAT机器的朋友一点指引,获得稳定的域名访问/家庭内网群晖随身娱乐/某些科学上网配置域名访问配置隐藏源ip/NAT私人机场等用途,注意合规使用,莫做违法之事。

最后附送NAT机器建站nginx配置参考:

NAT机器Nginx配置范例

server {
  listen 20788 ssl http2;
  root /home/wwwroot/lolimoe.ltd;
  index index.html index.htm index.php;
  #charset koi8-r;
  access_log /var/log/nginx/lolimoe.ltd.access.log main;
  server_name zhenjiang.lolimoe.ltd;
  ssl_certificate "/usr/local/cert/lolimoe_ltd.crt";
  ssl_certificate_key "/usr/local/cert/lolimoe_ltd.key";
  ssl_session_timeout 10m;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
  ssl_prefer_server_ciphers on;

  error_page 404 /404.html;
  error_page 500 502 503 504 /50x.html;
  location = /50x.html {
    root /usr/share/nginx/html;
  }
  client_max_body_size 8888m;
  location / {
    index index.html index.php;

    if (-f $request_filename/index.html) {
      rewrite (.*) $1/index.html break;
    }
    if (-f $request_filename/index.php) {
      rewrite (.*) $1/index.php;
    }
    if (!-f $request_filename) {
      rewrite (.*) /index.php;
    }
  }
  location ~ \.php {
    fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  }
  location ~ ^.+\.php {
    fastcgi_split_path_info ^(.+\.php)(.*)$;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
  }
  location ~ /.ht {
    deny all;
  }
  location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
    expires 15d;
  }
  location ~ .*\.(js|css)?$ {
    expires 1d;
  }
}

Last modification:January 18th, 2020 at 11:57 pm
If you think my article is useful to you, please feel free to appreciate