我将为你提供一个从基础到进阶的完整指南,涵盖最常用的 DNS 服务器软件 BIND (Berkeley Internet Name Domain)。

第一部分:基础 DNS 服务器搭建 (仅提供内网域名解析)
假设我们的目标是:
- 内网网段:
168.1.0/24 - DNS 服务器 IP:
168.1.10 - 内网域名:
local.lan - 需要解析的主机:
server.local.lan->168.1.10nas.local.lan->168.1.20pc1.local.lan->168.1.30
步骤 1: 安装 BIND
BIND 是最主流、功能最强大的 DNS 服务器软件。
在基于 Debian/Ubuntu 的系统上:
sudo apt update sudo apt install bind9 bind9utils
在基于 RHEL/CentOS/Fedora 的系统上:

sudo yum install bind bind-utils # 或者对于 dnf sudo dnf install bind bind-utils
步骤 2: 配置 BIND
BIND 的主要配置文件是 /etc/bind/named.conf 或 /etc/named.conf,我们主要编辑它的两个部分:options 和 zone。
-
编辑主配置文件
打开主配置文件:
sudo nano /etc/bind/named.conf
确保文件内容大致如下,特别是
listen-on和allow-query部分,我们只监听内网 IP,并只响应内网查询。
(图片来源网络,侵删)// // Please read /usr/share/doc/bind9/README.Debian.gz for information on // the up-to-date versions of the configuration files and zones. // // Do any local changes in /etc/bind/named.conf.local, instead of here. // include "/etc/bind/named.conf.options"; include "/etc/bind/named.conf.local"; include "/etc/bind/named.conf.default-zones"; // --- 以下是关键的修改部分 --- // 只监听内网接口 192.168.1.10 // 将 127.0.0.1::1 替换为你的内网IP listen-on port 53 { 127.0.0.1; 192.168.1.10; }; // 如果允许IPv6,可以取消下面这行的注释并填入内网IPv6地址 // listen-on port 53 { 127.0.0.1; ::1; 192.168.1.10; }; // 只允许内网网段 192.168.1.0/24 进行DNS查询 allow-query { localhost; 192.168.1.0/24; }; // 允许从本机进行递归查询(非常重要,否则无法解析外网域名) recursion yes; // 限制递归查询的来源,防止滥用 allow-recursion { localhost; 192.168.1.0/24; }; // 其他优化选项 dnssec-validation auto; auth-nxdomain no; # conform to RFC1035注意:
listen-on指定了服务器在哪个 IP 地址上监听 DNS 请求。allow-query指定了哪些 IP 地址可以向这个服务器发起查询请求。 -
定义区域文件
区域文件定义了哪个 DNS 后缀(如
local.lan)由这个服务器负责解析。继续编辑
/etc/bind/named.conf.local文件:sudo nano /etc/bind/named.conf.local
在文件末尾添加以下内容,定义一个“正向区域”和一个“反向区域”。
// // Do any local configuration here // // Consider adding the 1918 zones here, if they are not used in your // organization // include "/etc/bind/zones.rfc1918"; // --- 添加我们自己的区域定义 --- // 正向区域:将 local.lan 域名解析为 IP 地址 zone "local.lan" { type master; file "/etc/bind/db.local.lan"; }; // 反向区域:将 192.168.1.0/24 网段内的 IP 解析为 local.lan 域名 // 注意这里的网络地址是 1.168.192.in-addr.arpa 的格式 zone "1.168.192.in-addr.arpa" { type master; file "/etc/bind/db.192.168.1"; }; -
创建区域数据文件
我们需要创建上面定义的两个区域数据文件。
-
创建正向区域文件
# 复制一个模板文件 sudo cp /etc/bind/db.local /etc/bind/db.local.lan # 编辑新文件 sudo nano /etc/bind/db.local.lan
修改为:
; ; BIND data file for local.lan ; $TTL 604800 @ IN SOA ns1.local.lan. admin.local.lan. ( 2 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 604800 ) ; Negative Cache TTL ; @ IN NS ns1.local.lan. @ IN A 192.168.1.10 @ IN AAAA ::1 ; --- 添加我们的内网主机记录 --- ns1 IN A 192.168.1.10 server IN A 192.168.1.10 nas IN A 192.168.1.20 pc1 IN A 192.168.1.30 -
创建反向区域文件
# 复制一个模板文件 sudo cp /etc/bind/db.127 /etc/bind/db.192.168.1 # 编辑新文件 sudo nano /etc/bind/db.192.168.1
修改为:
; ; BIND reverse data file for 192.168.1.0/24 ; $TTL 604800 @ IN SOA ns1.local.lan. admin.local.lan. ( 1 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 604800 ) ; Negative Cache TTL ; @ IN NS ns1.local.lan. ; --- 添加我们的反向解析记录 --- 10 IN PTR server.local.lan. 20 IN PTR nas.local.lan. 30 IN PTR pc1.local.lan.注意: PTR 记录的 IP 地址部分是反写的,并且没有
.0(网络位)。
-
步骤 3: 启动并测试服务
-
检查配置文件语法 在重启服务前,务必检查配置是否正确。
# 对于 Debian/Ubuntu sudo named-checkconf # 对于 RHEL/CentOS sudo named-checkconf -c /etc/named.conf # 检查区域文件语法 sudo named-checkzone local.lan /etc/bind/db.local.lan sudo named-checkzone 1.168.192.in-addr.arpa /etc/bind/db.192.168.1
如果没有输出,说明语法正确。
-
启动并启用 BIND 服务
# 对于 Debian/Ubuntu (使用 systemd) sudo systemctl start bind9 sudo systemctl enable bind9 # 对于 RHEL/CentOS (使用 systemd) sudo systemctl start named sudo systemctl enable named
-
在客户端测试
将你电脑的 DNS 服务器地址临时修改为
168.1.10。-
测试正向解析
nslookup server.local.lan # 应该返回: 192.168.1.10 nslookup nas.local.lan # 应该返回: 192.168.1.20
-
测试反向解析
nslookup 192.168.1.20 # 应该返回: nas.local.lan
-
测试外网解析
nslookup www.baidu.com # 应该返回百度的公网IP地址,证明递归查询正常工作
-
如果所有测试都通过,恭喜你,你的基础内网 DNS 服务器已经搭建成功了!
第二部分:进阶功能 (广告过滤)
要实现广告过滤,我们需要一个包含大量广告域名黑名单的 zone 文件。Pi-hole 项目提供了现成的黑名单,我们可以利用它。
-
下载广告域名列表 你可以从
https://firebog.net/网站找到很多优秀的广告列表,这里我们使用一个组合列表。# 创建一个目录存放广告列表 sudo mkdir -p /etc/bind/adlists # 下载几个主要的列表 (使用 curl 或 wget) curl -o /etc/bind/adlists/adlist.txt https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts curl -o /etc/bind/adlists/list1.txt https://hosts-file.net/ad_servers.txt # ... 可以继续添加更多列表
-
合并并处理列表 我们需要将这些列表转换成 BIND 的 zone 文件格式,这个过程有点繁琐,通常需要编写一个脚本来完成:
- 读取所有列表文件。
- 提取出域名部分(去掉 IP 地址)。
- 去重。
- 为每个域名生成
CNAME记录,指向一个不存在的地址,如blackhole.local.lan。
一个简化的合并脚本示例 (
/usr/local/bin/create_ad_block_zone.sh):#!/bin/bash ADLIST_DIR="/etc/bind/adlists" ZONE_FILE="/etc/bind/db.adblock" BLACKHOLE_DOMAIN="blackhole.local.lan." # 清空或创建区域文件 echo "; Ad Block Zone File - Generated on $(date)" > $ZONE_FILE echo "\$TTL 604800" >> $ZONE_FILE echo "@ IN SOA ns1.local.lan. admin.local.lan. ( $(date +%s) 604800 86400 2419200 604800 )" >> $ZONE_FILE echo "@ IN NS ns1.local.lan." >> $ZONE_FILE echo "" >> $ZONE_FILE # 遍历所有列表文件,提取域名并生成 CNAME 记录 for file in $ADLIST_DIR/*.txt; do # 使用 sed 提取域名,跳过注释和空行 sed -e 's/#.*$//' -e '/^[[:space:]]*$/d' "$file" | awk '{print $2}' | \ grep -v '^localhost$' | grep -v '^localdomain$' | \ while read -r domain; do # 检查域名是否已存在 if ! grep -qF " ${domain} IN CNAME" $ZONE_FILE; then echo "*.${domain}. IN CNAME ${BLACKHOLE_DOMAIN}." >> $ZONE_FILE fi done done echo "Ad block zone file generated: $ZONE_FILE"给脚本执行权限并运行:
sudo chmod +x /usr/local/bin/create_ad_block_zone.sh sudo /usr/local/bin/create_ad_block_zone.sh
-
在 named.conf 中加载广告过滤区域 编辑
/etc/bind/named.conf.local,在文件末尾添加:// 广告过滤区域 zone "adblock" { type master; file "/etc/bind/db.adblock"; // 这个区域只允许查询,不允许动态更新 allow-query { any; }; allow-transfer { none; }; };注意,这里我们使用了 通配符,这意味着所有在
db.adblock文件中定义的域名(及其所有子域名)都会被解析到blackhole.local.lan。 -
重新加载 BIND 配置
sudo rndc reload # 或者重启服务 sudo systemctl restart bind9
-
测试广告过滤 将你的 DNS 服务器指向
168.1.10,然后尝试访问一个已知的广告网站,或者使用dig/nslookup查询一个广告域名。# 假设 doubleclick.net 是一个广告域名 nslookup doubleclick.net # 应该返回 blackhole.local.lan 的地址(如果它也在你的列表里)
第三部分:常用管理命令
- 检查配置:
sudo named-checkconf - 检查区域:
sudo named-checkzone <zone_name> <zone_file> - 重新加载配置 (不中断服务):
sudo rndc reload - 查看日志:
sudo tail -f /var/log/syslog(Debian/Ubuntu) 或sudo journalctl -u named -f(RHEL/CentOS) - 测试查询:
dig @192.168.1.10 nas.local.lan(指定 DNS 服务器进行查询)host nas.local.lan 192.168.1.10(使用 host 命令)
总结与最佳实践
- 静态 IP: 确保 DNS 服务器使用一个固定的内网 IP 地址。
- 安全: 不要将
allow-query设置为any,除非你有特殊需求,限制在你的内网网段。 - 日志: 定期查看日志,可以帮助你排查问题或发现异常的查询行为。
- 高可用: 对于生产环境,可以考虑配置两台 DNS 服务器,并使用
nsupdate或其他工具实现动态更新和故障转移。 - 替代方案: 如果你觉得 BIND 配置复杂,可以考虑使用更简单的工具,如
dnsmasq,它非常轻量,集成了 DHCP 和 DNS 功能,特别适合小型家庭或办公室网络。
希望这份详细的指南能帮助你成功搭建自己的内网 DNS 服务器!
