LOADING

利用 Mosdns (v4 or v5) 和 AdGuardHome 搭建自己的 DNS

群晖教程1年前 (2024)更新 ypng
30 0 0

原文地址:https://www.xukecheng.tech/use-mosdns-and-adguardhome-to-build-your-own-dns

前言

国内的 DNS 服务商一般有两个,网络运营商和部分商业公司。而由于种种原因,这些 DNS 都存在或多或少的问题,这里就不细说了。而部分玩家为了尽可能地规避其中的某些问题,因此必不可少地需要自建 DNS 服务。但是,需要注意得是,我们国家的互联网域名管理办法明文规定:
‼️
提供域名解析服务,应当遵守有关法律、法规、标准,具备相应的技术、服务和网络与信息安全保障能力,落实网络与信息安全保障措施,依法记录并留存域名解析日志、维护日志和变更记录,保障解析服务质量和解析系统安全。涉及经营电信业务的,应当依法取得电信业务经营许可。
因此,接下来搭建好的的 DNS 服务只能在自己的内网运行,用于学习、测试等个人用途上,不得对外提供服务。

工具选型

目前用得比较多,而且还在活跃的 DNS 工具总共有三种:
它们都是开源产品,能够做到防污染、防跟踪、防篡改、去广告、反跟踪等等功效。但是彼此之间的实现区别还是很多的,而我在仔细对比之后还是选择了后两款。至于原因这里不方便细说,比较复杂,但是如果说对于 SmartDNS 有特殊感情也可以自行搜索相关的教程。

服务搭建

首先介绍下思路,我们用 Mosdns 作为最核心的部分 → DNS 转发器,AdguardHome 作为可视化的前端和广告规则自动拦截和屏蔽工具。
当然,有人可能会问只用 AdGuardHome 就够了,为什么还要用 Mosdns?
至于为什么不单用 AdguardHome,我这里主要出于两方面的考虑:
  • 经过测试 Mosdns 的 DNS 查询转发速度相对更快,且查询条件能做到更加精细地控制,这里可以参考规则部分
  • Mosdns 的域名匹配工具可以直接利用一些常用的域名文件做到更加方便和精准地分流;Adguardhome 不是不行,但是很麻烦
这里需要你有一台测试 Linux 服务器(不用多好,能正常访问就行),接下来使用该命令一键安装 Docker。如果你不知道什么是 Docker,请自行搜索了解。

Mosdns

‼️
mosdns v5:2022年 12 月 21 日发布了 v5.0.0-rc.0,配置文件和 v4 有大量变化,需要参考 wiki 重新配置。因此我下面的内容也分为 v4 版本和 v5 版本以区分。
首先你需要准备好配置文件相关资源文件和config.yaml ,下面是相关链接可以复制或下载使用

资源文件

v4 版本:

wget https://glare.xukecheng.tech/Loyalsoldier/geoip/cn.dat -O /etc/mosdns/cn.dat && \
wget https://glare.xukecheng.tech/Loyalsoldier/v2ray-rules-dat/geosite.dat -O /etc/mosdns/geosite.dat && \
wget https://glare.xukecheng.tech/Loyalsoldier/v2ray-rules-dat/geoip.dat -O /etc/mosdns/geoip.dat && \
touch /etc/mosdns/ecs_cn_domain.txt && \
touch /etc/mosdns/ecs_tw_domain.txt

# ecs_cn_domain 是强制本地解析域名,ecs_tw_domain 是强制非本地解析域名;格式可以参考 https://github.com/pmkol/easymosdns/blob/main/ecs_tw_domain.txt

v5 版本:
wget https://raw.githubusercontent.com/xukecheng/scripts/main/mosdns_geodata_download.sh. -O mosdns_geodata_download.sh && chmod +x mosdns_geodata_download.sh && mosdns_geodata_download.sh

配置文件

路径:/etc/mosdns/config.yaml,下面列举了 v4 和 v5 版本的配置文件作为参考。
v4 版本配置文件

# 配置文件的部分内容参考了下面这个网站
# https://apad.pro/easymosdns
#
log:
file: "./mosdns.log"
level: error

data_providers:
- tag: geosite
file: ./geosite.dat
auto_reload: true
- tag: geoip
file: ./geoip.dat
auto_reload: true
- tag: cn
file: ./cn.dat
auto_reload: true
- tag: ecscn
file: ./ecs_cn_domain.txt
auto_reload: true
- tag: ecstw
file: ./ecs_tw_domain.txt
auto_reload: true
- tag: hosts
file: ./hosts.txt
auto_reload: true

plugins:
# 缓存的插件
- tag: cache
type: cache
args:
size: 10240
# 机器上部署了 redis 再开启
# redis: "redis://127.0.0.1:6379/0"
lazy_cache_ttl: 86400
cache_everything: true

# Hosts的插件
- tag: hosts
type: hosts
args:
hosts:
- "provider:hosts"

# 调整ECS的插件
# [auto|global|cn|tw]
- tag: ecs_auto
type: ecs
args:
auto: true
mask4: 24
force_overwrite: false
- tag: ecs_global
type: ecs
args:
auto: true
mask4: 22
force_overwrite: false
- tag: ecs_cn
type: ecs
args:
auto: false
ipv4: "1.2.4.0"
ipv6: "2001:dc7:1000::1"
mask4: 24
force_overwrite: true
- tag: ecs_tw
type: ecs
args:
auto: false
ipv4: "168.95.1.0"
ipv6: "2001:b000:168::1"
mask4: 22
force_overwrite: true

# 调整TTL的插件
- tag: ttl_short
type: ttl
args:
minimal_ttl: 60
maximum_ttl: 3600
- tag: ttl_long
type: ttl
args:
minimal_ttl: 300
maximum_ttl: 3600

# 屏蔽TYPE65类型请求的插件
- tag: qtype65
type: query_matcher
args:
qtype: [65]
- tag: black_hole
type: blackhole
args:
rcode: 0
ipv4: "127.0.0.1"
ipv6: "::1"

# 转发至 AliDNS 的插件
- tag: forward_ali
type: fast_forward
args:
upstream:
- addr: "https://dns.alidns.com/dns-query"
dial_addr: "223.5.5.5"
trusted: true
enable_pipeline: true
- addr: "tls://dns.alidns.com"
dial_addr: "223.5.5.5"
trusted: true
enable_pipeline: true

# 转发至 DnspodDNS 的插件
- tag: forward_dnspod
type: fast_forward
args:
upstream:
- addr: "https://1.12.12.12/dns-query"
trusted: true
- addr: "https://120.53.53.53/dns-query"
trusted: true

# 转发至本地服务器的插件
- tag: forward_local
type: sequence
args:
exec:
- parallel:
- - "forward_ali" # 执行序列 #1。
- - "forward_dnspod" # 执行序列 #2。

# 转发至 GoogleDNS 的插件
- tag: forward_google
type: fast_forward
args:
upstream:
- addr: "https://dns.google/dns-query"
dial_addr: "2001:4860:4860::8844"
trusted: true
enable_pipeline: true
enable_http3: true
- addr: "tls://dns.google"
dial_addr: "8.8.8.8"
trusted: true
enable_pipeline: true
enable_http3: true

# 转发至 CloudflareDNS 的插件
- tag: forward_cloudflare
type: fast_forward
args:
upstream:
- addr: "https://cloudflare-dns.com/dns-query"
dial_addr: "2606:4700::6810:f9f9"
trusted: true
enable_pipeline: true
enable_http3: true
- addr: "tls://1dot1dot1dot1.cloudflare-dns.com"
dial_addr: "1.1.1.1"
trusted: true
enable_pipeline: true
enable_http3: true

# 转发至远程服务器的插件
- tag: forward_remote
type: sequence
args:
exec:
- parallel: # 并行
- - "forward_google" # 执行序列 #1。
- - "forward_cloudflare" # 执行序列 #2。

# 匹配本地域名的插件
- tag: query_is_local_domain
type: query_matcher
args:
domain:
- "provider:geosite:cn"
- "provider:geosite:apple-cn"
- "provider:geosite:steam@cn"

# 匹配污染域名的插件
- tag: query_is_non_local_domain
type: query_matcher
args:
domain:
- "provider:geosite:geolocation-!cn"

- tag: response_has_local_ip
type: response_matcher
args:
ip:
# 使用默认geoip.dat文件
# - "ext:./geoip.dat:cn"
# 使用高性能cn.dat文件, 需要下载对应的文件
- "provider:cn:cn"

# - tag: query_is_ad_domain
# type: query_matcher
# args:
# domain:
# - "ext:./geosite.dat:category-ads-all"

# 匹配强制本地解析域名的插件
- tag: query_is_cn_domain
type: query_matcher
args:
domain:
- "provider:ecscn"

# 匹配强制非本地解析域名的插件
- tag: query_is_tw_domain
type: query_matcher
args:
domain:
- "provider:ecstw"

# 匹配RCODE2的插件
- tag: response_server_failed
type: response_matcher
args:
rcode: [2]

# 主要的运行逻辑插件
# sequence 插件中调用的插件 tag 必须在 sequence 前定义
# 否则 sequence 找不到对应插件
- tag: main_sequence
type: sequence
args:
exec:
# 域名映射IP
- hosts

# 缓存
- cache

# 屏蔽TYPE65类型请求
- if: qtype65
exec:
- black_hole
- _return

# 强制用本地服务器解析
- if: query_is_cn_domain
exec:
- ecs_auto
- forward_local
- _return

# 强制用非本地服务器解析
- if: query_is_tw_domain
exec:
- ecs_tw
- forward_remote
- ttl_long
- _return

# 屏蔽广告域名
# - if: query_is_ad_domain
# exec:
# - _new_nxdomain_response
# - _return

# 已知的本地域名或CDN域名用本地服务器解析
- if: query_is_local_domain
exec:
- ecs_auto
- forward_local
- _return

# 已知的污染域名用远程服务器解析
- if: query_is_non_local_domain
exec:
- _prefer_ipv4
- ecs_cn
- forward_remote
- _return

# 剩下的未知域名用IP分流,分流原理请参考fallback的工作流程
# primary 从本地服务器获取应答,丢弃非本地IP或污染IP的结果
- primary:
- ecs_auto
- forward_local
- ttl_short
- if: "(! response_has_local_ip) && [_response_valid_answer]"
exec:
- _drop_response
# secondary 从远程服务器获取应答,无法解析的域名从本地服务器获取应答
secondary:
- _prefer_ipv4
- ecs_global
- forward_remote
- ttl_long
- if: "response_server_failed"
exec:
- forward_local
- ttl_long
# 这里建议设置成 local 服务器正常延时的 2~5 倍
# 这个延时保证了 local 延时偶尔变高时,其结果不会被 remote 抢答
# 如果 local 超过这个延时还没响应,可以假设 local 出现了问题
# 这时用就采用 remote 的应答。单位: 毫秒
fast_fallback: 150

servers:
- exec: main_sequence
timeout: 5
listeners:
- protocol: udp
addr: "0.0.0.0:53"
- protocol: tcp
addr: "0.0.0.0:53"
# - protocol: http
# addr: "0.0.0.0:9443"
# url_path: "/dns-query"
# get_user_ip_from_header: "X-Forwarded-For"
# - protocol: tls
# addr: "0.0.0.0:853"
# cert: "/etc/mosdns/cert/test.crt" # TLS 所需证书文件。
# key: "/etc/mosdns/cert/test.key" # TLS 所需密钥文件。
# idle_timeout: 10 # 连接复用空连接超时时间。单位: 秒。默认: 10。

api:
http: "0.0.0.0:9080"

v5 版本配置文件:

log:
level: info

api:
http: "0.0.0.0:5534"

include: []

plugins:
- tag: geosite_cn
type: domain_set
args:
files:
- "/etc/mosdns/rules/geosite_cn.txt"

- tag: geoip_cn
type: ip_set
args:
files:
- "/etc/mosdns/rules/geoip_cn.txt"

- tag: geosite_apple
type: domain_set
args:
files:
- "/etc/mosdns/rules/geosite_apple.txt"

- tag: geosite_no_cn
type: domain_set
args:
files:
- "/etc/mosdns/rules/geosite_geolocation-!cn.txt"

- tag: force_cn
type: domain_set
args:
files:
- "/etc/mosdns/rules/force-cn.txt"

- tag: force_nocn
type: domain_set
args:
files:
- "/etc/mosdns/rules/force-nocn.txt"

- tag: hosts
type: hosts
args:
files:
- "/etc/mosdns/rules/hosts.txt"

- tag: local_ptr
type: domain_set
args:
files:
- "/etc/mosdns/rules/local-ptr.txt"

- tag: forward_udp
type: forward
args:
concurrent: 2
upstreams:
- addr: "223.5.5.5"
- addr: "114.114.114.114"

- tag: forward_local
type: forward
args:
upstreams:
- addr: "https://223.5.5.5/dns-query"
enable_http3: true

- tag: forward_remote
type: forward
args:
upstreams:
- addr: "https://8.8.8.8/dns-query"
enable_http3: true

- tag: forward_remote_upstream
type: sequence
args:
- exec: $forward_remote

- tag: has_resp_sequence
type: sequence
args:
- matches: has_resp
exec: accept

- tag: query_is_non_local_ip
type: sequence
args:
- exec: $forward_local
- matches: "!resp_ip $geoip_cn"
exec: drop_resp

- tag: fallback
type: fallback
args:
primary: query_is_non_local_ip
secondary: forward_remote_upstream
threshold: 500
always_standby: true

- tag: apple_domain_fallback
type: fallback
args:
primary: query_is_non_local_ip
secondary: forward_udp
threshold: 100
always_standby: true

- tag: query_is_apple_domain
type: sequence
args:
- matches: "!qname $geosite_apple"
exec: return
- exec: $apple_domain_fallback

- tag: query_is_local_domain
type: sequence
args:
- matches: qname $geosite_cn
exec: $forward_local

- tag: query_is_no_local_domain
type: sequence
args:
- matches: qname $geosite_no_cn
exec: $forward_remote_upstream

- tag: query_is_force_cn_domain
type: sequence
args:
- matches: qname $force_cn
exec: $forward_local

- tag: query_is_force_no_cn_domain
type: sequence
args:
- matches: qname $force_nocn
exec: $forward_remote_upstream

- tag: query_is_reject_domain
type: sequence
args:
- matches:
- qtype 12
- qname $local_ptr
exec: reject 3
- matches: qtype 65
exec: reject 3

- tag: main_sequence
type: sequence
args:
- exec: $hosts
- exec: jump has_resp_sequence
- exec: forward_edns0opt 8
- exec: $query_is_apple_domain
- exec: jump has_resp_sequence
- exec: $query_is_force_cn_domain
- exec: jump has_resp_sequence
- exec: $query_is_reject_domain
- exec: jump has_resp_sequence
- exec: $query_is_force_no_cn_domain
- exec: jump has_resp_sequence
- exec: $query_is_local_domain
- exec: jump has_resp_sequence
- exec: $query_is_no_local_domain
- exec: jump has_resp_sequence
- exec: $fallback

- tag: udp_server
type: udp_server
args:
entry: main_sequence
listen: ":53"

- tag: tcp_server
type: tcp_server
args:
entry: main_sequence
listen: ":53"

安装

上述工作都完成后就可以使用下述的安装命令了:
v4 版本:
docker run -d\
--name mosdns --net=host \
-v /etc/mosdns:/etc/mosdns \
irinesistiana/mosdns:v4.5.3
v5 版本:
docker run -d\
--name mosdns --net=host \
-v /etc/mosdns:/etc/mosdns \
irinesistiana/mosdns:latest
至此,Mosdns 已经搭建完成,理论上从这一刻开始,你就可以直接使用 DNS 服务了。但是,这里存在很多问题:
  • 没有可视化的、傻瓜式的界面
  • 想要自动更新广告屏蔽列表该怎么办
因此接下来我们就需要利用 AdGuardHome 来解决这一问题。

AdGuardHome

下面是 AdGuardHome 的 Docker 安装命令。
docker run -d --name adguardhome\
--restart unless-stopped\
-v /my/own/workdir:/opt/adguardhome/work\
-v /my/own/confdir:/opt/adguardhome/conf\
--net=host
-d adguard/adguardhome
# 详细参数请参考 https://hub.docker.com/r/adguard/adguardhome
安装完成后只需要使用浏览器访问 IP + 3000 端口即可进入服务初始化界面。在部署端口时需要注意一下:
  • 网页管理界面端口建议不使用默认 80,方便你使用 Nginx 或 Caddy 反代
  • DNS 服务端口也建议不要用 53,因为已经被 Mosdns 占用了
接下来设置完成用户名和密码登录,就来到了主界面。
利用 Mosdns (v4 or v5) 和 AdGuardHome 搭建自己的 DNS
接下来进入 DNS 设置页,将上游 DNS 服务器设置为 127.0.0.1,此时代表 AdGuardHome 将向 Mosdns 转发 DNS 查询。
利用 Mosdns (v4 or v5) 和 AdGuardHome 搭建自己的 DNS
同时建议在 DNS 服务配置启用 EDNS 客户端子网。
利用 Mosdns (v4 or v5) 和 AdGuardHome 搭建自己的 DNS
不建议开启缓存,缓存可以交给 Mosdns,这里 AdGuardHome 的作用就是转发、记录和去广告。
利用 Mosdns (v4 or v5) 和 AdGuardHome 搭建自己的 DNS
接下来还有两个地方需要设置:加密设置和设置 DNS 拦截列表。
加密设置在这里,主要能够支持 DoH 和 DoT。这里也要说明一下不建议直接使用 IP 形式的 DNS(使用我们自行搭建的服务时):
利用 Mosdns (v4 or v5) 和 AdGuardHome 搭建自己的 DNS
而 DNS 拦截列表就是可以去广告和自动更新规则的地方,规则请自行搜索:
利用 Mosdns (v4 or v5) 和 AdGuardHome 搭建自己的 DNS
PS:有个配置建议,可以打开 AdGuardHome.yaml 在 dns 下面增加 trusted_proxies,主要是能够获取到上游的真实请求地址,方便 ECS 的运行。

如何访问

这里建议使用 Nginx 或者 Caddy 反代 AdGuardHome,本地使用 DoH 地址进行测试,我自己使用得是 Caddy,可以参考一下:
{
  email you@email.com
}
https://you.domain {
    reverse_proxy https://172.17.0.1:<AdGuardHome 加密设置中的 HTTPS 端口> {
        transport http {
            tls_insecure_skip_verify
        }
    }
}
最终生成的 DoH 地址就是 https://you.domain/dns-query,大家可以把这一地址填写到对应的工具中即可。
另外,关于搭建的服务器有一些建议:
  • 到测试环境的延迟尽量低,否则容易出现在 DNS 解析阶段就浪费大量时间的情况
  • 有一定的 SLA 保证
  • 由于需要用到 HTTPS 来访问 DNS,所以如果你没有备案的域名可能无法在国内服务器上进行测试,建议可以选择回国线路相对较好的香港服务器
个人搭建并体验过的服务器厂商有
上面这两家的部分香港服务器线路都不错,建议可以试一下。另外,腾讯云的轻量服务器https://cloud.tencent.com/)也可以考虑的。
PS:括号内的不带 AFF。
参考资料:

原文地:址https://www.xukecheng.tech/use-mosdns-and-adguardhome-to-build-your-own-dns

© 版权声明

相关文章

暂无评论

暂无评论...