原文地址:https://www.xukecheng.tech/use-mosdns-and-adguardhome-to-build-your-own-dns
前言
工具选型
服务搭建
- 经过测试 Mosdns 的 DNS 查询转发速度相对更快,且查询条件能做到更加精细地控制,这里可以参考规则部分
- Mosdns 的域名匹配工具可以直接利用一些常用的域名文件做到更加方便和精准地分流;Adguardhome 不是不行,但是很麻烦
Mosdns
config.yaml
,下面是相关链接可以复制或下载使用资源文件
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
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 版本的配置文件作为参考。# 配置文件的部分内容参考了下面这个网站
# 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"
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
- 没有可视化的、傻瓜式的界面
- 想要自动更新广告屏蔽列表该怎么办
AdGuardHome
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
- 网页管理界面端口建议不使用默认 80,方便你使用 Nginx 或 Caddy 反代
- DNS 服务端口也建议不要用 53,因为已经被 Mosdns 占用了






dns:
trusted_proxies:
- 0.0.0.0/0
如何访问
{
email you@email.com
}
https://you.domain {
reverse_proxy https://172.17.0.1:<AdGuardHome 加密设置中的 HTTPS 端口> {
transport http {
tls_insecure_skip_verify
}
}
}
- 到测试环境的延迟尽量低,否则容易出现在 DNS 解析阶段就浪费大量时间的情况
- 有一定的 SLA 保证
- 由于需要用到 HTTPS 来访问 DNS,所以如果你没有备案的域名可能无法在国内服务器上进行测试,建议可以选择回国线路相对较好的香港服务器
原文地:址https://www.xukecheng.tech/use-mosdns-and-adguardhome-to-build-your-own-dns