为什么自建站的解析不该全押在第三方
很多站长从建站第一天起就把域名解析交给了域名注册商或者公共 DNS,面板上点几下 A 记录就完事。这在单机、单站、没有内网需求的阶段确实够用,但只要站点稍微长大一点,问题就会集中爆发:内网服务器要解析到私有 IP、家里和机房要看到不同的结果、运维要拦截挖矿和勒索软件的回连域名、解析日志要能自己留存排查——这些诉求第三方解析面板基本给不了,或者要收一笔不便宜的费用。
BIND9 是 DNS 世界里最老的实现之一,也是最经得起折腾的实现。它同时能干权威解析和递归解析,能用 views 做分视图响应,能用 RPZ 做恶意域名拦截,还能把查询日志完整落盘。这套组合对个人站长来说足够用,而且完全免费。本文从零到可用,把安装、权威区、递归、分视图、RPZ 和排错一次性讲透。
一、安装与目录规划
Debian/Ubuntu 系直接装包即可,CentOS 系把包名换成 bind、bind-utils。先规划目录,别把配置全堆在默认路径里。
apt update
apt install -y bind9 bind9utils bind9-dnsutils
# 目录规划
# /etc/bind/named.conf.local 本地自定义配置(区声明、view)
# /etc/bind/named.conf.options 全局选项(递归、转发、ACL)
# /etc/bind/zones/ 自建区的 zone 文件
# /var/cache/bind/ 动态区、缓存落盘
确认服务状态和监听端口。默认 BIND9 只监听 127.0.0.1,这是安全默认值,后面我们会显式打开对外 IP。
systemctl enable --now bind9
ss -lunp | grep :53
dig @127.0.0.1 version.bind chaos txt +short
二、权威解析:托管自己的域名
假设你自建权威 DNS 并给权威服务器分配了 ns1.zz1984.com 的 IP。先在 /etc/bind/named.conf.local 里声明区:
// 正向区
zone "zz1984.com" {
type master;
file "/etc/bind/zones/db.zz1984.com";
allow-transfer { 203.0.113.10; }; // 只允许从服务器做 AXFR
also-notify { 203.0.113.10; };
};
// 反向区(可选,但强烈建议配)
zone "113.0.203.in-addr.arpa" {
type master;
file "/etc/bind/zones/db.203.0.113";
};
正向 zone 文件几个必须写对的地方:SOA 的序列号递增规则、NS 记录、A/AAAA、MX 和 CAA。序列号建议直接用 YYYYMMDDnn 格式,运维时肉眼可读。
$TTL 3600
@ IN SOA ns1.zz1984.com. admin.zz1984.com. (
2026101301 ; serial 必须每次改完递增
7200 ; refresh
3600 ; retry
1209600 ; expire
300 ) ; minimum
@ IN NS ns1.zz1984.com.
@ IN NS ns2.zz1984.com.
@ IN A 203.0.113.20
www IN A 203.0.113.20
@ IN MX 10 mail.zz1984.com.
@ IN CAA 0 issue "letsencrypt.org"
mail IN A 203.0.113.21
ns1 IN A 203.0.113.20
ns2 IN A 203.0.113.10
写完之后必须先做语法检查再 reload,这是权威 DNS 的铁律,检查失败就回滚:
named-checkconf -z /etc/bind/named.conf
named-checkzone zz1984.com /etc/bind/zones/db.zz1984.com
rndc reload
dig @127.0.0.1 www.zz1984.com +short
注意 zone 文件里每行结尾如果漏了点号,BIND9 会自动把相对名补成 @ 下的子域,比如 www 写成 www 是 www.zz1984.com,但如果你想让 ns1 指到别的域就得写全 ns1.example.net.。这个点号是新手最容易踩的坑。
三、递归解析:给自己的服务器用
权威和递归不要混在同一个对外实例上,但给自己内网当递归解析器是很常见的用法。全局选项里打开递归并限制来源:
acl "trusted" {
127.0.0.1;
10.0.0.0/8;
192.168.0.0/16;
};
options {
directory "/var/cache/bind";
recursion yes;
allow-recursion { trusted; };
allow-query { trusted; };
allow-query-cache { trusted; };
// 关闭对外版本探测
version "not disclosed";
// 开启 DNSSEC 验证
dnssec-validation auto;
// 防放大攻击:只监听内网网卡
listen-on { 127.0.0.1; 10.0.0.5; };
listen-on-v6 { none; };
};
如果你想用上游公共 DNS 做转发而不是自己从根开始递归,用 forwarders,但要理解代价:转发的响应质量取决于上游,而且更容易被上游投毒。自建递归的干净程度更高,代价是要维护根提示文件且缓存预热慢。个人站普遍建议直接自递归加开启 DNSSEC 验证。
四、views 分视图:一份域名对内对外两种答案
分视图是 BIND9 最有价值的功能之一。典型场景:外网访问 www 走公网 CDN,内网访问同一域名走内网源站,避免内网流量绕出去再绕回来。做法是把 zone 声明搬进不同的 view 里:
view "internal" {
match-clients { trusted; };
recursion yes;
zone "zz1984.com" {
type master;
file "/etc/bind/zones/db.zz1984.com.internal";
};
};
view "external" {
match-clients { any; };
recursion no;
zone "zz1984.com" {
type master;
file "/etc/bind/zones/db.zz1984.com.external";
};
};
要点:一旦用了 view,所有 zone 声明都必须放进某个 view,连根提示 zone "." 也要,否则 named-checkconf 直接报错。match-clients 的匹配顺序就是 view 的书写顺序,第一个匹配上的生效,所以 internal 要写在 external 前面。内网 zone 文件里 www 指 10.0.0.5,外网 zone 文件里指 CDN CNAME,两边序列号独立维护。
五、RPZ 拦截:把恶意域名挡在解析层
RPZ(Response Policy Zone)允许你用一个普通 zone 文件表达拦截策略,命中后返回 NXDOMAIN 或自建的墙页 IP。对个人站来说,最常见的用途是拦截挖矿、钓鱼、广告和 C2 回连域名。配置方式:
options {
// ... 其他选项
response-policy {
zone "rpz.local" policy given;
zone "rpz.feed" policy nxdomain;
} qname-wait-recurse no;
};
zone "rpz.local" {
type master;
file "/etc/bind/zones/db.rpz.local";
};
RPZ zone 文件的写法很直观,用 CNAME . 表示拦截:
$TTL 300
@ IN SOA localhost. admin.localhost. ( 1 3600 600 86400 300 )
IN NS localhost.
; NXDOMAIN 拦截
miner.evil.example IN CNAME .
coin-hive.example IN CNAME .
; 墙页重定向到自建提示页
ads.tracker.example IN CNAME wall.zz1984.com.
社区维护的 RPZ feed(如各类恶意域名聚合项目)可以直接下载后 include 进 zone 文件,每天 cron 更新一次再 rndc reload 即可。注意 RPZ 会显著增加内存占用和查询延迟,feed 越大越明显,个人站建议只订阅一到两个精选源,别什么都往里塞。
六、查询日志与排错
线上 DNS 出问题时,最怕的是"没有日志可看"。打开查询日志(注意这个日志量很大,务必配 logrotate):
logging {
channel queries {
file "/var/log/named/queries.log" versions 5 size 50m;
severity info;
print-time yes;
print-category yes;
};
category queries { queries; };
category dnssec { queries; };
};
常用排查命令:dig +trace www.zz1984.com 看完整递归链路;delv @127.0.0.1 www.zz1984.com 专门做 DNSSEC 验证并告诉你断在哪一级;rndc status 看运行状态和内存占用;named-checkconf -z 一次性验证所有区加载是否成功。
几个高频故障对照:解析改了不生效,九成是序列号没递增或者从服务器没收到 notify;部分客户端拿到旧 IP,先怀疑缓存 TTL 而不是服务端;RPZ 拦截后客户端的报错五花八门,注意 policy given 返回的是 NODATA 不是 NXDOMAIN,某些应用会因为 NODATA 反复重试而变慢,这时换成 policy nxdomain 更利落。
结语
把 DNS 握在自己手里,最直接的收益是可控:控制权和日志都在自己这边;其次是省钱,公共解析的付费版溢价不低。代价是需要理解 view、RPZ、序列号和 DNSSEC 这些概念,并且养成"改完先 named-checkconf 再 reload"的习惯。对个人站长来说,一台最小配置的 VPS 跑 BIND9 加一个从服务器做冗余,就已经比绝大多数第三方免费解析更稳、更干净了。