Dynamic DNS (ddns)对于从公网访问内网的资源是必不可少的。我需要解析的域名在CloudFlare上管理。我家里的主路由器虽然可以安装CloudFlare的ddns插件,但这个插件只能读取WAN口ip来认作当前公网ip。无奈主路由器是接在电信入户光猫后面,又懒得折腾光猫搞桥接,所以主路由器的WAN口还是内网地址,无法使用ddns插件。
于是考虑自己通过虚拟主机上的php搭建一个个人ddns,由本地路由器定时向该php网页发起请求,php获取该请求发起方的公网ip后,检查并设置CloudFlare的DNS记录。
Php实现方面,可以参照网上找到的这个实现 https://github.com/mumi/CloudFlare-Dynamic-DNS . 原本我确实计划直接在php里读取请求方公网ip,后来发现如果使用了CloudFlare的CDN,请求方ip会变成CloudFlare的CDN服务器:-p 于是,最终还是在路由器的脚本里利用第三方ip查询网站(例如:whatismyip.akamai.com)确定自己的公网ip,再做为参数发给php。话说这种实现方式里php网页有些多余了,完全可以直接在路由器脚本里更新DNS记录。不过本例还是保持php方案,可以最灵活地支持各种场景。
路由器的脚本除了执行本机ip查询外,还要通过nslookup查询当前DNS记录。如果两者不一致,则执行DNS记录更新操作。这里比较麻烦的是nslookup返回格式比较复杂,要在不同情况下准确提取出DNS记录IP需要一番周折。以下脚本代码在华硕RT-AC86U上调试通过,仅供参考。
#!/bin/bash
domain_name='***.********.***'
domain_email='******@*******.com'
key=**************
ip_check_url='whatismyip.akamai.com'
#Read and parse DNS record for domain_name
record_raw=$(nslookup $domain_name | sed -n '5p' )
record_simple=$(echo $record_raw | grep -o '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*$')
if [ "$record_simple" == "" ]; then
record_comp=$(echo $record_raw | grep -o '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*\s')
record_simple="$(echo -e "${record_comp}" | tr -d '[:space:]')"
fi
echo "Current DNS record: $current_record"
#Detect current public IP
current_ip=$(curl -s $ip_check_url)
echo "Actual IP: $current_ip"
#Update DNS record if current public IP changes
if [ "$record_simple" != "$current_ip" ]; then
echo 'Updating DNS...'
curl -k -X GET "https://*****.***/cf-ddns.php?domain=$domain_name&
else
echo 'No need to update.'
fi
最后,在路由器的定时任务中添加这个DDNS检查/更新脚本。RT-AC86U需要在/jffs/scripts目录里添加init-start脚本,确保重启后定时任务仍然保持。详情可以参见:https://bugxia.com/946.html