MENU

使用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
996.icu 996.icu