自己弄一个动态 DNS 服务

Network

虽然有自己的 VPS ,但是有时候还是需要动态 DNS (也就是 DDNS ) 来做一些事情,比如在公网上连接到自己宿舍的电脑,总不能打个电话问下室友 IP 是什么吧。。。然而现在已经有的 DDNS 的方案虽说也不少,但是要么贵,要么坑,要么是就国外服务连个请求都发不通,于是我决定自己弄一个。

注意本文的方案需要一个有固定 IP 地址的服务器来承担 NS 服务器的任务,如果你只是想把自家电脑当作服务器用,那就不必往下看了,这个方案可能不适合你。

其实所谓的 DDNS ,就是个特殊的 NS 服务器,只是它返回的查询结果能因某个客户端所在的 IP 动态地改变。所以,首先我们就弄个 NS 服务器出来。

现在在自己的 VPS 放 DNS 服务器的方案不少,由于并没有多少解析量,我选择了轻量而且配置简单的 dnsmasq) ,它也被用在 OpenWRT 上,作为 DNS 缓存服务器来加快站点的 DNS 解析速度。使用各大包管理器都可以很方便地安装它。

apt-get install dnsmasq

默认情况下, dnsmasq 优先解析/etc/hosts文件中的记录,并作为返回的请求结果。于是只需要在/etc/hosts文件中加入自己的解析行即可。你还可以在/etc/dnsmasq.conf中修改此默认值,反注释no-hosts可以关闭对hosts的解析,还可以使用addn-hosts=来指定其他文件来担任此职。例如,我的服务器地址是 caoyue.com.cn ,我往/etc/hosts中加入这样的一行。

123.123.123.123 test.caoyue.com.cn

然后使用/etc/init.d/dnsmasq restart重启一下 dnsmasq 服务,这样就把 test.caoyue.com.cn 解析到了 123.123.123.123 。我们可以直接在终端里查看设置的结果(我的服务器的地址是 caoyue.com.cn )。

$ nslookup test.caoyue.com.cn caoyue.com.cn
Server:         caoyue.com.cn
Address:        120.27.113.124#53

Name:   test.caoyue.com.cn
Address: 123.123.123.123

然后到自己域名的 DNS 提供商哪里增加一条 NS 记录,指向自己的服务器,就像这样。

test    NS    caoyue.com.cn    600

稍等片刻,不带第二个参数 nslookup 新增的这个域名,如果返回了正确的结果(本例中是 123.123.123.123),就说明已经设置好了。

搞定了 NS 服务器,然后就要解决动态更新的问题。实际上动态更新也就是客户端定时发送请求给服务器,然后服务器再根据客户端的请求修改记录。这里我是用 PHP 来实现,首先得把/etc/hosts的权限设置成 0666 以便使用 PHP 修改,如果担心会产生安全问题,那么你还可以在/etc/dnsmasq.conf里设置addn-hosts=

<?php

// TODO: 在这里添加前置验证,防止接口被非法调用

// 需要配置的域名
$domain = 'test.caoyue.com.cn';

// hosts 文件位置,默认情况下是 /etc/hosts
$hosts_file_path = '/etc/hosts';

// 使用请求地址作为需要设置的 IP 地址
$ip_address = $_SERVER["REMOTE_ADDR"];

// 处理并修改 hosts 文件
$content = file_get_contents($hosts_file_path);
$content_array = explode("\n", $content);

$is_replaced = false;

$hosts_record = $ip_address . "\t" . $domain;

foreach ($content_array as $key => $value) {
    if (strpos($value, $domain) !== false) {
        $content_array[$key] = $hosts_record;
        $is_replaced = true;
        break;
    }
}

if (!$is_replaced) {
    $content_array[] = $hosts_record;
}

$result = implode("\n", $content_array);
file_put_contents($hosts_file_path, $result);

echo "OK";

然后客户端定时请求这个 php 即可,如果你像我一样使用是 OpenWRT ,你也可以往路由器的 crontab 里加入类似于这样的一行

*/30 * * * * /usr/bin/wget --spider "https://api.caoyue.com.cn/ddns-refresh.php"

当然你还可以使用其他方案,比如建立一个单独的账户,在它的.bashrc里写上更新脚本并使用 SSH 密钥验证,这样比 PHP 要安全些。

更新了/etc/hosts文件之后还得重启dnsmasq使更改生效,这里我使用了一种比较笨的方法,设置 crontab 让 dnsmasq 定时重启(因为得 root 权限),但是貌似找不到什么比较好的又能保证安全性的方法了。。。

Post Directory

文章目录