BIND9 自建 DNS 权威与递归实战:views 分视图、RPZ 恶意域名拦截与查询日志排错全流程

为什么自建站的解析不该全押在第三方

很多站长从建站第一天起就把域名解析交给了域名注册商或者公共 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 加一个从服务器做冗余,就已经比绝大多数第三方免费解析更稳、更干净了。

Last modification:October 13th, 2026 at 09:23 pm

Leave a Comment