使用bind9配置本地DNS服务器
我自己有一些小型的卡片机,像树霉派2B、3B+、USB-Armory等设备都连接在家庭网络里,这些小型设备可以当作内网里的机器使用,可以在内部部署一些服务,类似于一个公司的内网环境。但因为是在路由器下面,通过DHCP分配内网IP,所以在访问服务的时候每次都要记下IP十分不方便。通常我也会使用SSH登录我的内网机器,但是记住四五个IP地址对我来说是非常困难的一件事情。有没有什么办法可以让我像访问外部网站一样,访问我的内网机器呢?
我们知道访问外网网站一般都使用域名来访问,公网域名服务器把我们要访问的域名解析成对应的公网IP返回来,再使用公网IP去访问对应的网站。所以用户只需要记住网站的域名就可以了,因为域名是文字类型的,有语义,方便记忆,也就比使用IP直接访问更加方便一些。于是我们如果把内网环境和外网环境作一个对比,差别就是内网中少一个可以将域名转换成内网IP的域名服务器。
了解到这些,我准备把内网中的一台树莓派配置为一个域名服务器来方便的访问内网中的各个机器。在配置域名服务器之前我们必须计划一下域名怎么分配,而且内网中的各机器分配到的IP地址也应该是不变的静态类型的IP。幸运的是路由器的DHCP自动分配IP地址可以实现机器的MAC地址和所分配的IP地址绑定功能,也就是说,你可以为指定的机器分配一个在内网环境中不会改变的唯一IP地址,这样就方便我们把域名和IP地址作映射了。
我把内网域名结构定义成: <host>.<domain-name>
, 其中<host>
为内网各机器的名称,我们可以自定义。<domain-name>
是域名,也可以自定义。
比方说我的两个树霉派机器分别是2B、3B+,并且路由器给它们MAC绑定分配的IP地址分别是: 192.168.0.104
、192.168.0.105
,自己起一个域名: jokerhome.com
,那么我们的域名映射关系可以定义如下:
域名 | 内网IP |
---|---|
pi2.jokerhome.com | 192.168.0.104 |
pi3.jokerhome.com | 192.168.0.105 |
下面就让我们在192.168.0.105
这树霉派3B+上部署DNS域名解析服务吧
首先通过我自己的电脑(Mac)终端访问树霉派3B+
$ ssh pi@192.168.0.105
...
pi@RPi3BPlus:~ $
然后我们安装一个开源的DNS服务软件bind9
:
pi@RPi3BPlus:~ $ sudo apt-cache search bind9
bind9 - Internet Domain Name Server
...
pi@RPi3BPlus:~ $ sudo apt-get install -y bind9
当安装完成后,我们进入它的配置文件目录下面配置内网机器的域名和IP映射关系。
pi@RPi3BPlus:~ $ cd /etc/bind
pi@RPi3BPlus:/etc/bind $ ls
bind.keys db.255 db.root named.conf.options
db.0 db.empty named.conf rndc.key
db.0.168.192 db.jokerhome.com named.conf.default-zones zones.rfc1918
db.127 db.local named.conf.local
pi@RPi3BPlus:/etc/bind $
域名解析包含正向和返向两个过程,正向就是通过文本的域名向IP地址解析的过程,反向过程就是通过IP地址查找对应的文本形式的域名。所以我们需要修改配置文件named.conf.local
, 添加正向解析和反向解析两个配置块,区块的名称尽量取有意义的,方便理解:
zone "jokerhome.com" {
type master;
file "/etc/bind/db.jokerhome.com";
};
zone "0.168.192.in-addr.arpa" {
type master;
file "/etc/bind/db.0.168.192";
};
上面第一个zone
定义正向解析的相关配置,master
表求是主DNS解析器。file
指定的路径,表达具体的映射关系在指定路径的文件内定义。第二个zone
定义反向解析配置,类同。
然后我们分别在对应file
指定的路径下编辑对应的文件,如果没有对应文件,需要自己创建。两个映射文件的内容具体如下:
pi@RPi3BPlus:/etc/bind $ cat db.jokerhome.com
;
; BIND data file for local loopback interface
;
@ IN SOA jokerhome.com. root.jokerhome.com. (
2 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
NS ns
ns IN A 192.168.0.105
pi3 IN A 192.168.0.105
pi2 IN A 192.168.0.104
pi@RPi3BPlus:/etc/bind $ cat db.0.168.192
;
; BIND reverse data file for local loopback interface
;
@ IN SOA jokerhome.com. root.jokerhome.com. (
1 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
NS ns.jokerhome.com.
105 IN PTR ns.jokerhome.com.
104 IN PTR pi2.jokerhome.com.
105 IN PTR pi3.jokerhome.com.
其中@
的值和zone
定义的名称是一样的,在文件db.jokerhome.com
里的@
就相当于jokerhome.com
, 在文件db.0.168.192
中@
就相当于0.168.192.in-addr.arpa
在文件db.jokerhome.com
中
pi3 IN A 192.168.0.105
被展开后就相当于:
pi3.jokerhome.com IN A 192.168.0.105
因为pi3后面没有跟.
号,所以它的实际值会把zone
的名称jokerhome.com
补在后面。
在文件db.0.168.192
中
105 IN PTR ns.jokerhome.com.
被展开后相当于:
105.0.168.192.in-addr.arpa IN PTR ns.jokerhome.com.
注意到这里的PTR后面的域名最后加了一个.
,表明这是一个绝对指定的字段,不会自动把zone
名称0.168.192.in-addr.arpa
拼在后面,而如果不加.
,那么ns.jokerhome.com
就会变成ns.jokerhome.com..0.168.192.in-addr.arpa
, 这显然是不正确的。
这两个文件分配从正反两个方向定义了域名和IP的映射关系。当定义好配置后,我们可以分别检查一下,它们是否配置正确:
pi@RPi3BPlus:/etc/bind $ named-checkzone "jokerhome.com" "/etc/bind/db.jokerhome.com"
/etc/bind/db.jokerhome.com:4: no TTL specified; using SOA MINTTL instead
zone jokerhome.com/IN: loaded serial 2
OK
pi@RPi3BPlus:/etc/bind $ named-checkzone "0.168.192.in-addr.arpa" "/etc/bind/db.0.168.192"
/etc/bind/db.0.168.192:4: no TTL specified; using SOA MINTTL instead
zone 0.168.192.in-addr.arpa/IN: loaded serial 1
OK
可见正反两个方向的配置都显示OK。那么我们启动服务,实际的测试一下是否能够正常解析:
pi@RPi3BPlus:/etc/bind $ sudo systemctl start bind9.service
pi@RPi3BPlus:/etc/bind $ sudo systemctl status bind9.service
● bind9.service - BIND Domain Name Server
Loaded: loaded (/lib/systemd/system/bind9.service; enabled; vendor preset: en
Active: active (running) since Fri 2019-07-05 11:41:48 BST; 38s ago
Docs: man:named(8)
...
可见DNS
服务已经启动成功,我们测试DNS解析还需要安装一个工具包dnsutils
:
pi@RPi3BPlus:/etc/bind $ sudo apt-cache search dnsutils
dnsutils - Clients provided with BIND
...
pi@RPi3BPlus:/etc/bind $ sudo apt-get install -y dnsutils
安装完成DNS测试工具后我们尝试解析一下内网机器的域名,看看能不能得到正确的IP地址:
pi@RPi3BPlus:/etc/bind $ dig @192.168.0.105 pi2.jokerhome.com
...
;; ANSWER SECTION:
pi2.jokerhome.com. 604800 IN A 192.168.0.104
...
@192.168.0.105
表示dig
命令使用192.168.0.105
这个域名服务器对域名pi2.jokerhome.com
进行解析。可以看到我们已经可以成功的解析pi2.jokerhome.com
这个域名为IP:192.168.0.104
了。这说明我们的内网域名服务已经生效。此时如果我们解析外网域名会发现无法解析,因为我们只指定了内网机器IP和域名的映射关系,并不知道外网域名应该怎么解析。
pi@RPi3BPlus:/etc/bind $ dig @192.168.0.105 www.baidu.com
// 这里卡住了,解析不了
bind9
提供把不能解析的域名交给其它域名服务器解析的功能。所以我们需要把外网域名的解析抛给路由器去处理,因为我们正常上网时默认配置路由器为DNS服务器。我们只需要修改配置文件named.conf.options
:
options {
directory "/var/cache/bind";
...
forwarders {
192.168.0.1;
192.168.1.1;
};
...
dnssec-validation no;
...
};
我们只需要在forworders
里添上路由器在内网中的IP地址就可以把不能解析的域名交给路由器去解析了。同时还要把dnssec-validation
设置为no
,因为我们的本地DNS服务器设置比较粗糙,没有实现dns安全解析验证的功能。至此我们保存文件后,重新启动一次bind9
服务。
pi@RPi3BPlus:/etc/bind $ sudo systemctl restart bind9.service
这样我们的本地DNS服务器就配置完成了,下一步就是在你的PC端把本地DNS服务器的IP地址设置为你网卡的默认DNS服务器地址就可以了。
我在我的树霉派2B上有一个代码仓库平台服务。当这个本地DNS服务完成后,就可以直接使用pi2.jokerhome.com:3000
这种方法去访问本地服务,而不需要每次都使用IP方式:192.168.0.104:3000
去访问了。这便于我之后可以在内网中部署一个小型公司生产线的原型。
如果觉得使用端口号访问有些不方便,那么还可以在机器上开启nginx端口转发功能,让不同的域名对应到不同的端口服务上面。