前言

AdGuardHome 一款由 Golang 编写的 DNS 服务器,利用 AdGuardHome 可以方便的控制自己的 DNS 解析结果

在AdGuardHome官方教程中提供了适用于 Linux 和 Mac 的快捷安装命令

curl -sSL https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh

当然 AdGuardHome 根据 GPL-3.0 完整开源于 Github 你也可以拉取源码,进行编译安装

下面以 Linux 为例

在运行官方安装命令后会创建 /opt/AdGuardHome 文件夹,有关的配置文件及其他规则文件等都会存放在这里

/opt/AdGuardHome
├── AdGuardHome
├── AdGuardHome.sig
├── AdGuardHome.yaml
├── CHANGELOG.md
├── data
├── LICENSE.txt
└── README.md

其中 AdGuardHome.yaml 会在首次登陆 IP:3000 完成初始化配置后自动创建

配置前

首先需要明确的是,为什么需要建立自己的 DNS 服务器?

  1. 当前 DNS 客户端(PC、手机等终端等)使用运营商或公共 DNS 无法获取正确的解析结果
  2. 由于某种原因需要对特点域名的解析结果进行控制
  3. 在局域网内使用内网解析或是 Fake-IP 等特殊需求

在不限于以上情况的需求下,我们往往会需要在局域网或是公网上搭建私人的 DNS 服务器

而如果没有特殊的需求其实可以使用运营商或是公共 DNS 就获得达到较佳的访问体验,具体可以参考 sukka 关于如何选择适合公共 DNS 的这篇文章,在不了解客户端所在网络和相关公共 DNS 的情况下盲目的配置 AdGuardHome 并使用可能会适得其反

值的一提的是,使用 clash 的情况下 DNS 的解析正确与否不会显著影响访问体验,因此不需要强求解析结果均为正确。

配置

本次配置默认 AdGuardHome 为本次私人 DNS 服务器的上游,即直接对接运营商 DNS 或公共 DNS. (所以可以对接到其他 DNS 服务端)


点击界面中的 设置-DNS 设置 选项并在 上游 DNS 服务器 中填入

https://1.0.0.1/dns-query
https://8.8.4.4/dns-query
119.29.29.29
223.5.5.5

值的注意的是,在中国大陆不少公共 DoH DoT 的访问可能是不通畅的。 如果能保证 1.0.0.1 及 8.8.4.4 的通讯顺畅,可勾选第三个选项,达到类似 smartdns 的效果 当然,以上填写的实例也仅仅是仅供参考,如何找到适用于当前客户端的公共 DNS 本事就是一门学问,包括但不限于连接稳定性、解析的速度、解析结果的准确性、解析结果的时效性等问题


点击界面中的 过滤器-DNS 封锁清单 选项,利用该功能可以达到拦截 SDK,轻度去广告等功能 这里提几个

  1. AdGuardHome 自带列表中的 anti-AD,有很大的命中概率 https://raw.githubusercontent.com/privacy-protection-tools/anti-AD/master/anti-ad-easylist.txt
  2. 知乎的广告拦截 https://raw.githubusercontent.com/zsakvo/AdGuard-Custom-Rule/master/rule/zhihu.txt
  3. 知名的乘风广告过滤规则 https://raw.githubusercontent.com/xinggsf/Adblock-Plus-Rule/master/ABP-FX.txt

完成以上两步应该能满足大多数人的需求,修改客户端的 DNS 请求地址为 AdGuardHome 所监听的 IP,就可以试用咯

配置后

理想状况下在进行如上的配置后,应该需要能流畅的访问本地的应用服务,且能准确的返回所有的域名解析结果 但是事实往往是残酷的 在使用了 AdGuardHome 后,可能会出现以下情况:

  1. 国内应用如微信、微博、知乎等社交平台加载缓慢甚至失败的糟糕体验
  2. DNS 解析结果依旧返回有误的尴尬现象

没错,如果按照上面的配置使用 AdGuardHome 大概率会出现 “ 还不如不用的 ” 的尴尬局面 所以必须进行调优

调优

原因就在于使用的公共 DNS 无法返回最适合客户端的解析结果,以及 AdGuardHome 上游 DNS 调用算法会使得上游长期使用国内公共 DNS 或国外公共 DNS,造成水土不服的问题 因此,我们需要手动区分国内域名和国外域名的上游公共 DNS

在此之前或许需要了解 AdGuardHome 的配置文件 /opt/AdGuardHome/AdGuardHome.yaml

bind_host: 0.0.0.0                  # 绑定的网卡,此时表示绑定全部网卡
bind_port: 3000                     # HTTP 监听的端口
beta_bind_port: 0
users:                              # 登陆账号及非明文密码
···
auth_attempts: 5
block_auth_min: 15
http_proxy: ""
language: ""
rlimit_nofile: 0
debug_pprof: false
web_session_ttl: 720
dns:                                # 上游 DNS 设置
···
tls:                                # 加密设置,包括控制界面访问及设置 DoH DoT
···
filters:                            # DNS 封锁清单
···
whitelist_filters: []               # DNS 允许清单
user_rules: []                      # 自定义过滤规则
dhcp:                               # DHCP 服务设置
···
clients: []                         # 客户端控制
log_compress: false
log_localtime: false
log_max_backups: 0
log_max_size: 100
log_max_age: 3
log_file: ""
verbose: false
schema_version: 10

显而易见的,需要进行进一步设置的是 上游 DNS 设置

dns:
  bind_hosts:
  - 0.0.0.0
  port: 53
  statistics_interval: 1            # 统计数据的时间间隔(天)
  querylog_enabled: true
  querylog_file_enabled: true
  querylog_interval: 90
  querylog_size_memory: 1000
  anonymize_client_ip: false
  protection_enabled: true
  blocking_mode: default
  blocking_ipv4: ""
  blocking_ipv6: ""
  blocked_response_ttl: 10
  parental_block_host: family-block.dns.adguard.com
  safebrowsing_block_host: standard-block.dns.adguard.com
  ratelimit: 20                     # 同个客户端每秒可解析的数量,局域网内可设置为 0
  ratelimit_whitelist: []           # 填入 IP 排除上述的 ratelimit
  refuse_any: true                  # 禁用 ANY 类型请求,局域网内可设置为 false
  upstream_dns:                     # 设置的上游 DNS 
  - https://dns10.quad9.net/dns-query
  upstream_dns_file: ""             
  bootstrap_dns:                    # 用于解析上游 DNS 中 DoH/DoT 等使用域名的 IP 
  - 9.9.9.10
  - 149.112.112.10
  - 2620:fe::10
  - 2620:fe::fe:10
  all_servers: false                # 更改为 true 表示选用网页端中的并行请求
  fastest_addr: false               # 更改为 true 表示选用网页端中的最快 IP 地址
  allowed_clients: []               # 允许调用的客户端 IP,一但填写表示使用白名单模式
  disallowed_clients: []            # 不允许调用的客户端 IP,用于封锁陌生的客户端请求
  blocked_hosts:                    # 禁止解析的域名,填入的域名不会返回任何解析结果
  - version.bind
  - id.server
  - hostname.bind
  cache_size: 4194304               # DNS 缓存大小
  cache_ttl_min: 0                  # DNS TTL 最小值,限制由上游 DNS 获取的 TTL,不宜过小
  cache_ttl_max: 0                  # DNS TTL 最大值,限制由上游 DNS 获取的 TTL,不宜过大
  bogus_nxdomain: []
  aaaa_disabled: false
  enable_dnssec: false
  edns_client_subnet: false
  max_goroutines: 300
  ipset:                            # 允许写入 ipset 类似于 dnsmasq,这里提供一个实例
  - google.com/google
  filtering_enabled: true           # 是否启用过滤
  filters_update_interval: 24       
  parental_enabled: false           # 家长控制
  safesearch_enabled: false         # 安全搜索
  safebrowsing_enabled: false
  safebrowsing_cache_size: 1048576
  safesearch_cache_size: 1048576
  parental_cache_size: 1048576
  cache_time: 30
  rewrites: []                      # 过滤器下的 DNS 重写,有一些情况需要在配置文件手动填写,无法在网页写入
  blocked_services: []
  local_domain_name: lan
  resolve_clients: true             # 通过 PTR 请求,启用客户端主机名解析
  local_ptr_upstreams: []

在其中的 upstream_dns 子项中,可以填入类似如下的条目,为特定的域名指定上游 DNS

upstream_dns:
  - https://1.0.0.1/dns-query
  - https://8.8.4.4/dns-query
  - [/baidu.com/]119.29.29.29
  - [/zhihu.com/]119.29.29.29

所以可以找一个 cnsitelist 写入其中,达到分流的效果 这里提供一个由 v2fly domain-list-community 项目中的 geosote:cn 转换而来的 cnlist 直接复制到配置文件中对应位置即可

当然,这也只是其中的一个方法,这里有一个弊端在于特定域定的上游 DNS 无法指定多个进行互补 所以这里也提供其他的思路:

  1. 不同的特点需求域名启动一个 AdGuardHome,最后汇总于一个直接面向客户端的 AdGuardHome
  2. 使用 clash 等具备国内外分流的 DNS 服务器用于 AdGuardHome 的上游(如果使用 clash TUN 模式等需通过 DNS 获取域名 IP 映射的软件在使用 AdGuardHome 时可将 clash 作为唯一上游服务器,并适当调整 AdGuardHome 的 DNS TTL)

写在最后

以上内容始终以部署在局域网内为前提,AdGuardHome 提供的 DoH DoT DoQ 等加密查询方式无疑让它同样适用于搭建在公网,这里也说一句不要走寻常路… DNS 查询对于绝大多数的客户端互联网访问行为都是至关重要的,如果出现互联网访问受阻首先就应该考虑为 DNS 出现故障 因此才有这篇文章的抛砖引玉,希望能对看到这篇文章的你产生帮助