使用Knot DNS自建dns服务器
最早在2017年前后就尝试使用powerdns来代替域名注册商的dns,但由于配置繁杂后来放弃了这个想法,随后一直使用conoha的dns服务并且通过api编写了一个面板方便管理域名,在去年稍早的时候得知conoha即将以没有"有效服务"为理由关闭我的账户,然而当我开始尝试cloudns/ns1/he/cloudcone的dns服务时,他们都有一些限制,于是自建dns又提上日程,最后决定使用knot dns来进行自建.
为什么选择Knot Dns
其实一开始选择的是安装HestiaCP然后通过其API进行管理,先不说这个面板基本没有API,使用一段时间后发现会丢解析数据,并且在官方论坛中有不少人遇到这个问题,没有得到解决,于是便重新开始寻找其他的解决方案.
Knot DNS是由捷克的CZNIC开发的,而bgp玩家使用的bird也是由CZNIC赞助的,看了Knot DNS的文档后发现其支持geo解析以及配置简单且轻量化和对cpu/内存的低占用.
除了将DNS配置放在配置文件,knot还可以将配置放在sqlite数据库中,此外还提供cli命令对dns进行管理.
官方有正在开发的rest api项目(虽然该项目目前功能不完整,无法直接使用)可以给web面板开发带来不少的便利性.
主从服务器设置非常简单,只需在配置文件修改几行配置即可,并且zone数据自动同步.
自建dns成本
自建dns从来都不是一个简单的事情,并且总是面临一些风险,比如当dns服务器出现故障时,域名所有的解析失效,无法访问域名邮箱,接收邮件,无法登陆一些使用域名邮箱验证的账户,如果dns服务器出现安全漏洞甚至可能丢失对自己域名的控制权,为了应对这些问题,需要付出很多时间成本来维护dns服务器.
除了上述风险,还有dns服务器的费用成本,当前采用的是1主2从架构,在欧美亚各有一个dns服务器,受益于Knot DNS所占用的资源不高,在美国的dns服务器成本约为12USD/年,而欧洲刻意选择了一个乌克兰商家的基辅vps,其价格大概为540UAH/年,亚洲的成本是最贵的,价格是5388JPY/年
除了服务器费用,还需要一个域名专门用作DNS服务器,目前所使用的域名大概为20USD/年
此外,还需要一个vps放置管理面板,以及另外一个域名作为管理面板的域名和一个第三方的dns服务器托管这个域名(本篇文章不会介绍web管理面板相关的内容,所以这些费用不包含在此
安装
可以在knot官网找到安装文档,地址是https://www.knot-dns.cz/download/
官网提供了debian/ubuntu/rhel系列的安装包和docker映像和源码
一如既往,仍然使用ubuntu作为vps的系统
apt-get update
apt-get -y install apt-transport-https ca-certificates wget -y
wget -O /usr/share/keyrings/cznic-labs-pkg.gpg https://pkg.labs.nic.cz/gpg
echo "deb [signed-by=/usr/share/keyrings/cznic-labs-pkg.gpg] https://pkg.labs.nic.cz/knot-dns jammy main" > /etc/apt/sources.list.d/cznic-labs-knot-dns.list
apt-get update
apt-get install knot -y
需要在所有的机器上使用这段命令安装knot,确保knot的主版本号(及开头2位)是相同的.
主服务器配置
打开/etc/knot/knot.conf
对其进行修改,大致配置如下
server:
rundir: "/run/knot"
user: knot:knot #启动knot的账户,这里需要注意一下权限问题
automatic-acl: on #自动acl
listen: 0.0.0.0@53 #监听端口
listen: ::@53 #监听端口
log:
- target: syslog
any: info
database: #sqlite数据库
storage: "/var/lib/knot" #sqlite数据库所在位置
remote: #节点列表(从机列表)
- id: us #节点名称
address: 192.168.0.3@53 #节点ip
- id: eu
address: 192.168.0.2@53
template: #模板
- id: default #默认模板(所有zone都会继承这个配置)
storage: "/var/lib/knot" #zone储存目录
file: "%s.zone" #zone储存名称
notify: [us, eu] #zone同步到的从机
zone:
保存后执行knotc conf-import /etc/knot/knot.conf
将其导入数据库然后执行systemctl start knot
运行dns服务器
从机
打开/etc/knot/knot.conf
对其进行修改,大致配置如下
server:
rundir: "/run/knot"
user: knot:knot
automatic-acl: on
listen: 0.0.0.0@53
listen: ::@53
log:
- target: syslog
any: info
database:
storage: "/var/lib/knot"
remote:#节点列表(主机和除自己之外的其他从机列表)
- id: asia
address: 192.168.0.1@53
- id: us
address: 192.168.0.3@53
template: #模板
- id: default #默认模板
storage: "/var/lib/knot"
file: "%s.zone"
master: [asia] #指定主机
zone:
保存后执行knotc conf-import /etc/knot/knot.conf
将其导入数据库然后执行systemctl start knot
运行dns服务器
其余的从机设置方式相同
添加dns用域名
这里假设域名demo.lan
是dns服务器专用域名,在所有机器上执行如下命令添加zone
knotc conf-begin
knotc conf-set 'zone.domain' 'demo.lan'
knotc conf-commit
后续添加域名时也需要在所有机器上执行这段命令添加zone,只有解析内容是只在主机上添加的
然后这里假设给所有主机分配的ns前缀分别是ns1/ns2/ns3
,在主机执行如下命令添加A记录,如果dns服务器支持ipv6同时也要设置AAAA记录
knotc zone-begin demo.lan
knotc zone-set demo.lan ns1 3600 A 192.168.0.1
knotc zone-set demo.lan ns2 3600 A 192.168.0.2
knotc zone-set demo.lan ns3 3600 A 192.168.0.3
knotc zone-set demo.lan ns1 3600 AAAA fe80:8888:8888:8888::1
knotc zone-set demo.lan ns2 3600 AAAA fe80:8888:8888:8888::2
knotc zone-set demo.lan ns3 3600 AAAA fe80:8888:8888:8888::3
knotc zone-commit demo.lan
设置后即可通过nslookup ns1.demo.lan 192.168.0.1
验证解析了
然后在域名注册商那里设置胶水记录(Glue Record)
对域名的增删改查
这里以域名local.lan为例
#添加域名
knotc conf-begin
knotc conf-set 'zone.domain' 'local.lan'
knotc conf-commit
#设置基础解析,这一步是必须的
knotc zone-begin local.lan
knotc zone-set local.lan @ 3600 SOA ns admin 1 86400 900 691200 3600
knotc zone-set local.lan @ 3600 NS ns1.demo.lan.
knotc zone-set local.lan @ 3600 NS ns2.demo.lan.
knotc zone-set local.lan @ 3600 NS ns3.demo.lan.
knotc zone-commit local.lan
#设置A/AAAA/CNAME/TXT记录
knotc zone-begin local.lan
knotc zone-set local.lan a-test 3600 A 192.168.0.1
knotc zone-set local.lan aaaa-test 3600 AAAA 2001:DB8::1
knotc zone-set local.lan cname-test 3600 CNAME cname.xxx.lan.
knotc zone-set local.lan @ 3600 TXT \"v=spf1 a:mail.example.com -all\"
knotc zone-commit local.lan
需要注意的是类似MX/CNAME/NS
等使用域名作为值的记录,其值结尾需要使用符号.
,否则后面会自动拼接当前域名
对于txt内容含有双引号时需要通过转义符对其转移
解析和修改配置是需要通过begin开启事物,解析后需要通过commit提交事务,如果中途想放弃修改则使用abort停止并恢复开启事物前的操作
更多的操作可以看官方文档:https://www.knot-dns.cz/docs/3.3/html/operation.html#dynamic-configuration
区域文件的备份
备份部分可以看官方文档:https://www.knot-dns.cz/docs/3.3/html/operation.html#data-and-metadata-backup
knotc zone-backup +backupdir /tmp/_backup
此外推荐使用备份脚本备份knot的配置文件/etc/knot/knot.conf
以及zone和数据库等文件所在的/var/lib/knot
目录
这里提供一份备份脚本参考
#!/bin/bash
# WebDAV settings
webdav_url="https://backup.sh/dav/ns1/" # 指定 WebDAV 中的 ns1 路径(每台机器单独一个目录)
webdav_user="account"
webdav_password="password"
# 备份目录和文件名之类的
backup_dir="/var/lib/knot"
backup_date=$(date +%Y%m%d)
backup_file="knot_backup_$backup_date.tar.gz"
online_backup_file="knot_online_backup_$backup_date.tar.gz"
config_backup_file="knot_config_$backup_date.conf"
# 创建临时目录
temp_backup_dir="/tmp/knot_backup"
online_zone_backup_dir="$temp_backup_dir/online_backup"
mkdir -p $temp_backup_dir
mkdir -p $online_zone_backup_dir
chmod -R 0777 $temp_backup_dir
# 通过knotc导出配置
knotc conf-export > $temp_backup_dir/$config_backup_file
knotc zone-backup +backupdir $online_zone_backup_dir
# 打包/var/lib/knot目录文件和上面zone-backup的文件
tar -czvf $temp_backup_dir/$backup_file -C $backup_dir .
tar -czvf $temp_backup_dir/$online_backup_file -C $online_zone_backup_dir .
# 上传文件到webdav
curl -T $temp_backup_dir/$online_backup_file -u $webdav_user:$webdav_password $webdav_url
curl -T $temp_backup_dir/$backup_file -u $webdav_user:$webdav_password $webdav_url
curl -T $temp_backup_dir/$config_backup_file -u $webdav_user:$webdav_password $webdav_url
# 删除本地文件
rm -rf $temp_backup_dir