动态 DNS——问题解决的实例
前几天在 Linux Journal IRC 聊天室 (#linuxjournal on Freenode) 中,我向大家抱怨 no-ip.com 在没有警告的情况下删除了我的帐户。我的家庭 IP 地址已经几个月没有改变了,由于没有更新,它看起来像是被废弃了。问题是,尽管 IP 地址没有改变,但我一直使用动态 DNS 域名来连接到我的住宅。当帐户被删除后,域名无法解析,我再也无法连接到我的住宅了。
IRC 聊天室的朋友们非常乐于助人,他们推荐了其他的动态 DNS 托管服务。尽管现在仍然有一些免费的选择,但我对依赖别人来管理我的 DNS 服务感到沮丧。因此,像任何一个技术爱好者一样,我试图找到一种方法来自己托管动态 DNS 服务。我原以为在我的主机托管服务器上简单地 apt-get install
就可以了,但事实证明,并没有一个简单的动态 DNS 服务器软件包——至少,我没有找到。所以,又像任何一个特别喜欢钻研的技术爱好者一样,我决定自己动手。它既不优雅,也不漂亮,而且实际上只是一堆廉价的技巧。但是,这是一个使用现有工具解决问题的好例子,因此在本文中,我将解释这个过程。
首先,重要的是要指出几点。本文的目的并不是真正解释制作自托管动态 DNS 系统的最佳方法。事实上,可能有一打更好的方法可以做同样的事情。这才是重点。你越熟悉 Linux 工具,你在解决问题时就越有资源。我将详细介绍我采取的步骤,希望大多数读者能够采用我的方法并在此基础上改进很多倍。这种类型的合作正是开源社区如此伟大的原因!让我们开始吧。
我的个人工具箱我们都有稍微不同的技巧。我很幸运地属于“非常幸运”的类别,这要感谢 Kyle Rankin 向我介绍了免费的 Raspberry Pi 主机托管服务。当涉及到这类事情时,一台具有静态 IP 地址的完整 Linux 机器真是一个万能工具,但也许别人的解决方案不需要完整的服务器。
除了 Raspberry Pi 服务器,我还有一台家用 Linux 服务器、一台家用路由器和一些我拥有的域名。我还在几个 Web 托管服务器上拥有帐户,以及像 Dropbox、Google Drive 和其他一些基于云的存储帐户。
第一个问题——我的 IP 是什么?动态 DNS 托管的优点在于,无论您的家庭 IP 地址是什么,即使它发生了变化,相同的域名仍然可以解析。诚然,我的家庭 IP 地址已经几个月没有改变了,但我仍然使用 DNS 名称来访问它。因此,当我在 no-ip.com 的帐户被删除时,我就无法知道我的家庭 IP 是什么。
互联网上有许多网站可以返回您的 IP 地址。因为我的动态 DNS 帐户刚刚被删除,所以我真的不想依赖免费的在线服务来检测我的 IP 地址。幸运的是,这个难题很简单。只需几行托管在任何支持 PHP 的 Web 主机上的 PHP 代码即可。例如,我的 IP 检测脚本托管在 http://snar.co/ip(我的个人域名——欢迎随意使用)。请在图 1 中查看其运行情况。它只包含以下内容
<?php
// Save the IP to a variable
$ip_address = $_SERVER['REMOTE_ADDR'];
// To display the IP:
echo $ip_address;
?>

图 1. 与许多“我的 IP 是什么”服务不同,我的脚本只返回一个 IP 地址。
令人沮丧的是,尽管我有一种在家检测我的 IP 地址的方法,但我实际上并不在家,所以我陷入了两难境地。幸运的是,我的妻子在家。我给她发短信,让她访问我的 snar.co 地址,并告诉我她返回的 IP 地址。一旦我有了那个 IP 地址,我就可以连接到我的家用服务器并设置一些自动化。
让我们永远不要再这样做了倒不是我不喜欢给妻子发短信,只是指望有人在家来检查 IP 地址并不是自己动手搭建 DNS 的最佳方式。还有一种可能性是,我梦想中的任何动态 DNS 解决方案都可能会失败,我想确保我始终可以找出我的家庭 IP 地址。
我考虑了几种不同的方法来使我的 IP 地址始终可访问。最简单的方法是设置一个 cron 作业,定期将我的 PHP 脚本的结果上传到我的 Raspberry Pi 或我的某个 Web 主机。为了做到这一点,我只需要设置 SSH 密钥,以便我的家用服务器可以在没有任何交互式身份验证的情况下上传文件。事实上,这就是我推荐的做法。然而,碰巧我很懒。我实际上做的是设置一个 cron 作业,将我的 IP 地址复制到我的 Dropbox 文件夹中的一个文本文件中。它不如 scp
更好,但最终结果是相同的。这是我的 cron 作业的样子
1 * * * * /usr/bin/wget -r --quiet -O ~/Dropbox/Public/IP.txt
↪'http://snar.co/ip'
它基本上每小时用我当前的家庭 IP 地址更新我的 Dropbox 文件夹。由于 Dropbox 会同步到我拥有的每台设备和计算机上,因此它始终可以随时访问。
但这仍然不是 DNS现在事情变得有点复杂了。因为我有一个完整的服务器和一些域名可以使用,所以设置 BIND 并提供一个子域名是有意义的。BIND 确实具有使用远程更新命令更改主机条目的能力。它需要设置加密密钥,当然,BIND 守护程序也必须正确配置。还记得我说过我很懒吗?现在仍然如此。因为我只想为我的家庭 IP 地址提供一个域名,所以我选择了一些更简单的东西。
DNSMasq 是一个非常简单的守护程序,它运行在我的基于 Linux 的家用路由器上。它同时处理 DHCP 服务和 DNS 解析。在这两种情况下,服务都非常精简和简单,但如果你的全部需求只是简单的 DNS 解析,那么没有比 DNSMasq 更简单的了。它会查看服务器的 /etc/hosts 文件,并在查询时提供这些条目。我所要做的就是将我的家庭 IP 地址放入我的服务器的 /etc/hosts 文件中,并定期向 DNSMasq 发送 HUP 信号以重新加载其文件。一个简单的 DNS 服务器是解决问题的最后一块拼图。接下来是实施。
整合所有部分第一步是创建一个 DNS 条目,我可以使用 DNSMasq 更新它。这比大多数人意识到的要简单。我只是添加了一个指向我的 Linux 服务器的 NS 记录。所以基本上,我有一个看起来像这样的条目
home.mydomain.org. IN NS server.mydomain.org.
这意味着,“当解析 home.mydomain.org 或其任何子域名时,请向 server.mydomain.org 询问地址。” 这正是我想要的,因为这样一来,每当我(或任何其他人)尝试访问 home.mydomain.org 时,它都会要求我的服务器解析该名称。剩下的唯一事情是让我的服务器(运行 DNSMasq)以正确的 IP 地址响应。这意味着还需要几个 cron 作业。
还记得我保存在 Dropbox 中的酷炫的 IP.txt 文件吗?为了拼凑我服务器上的 /etc/hosts 文件,我不得不稍微修改一下我的 PHP 脚本。为了创建与 /etc/hosts 兼容的输出,我将其更改为
<?php
// Save the IP to a variable
$ip_address = $_SERVER['REMOTE_ADDR'];
// To display the IP:
echo $ip_address;
echo " home.mydomain.org";
?>
请注意“home”之前的空格。现在我的 Public Dropbox 文件夹中的文件是一个格式正确的 /etc/hosts 行。为了将其与我原来的 hosts 文件结合起来,我在我的服务器上创建了一个文件夹 /etc/hosts.d/,并将 /etc/hosts 复制到 /etc/hosts.d/00-original。
还跟着我吗?最后一步是在服务器上运行以下脚本。我每小时运行一次此脚本,因此如果我的 IP 地址发生变化,最多一个小时即可纠正。这是服务器脚本
#!/bin/bash
/usr/bin/wget -r --quiet -O /etc/hosts.d/home
↪'https://dl.dropbox.com/xxx/IP.txt'
cat /etc/hosts.d/* > /etc/hosts
killall -SIGHUP dnsmasq
第一行检索存储在我的 Dropbox Public 文件夹中的当前 IP 地址。第二行通过连接 /etc/hosts.d/ 中的所有文件来创建一个新的 /etc/hosts 文件。最后,我向 dnsmasq 发送 SIGHUP 信号,以便它重新加载 /etc/hosts 文件。
最后的想法作为演示问题解决的一种方式,我真正喜欢这个例子的原因是,有很多不同的方法可以实现相同的结果。我的解决方案远非最佳。我马上就能想到
-
我可以让我的家用服务器上的脚本检查 IP 地址是否发生变化,而不是只是不断更新。如果发生变化,它可以启动远程服务器上的更新过程,而不是每小时更新 hosts 文件,无论是否需要。
-
根据您使用的 DNS 托管公司,可能可以使用远程命令更改地址。也可能有一些免费的 DNS 服务器直接由像 ddclient 这样的客户端支持。
-
由于我的解决方案需要一台具有静态 IP 地址的远程 Linux 服务器,这使得我的特定解决方案对许多人来说是不可访问的。这只是意味着您需要更加努力地思考才能想出一个解决方案!
似乎再次声明我的免责声明是恰当的:我刚刚解释的过程并不是解决 IP 地址更改问题的最有效方法。我的方法很粗糙,我的脚本很简单,而且我没有包含任何错误纠正。(如果我无法从 Dropbox 下载文件会发生什么?我的脚本会失败吗?很可能会!)本文的目的是让您思考。Linux 为我们提供了强大、灵活且最重要的是有用的工具。有时您需要创建一些数字胶带并在运行时解决问题。
如果您似乎无法找到解决特定问题的方法怎么办?这就是 Linux 社区真正闪耀的地方。请访问 #linuxjournal 频道,或参加当地的 LUG 会议。那里的人们和我非常相似,并且渴望帮助解决问题。每个人都喜欢谜题,当您可以使用 Linux 来解决它时?太棒了!