用自己的域名配置动态域名解析(DDNS) (三)

之前我写过ddns的两篇文章,但时过境迁,随着供应商对其cli工具的修改,shell已经无法匹配到其输出,带来的问题是shell脚本失效,所以此次改用了更为直接的方式:直接调用其API接口,而不再使用它们封装好的cli工具。
因为众所周知的一些地域性原因,我们的网络环境并不是真正的国际互联网,就造成了很多地域性的小气候,用户可选择的供应商并不多,此次依然以阿里云作为供应商。
需要声明的是这并不是给阿里云作广告,我也没有收取阿里的任何金融、物质或者精神方面的支持。


使用说明:
例如:将本程序代码拉回本地后 放在了 /mnt/apps/ddns/ 下

本程序默认的日志路径是 /mnt/logs/ddns/
建立这个路径:
sudo mkdir -p /mnt/logs/ddns/
sudo chmod 777 /mnt/logs/ddns/

打开 /mnt/apps/ddns/dns.php 按自己的实际需求修改以下变量
$dns["dev"]
$dns["domain_0"]
$dns["domain_1"]
$dns["domain_2"]
$dns["api"]["key"]
$dns["api"]["secret"]

接着执行:
chmod +x /mnt/apps/ddns/ipv4.sh
确保 ipv4.sh 具备可执行权限,因为我们需要它从网卡拿出ip地址

接着是定时任务,打开
/mnt/apps/ddns/ddns.cron
修改下面这三行中的 <你的本地用户名> 部份,改成你要用来执行定时任务的本地用户名,默认的是expl
MAILTO=<你的本地用户名>
HOME=/home/<你的本地用户名>/
*/1 * * * * <你的本地用户名> php /mnt/apps/ddns/dns.php >> /mnt/logs/ddns/ddns_aliyun_`date +'\%Y-\%m-\%d.\%H:\%M:\%S.\%N'`.txt

接着复制到 /etc/cron.d/ 中去
sudo cp -v /mnt/apps/ddns/ddns.cron /etc/cron.d/
留意一下复制过去后的属主,需要为 root:root
ls -laZh /etc/cron.d/ddns.cron
如果不是 root:root 的话就执行
sudo chown root:root /etc/cron.d/ddns.cron


到此ddns就部署完成了。

如果你的系统没有开启 cronie.service 的开机自启的话就执行:
sudo systemctl restart cronie.service
sudo systemctl enable cronie.service
一般说来 cronie.service 都是默认开机自启的,所以这一步一般不需要。
可以使用这条命令来确定一下:
sudo systemctl status cronie.service



----
话外话:
很多人对阿里封装的签名机制很是头疼,我也是对着其官方的文档看了半天,后来发现其文档中很多点都没有提到。
这里简单的说一下我的处理思路:
首先,生成时间戳时一定要注意时区。阿里云的服务器的时间戳是UTC时区的,所以生成的时间戳如果是东八区的话就会导致比阿里服务器早了八个小时,而服务器只接收十五分钟之内的时间差异,所以会导致请求失败。
再就是,阿里云的不同业务的api接口的base url 是有可能不同的。比如,我们这个程序用到的云解析的api其base url 是 alidns.aliyuncs.com 但是云服务器的base url就是 ecs.aliyuncs.com 。
同样的,不同业务的api接口也有其自己的版本号,此文写作时云解析的api版本号是 2015-01-09 。
签名生成时是需要把 公共请求参数 和 业务请求参数 一起排序的,而不是把公共请求参数和业务请求参数分别排序后再拼接。
再就是,排序后分别按 https://help.aliyun.com/document_detail/315526.html#sectiondiv-6jf-89b-wfa 的方式编码后再拼接,而不是拼接后再编码。因为阿里云要求 = 和 & 要保持原样,不能被编码,对这个处理逻辑我真的想不出原因。
再一步时,前面加上请求模式+&+/的编码后字符串+&+上一步中的字符串编码后的字符串:比如本程序中用这一行来拼接这个字符串:
$tss_1 = 'GET&' . rawurlencode ( '/' ) . '&' . rawurlencode( $qs ) ;
然后才到了真正生成签名的步骤,这一步时才会用到AccessKeySecret:先HMAC-SHA1,再base64,再https://help.aliyun.com/document_detail/315526.html#sectiondiv-6jf-89b-wfa
$signature = rawurlencode ( base64_encode ( hash_hmac ( "sha1", $tss_1, $dns["api"]["secret"].'&', true ) ) ) ;
然后把签名附在请求url的后面了
$tss_2 = $dns["api"]["u"] . "?" . $qs .'&Signature=' . $signature ;
这一圈转下来,不把人弄迷糊不肯罢休的架势...
回头一想弄成这样是为什么呢?
如果说是为了请求的完整性,那不完整的请求服务器直接报错,岂不是更省事?不管是阿里还是客户都省事。
如果说是为了不在get模式中暴露用户的secret的话,直接用post模式就可以避免了啊,也没必要搞这么麻烦。
别的原因?为了推广cli工具?或者它封装好的SDK?那些我就懒的吐槽了。
总之,我没有想出合理的原因。

本文由 http://www.timeline.menu/article/co/ddns.3.html 原创,转载时请标明出处。
本文设有讨论区,地址是 https://www.expl.cc/discuss/viewtopic.php?t=128 ,欢迎发表你对本文的看法。如文中有错误,也欢迎指出。