😑苦于 IPv4 资源紧张,现在的 IP 地址默认都是提供内网 IP,可出不可进的意思;即便我们申请到了公网 IP,也并不是一个固定的静态 IP,一般隔天就变。这就给我们带来了新的麻烦,每次都要查一下 IP 地址,有了 DDNS 技术,可以将动态 IP 映射到域名,域名是不变的,所以通过域名可以来直接访问主机。可市面上的 DDNS 要钱,路由器的 DDNS 功能虽然免费但非常不稳定。

DDNS(Dynamic Domain Name Server,动态域名服务)是将用户的动态 IP 地址映射到一个固定的域名解析服务上,用户每次连接网络的时候客户端程序就会通过信息传递把该主机的动态 IP 地址传送给位于服务商主机上的服务器程序,服务器程序负责提供DNS 服务并实现动态域名解析。

起初我利用的是主机后台运行一个脚本监控 IP 地址,变动则自动发送到我的邮箱,几天前发现可以直接通过 API 接口操作阿里云域名解析服务,终于可以自动修改域名解析一劳永逸了。

这个脚本很简单,大体两个功能

  1. 监听 IP 地址
  2. 重新进行域名解析

程序放在 GitHub:https://github.com/lexinhu/ddns-micro/

修改 application.yml 中的配置信息即可运行,可以自己打包运行在任何平台。

Linux 启动命令参考如下

nohup java -jar -Xms128m -Xmx256m -XX:PermSize=128M -XX:MaxPermSize=256M ddns-micro.jar &

获取公网 IP 地址,最好的方法是使用网络请求网站,这里选择的是网络上公开免费的获取 IP 地址的网站,省了很多功夫。

@Scheduled(fixedRate = 1800000)
public void ipTask() {
    String ipv4 = "";
    BufferedReader in = null;
    try {
        URL realUrl = new URL(pullAddress);
        // 打开和 URL 之间的连接
        URLConnection connection = realUrl.openConnection();
        // 定义 BufferedReader 输入流来读取URL的响应
        in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        String line;
        while ((line = in.readLine()) != null) {
            ipv4 += line;
        }
        // TODO: 2022/5/10 更新阿里云域名解析
        aliyunDomain.updateDomainRecord(ipv4);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (in != null) {
                in.close();
            }
        } catch (Exception e2) {
            e2.printStackTrace();
        }
    }
}

修改阿里云域名解析,这里要注意的是需要去判断哪条记录以及记录的解析内容是否需要更改,不可疏忽。

// 修改阿里云域名解析记录
public void updateDomainRecord(String ipv4) throws Exception {
    Client client = this.initialization();
    DescribeDomainRecordsRequest domainRecordsRequest = new DescribeDomainRecordsRequest();
    domainRecordsRequest.setDomainName(DOMAIN_NAME);
    // 解析记录列表
    DescribeDomainRecordsResponse domainRecordsResponse = client.describeDomainRecords(domainRecordsRequest);
    for (DescribeDomainRecordsResponseBody.DescribeDomainRecordsResponseBodyDomainRecordsRecord record : domainRecordsResponse.body.domainRecords.record) {
        UpdateDomainRecordRequest updateDomainRecordRequest = new UpdateDomainRecordRequest();
        // 找到指定的二级域名
        if (record.RR.equals(TWO_DOMAIN_NAME)) {
            // ip 变动则重新解析
            if (!record.value.equals(ipv4)) {
                BeanUtils.copyProperties(record, updateDomainRecordRequest);
                updateDomainRecordRequest.setValue(ipv4);
                client.updateDomainRecord(updateDomainRecordRequest);
                System.out.println(record.RR + "." + DOMAIN_NAME + "的主机记录更新为记录值: " + ipv4);
            }
            break;
        }
    }
}

Last modification:July 3, 2022
如果觉得我的文章对你有用,请随意赞赏