怎样部署gdnsd建立DNS服务

2020年11月17日 | 分类: 【技术】

参考:https://sb.sb/blog/debian-install-gdnsd/

【介绍】

gdnsd 是一款权威 DNS (Authoritative-only DNS)服务器软件,因为自带 GeoIP 插件,适合自建 CDN 做分区解析,WikiPedia 就是使用 gdnsd 进行全球 CDN 分区解析。

国内的DNS服务商如 CloudXNS, DNSpod 所提供的免费版DNS服务器都在国内,这样会造成国外的用户解析你的域名很慢。同理,国外的DNS服务商如 Cloudflare 的 DNS 服务器都在国外,造成国内的用户解析你的域名很慢。所以需要选择一家对国内外速度都友好的 ISP 来托管你的权威 DNS 服务器。

【部署】

注册 DNS 服务器:

假设 DNS 域名是 example.com ,购买并安装好两台 NS 服务器:

ns1.example.com 对应 IPv4 192.0.2.2 IPv6 2001:DB8::2
ns2.example.com 对应 IPv4 192.0.2.3 IPv6 2001:DB8::3

首先注册 Name Servers ,以 WHMCS 为例,登陆 Custom Portal 后,点击 Domains > My Domains > 进入您的域名管理页面,点击小工具的箭头,接着点击左侧的 Private Nameservers ,然后在右侧即可注册、管理或删除 NS 服务器。分别注册 ns1 和 ns2 即可。

安装 gdnsd:

apt-get install gdnsd

如果加了 Backports 则可以使用

apt-get -t stretch-backports install gdnsd

打开服务器端口:

打开 TCP / UDP 的 53 端口,否则 DNS 是无法工作的。

firewall-cmd --zone=public --add-port=53/tcp --permanent
firewall-cmd --zone=public --add-port=53/udp --permanent
service firewalld reload
firewall-cmd --zone=public --list-ports

配置 gdnsd:

百科:https://github.com/gdnsd/gdnsd/wiki
配置:https://github.com/gdnsd/gdnsd/wiki/GdnsdConfig
配置:https://github.com/gdnsd/gdnsd/wiki/GdnsdZonefile

逻辑规划:当国内用户请求 example.org 解析的时候, gdnsd 判断用户本地的 DNS 是否在国内,是的话解析到国内对应的服务器节点,如果不是,则默认解析到国外服务器节点。

首先登录 ns1.example.com:

gdnsd 需要有一个对应的 config 文件,需要自己创建,这里默认新建一个 /etc/gdnsd/config 文件,输入以下内容

options => {
  listen => any
  dns_port => 53
  chaos_response => "SBDNS"
}

service_types => {
  example_monitor => {
    plugin => http_status
    ok_codes => [200, 301, 302, 403, 404]
    vhost => example.org
    url_path => /
  }
}

plugins => { geoip => {
  maps => {
    china_map => {
      geoip_db => GeoLiteCity.dat
      datacenters => [default-dc, cn-dc]
      map => {
        AS => {CN => [cn-dc, default-dc]}
      }
    }
	
  }
  resources => {
  
    example_org => {
      map => china_map
      service_types => example_monitor
      dcmap => {
	  
        cn-dc => {
		addrs_v4 => 192.0.2.4
		addrs_v6 => 2001:DB8::4
		},

        default-dc => {
		addrs_v4 => 192.0.2.5
		addrs_v6 => 2001:DB8::5
		},
		
      }
    }

    }
	
  }
  
}

逐条解释:

options => {
  listen => any
  dns_port => 53
  chaos_response => "SBDNS"
}

options 是 gdnsd 的配置选项,一般无特殊需求的话可以监听本机的所有 IP ,所以这里 listen 选的是 any, DNS 服务器端口选默认的 53,chaos_response 则是 DNS 返回的软件版本,可以自己随便指定个名字:

service_types => {
  example_monitor => {
    plugin => http_status
    ok_codes => [200, 301, 302, 403, 404]
    vhost => example.org
    url_path => /
  }
}

这里因为我们开启了监控,并且使用的插件是 http_status ,如果不需要监控的话可以忽略


plugins => { geoip => {
  maps => {
    china_map => {
      geoip_db => GeoLiteCity.dat
      datacenters => [default-dc, cn-dc]
      map => {
        AS => {CN => [cn-dc, default-dc]}
      }
    }
	
  }
  resources => {
  
    example_org => {
      map => china_map
      service_types => example_monitor
      dcmap => {
	  
        cn-dc => {
		addrs_v4 => 192.0.2.4
		addrs_v6 => 2001:DB8::4
		},

        default-dc => {
		addrs_v4 => 192.0.2.5
		addrs_v6 => 2001:DB8::5
		},
		
      }
    }

    }
	
  }
  
}

这一段才是最重要的,也是本文的精髓所在,这里我们启用了 GeoIP 插件,设置的默认解析到国外的节点,国内用户对应一个 datacenter 叫做 cn-dc ,只要 gdnsd 判断该用户是国内请求的解析,那么就返回我们设置的国内 IP ,否则就返回默认的国外节点,如果不需要 IPv4 则可以直接写

cn-dc => 192.0.2.4
default-dc  => 192.0.2.5

安装 GeoIP 数据库:

IP数据库使用的是 Maxmind 免费的 GeoLite City,适用于精度要求不高的情况:

cd /etc/gdnsd/geoip && wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz && gzip -df GeoLiteCity.dat.gz

配置 zonefile:

配置 DNS 域名 example.com 所以新建一个 /etc/gdnsd/zones/example.com 文件,举例如下:

$TTL	86400

@	IN	SOA ns1.example.com.	hostmaster.example.com.	(
	1      ; serial
	7200   ; refresh
	900    ; retry
	1209600     ; expire
	10800    ; ncache
)

@		NS		ns1.example.com.
@		NS		ns2.example.com.

ns1		A	192.0.2.2
ns2		A 	192.0.2.3

ns1     AAAA	2001:DB8::2
ns2     AAAA	2001:DB8::3

这里默认设置的 TTL 是 86400 也就是一天,可以根据需要修改。

接着需要创建 /etc/gdnsd/zones/example.org 文件,举例如下:

$TTL	3600

@	IN	SOA ns1.example.com.	hostmaster.example.com.	(
	1      ; serial
	7200   ; refresh
	900    ; retry
	1209600     ; expire
	10800    ; ncache
)

@		NS		ns1.example.com.
@		NS		ns2.example.com.

@		DYNA	geoip!example_org

www		CNAME	example.org.

检查 gdnsd 配置:

gdnsd checkconf

如果最后三行输出如下,即成功配置:

# info: rfc1035: Loaded 71 zonefiles from '/etc/gdnsd/zones/'
# info: rfc1035: quiescence time is 3 seconds
# info: Configuration and zone data loads just fine

重启 gdnsd:

如果修改了 config 文件,那么我们则需要重启 gdnsd 服务,如果之后只是修改 zonefile 那么则无需这个步骤

gdnsd restart

配置 ns2.example.com 并同步:

由于 gdnsd 是个轻量级的 DNS 服务器,不带同步功能,所以需要按照上面的步骤重新配置一次 ns2.example.com 并且让他重启生效,为了今后方便同步,可以使用 rsync 来进行。

首先,在 ns1 和 ns2 都安装 rsync

apt-get install rsync

然后以 ns1 作为 master ,ns2 作为 slave ,每次修改 ns1 的文件并且自动同步到 ns2,以下命令均在 ns1 操作:

生成 SSH Key

ssh-keygen -t ed25519

查看并复制公钥 id_ed25519.pub:

cat ~/.ssh/id_ed25519.pub

把公钥的内容复制到 ns2 服务器的 ~/.ssh/authorized_keys 即可:

然后执行同步

rsync -avz --delete /etc/gdnsd/ ns2.example.com:/etc/gdnsd/

也可以写入 bash 脚本,比如 sync.sh

CONFDIR=/etc/gdnsd
rsync -avz --delete $CONFDIR/ ns2.example.com:/etc/gdnsd/

赋予权限:

chmod +x sync.sh

之后就可以直接执行脚本,不需要每次输入代码

./sync.sh

更新 GeoIP 数据库的脚本 geoip.sh:

URL=http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
FILENAME=GeoLiteCity.dat.gz
DIR=/etc/gdnsd/geoip
cd $DIR; rm -f $FILENAME; wget $URL; gzip -df $FILENAME

修改域名 DNS 服务器:

在注册商处把 example.com 和 example.org 的 DNS 服务器设置为 ns1.example.com 和 ns2.example.com 并耐心等待生效。

测试生效:

一般耐心等待一段时间(取决于您的旧 DNS 服务器 TTL 失效时间)后,自建的 gdnsd 已经生效,建议找一台国内的机器和国外的 Linux 机器来分别测试。

首先安装必要的 DNS 工具。

Debian / Ubuntu 下

apt-get install dnsutils

CentOS 下

yum install bind-utils

然后我们使用 dig 命令来检测:

首先检测 NS 记录是否生效

root@debian ~ # dig NS example.com +short
ns1.example.com.
ns2.example.com.

检测 A 记录或 AAAA 记录是否生效

国内对应解析到 192.0.2.4 和 2001:DB8::4

root@china ~ # dig A example.com +short @223.5.5.5
192.0.2.4
root@china ~ # dig AAAA example.com +short @223.5.5.5
2001:DB8::4

国外对应解析到 192.0.2.5 和 2001:DB8::5

root@australia ~ # dig A example.com +short @8.8.8.8
192.0.2.5
root@australia ~ # dig AAAA example.com +short @8.8.8.8
2001:DB8::5

更多节点检测的话可以去 ping.chinaz.com 或 just-ping.com 查看全国以及全世界各地的解析情况。