安装

安装之前

先啰嗦两句,明确一下为什么要使用mosdns。mosdns是一个DNS转发器,同类工具还有smartdns等等。笼统的说,使用它是为了更好地掌控家庭网络的DNS解析。具体一点,可以分为以下几个原因:

  • 通过代理查询某些DNS,最大程度避免DNS污染和DNS泄露
  • 屏蔽某些域名,已达到去广告的目的,可以取代AdGurad Home
  • 对某些域名设置ipv4/ipv6偏好
  • 通过设置乐观缓存,常用域名的解析可以做到微秒级别,加快访问速度
  • 设置多个上游DNS,并发查询,获取最快的结果以及避免故障
  • 设置ECS,获得尽可能准确和优质的解析结果
  • 利用CF优选IP设置hosts,加快家庭网络中的Cloudflare网站访问速度(这个到时候单独写一篇文章😬 )

以上是我个人在家庭网络中自己搭建DNS服务器的主要原因,下文会展开描述,除此之外,mosdns本身还有不少功能,我暂时用不到,就不过多介绍了。

另外,mosdns的wiki写的挺详细的,如果你是纯小白,需要先把wiki看一下,我这里主要分享wiki上没有的、我自己的配置思路,很多wiki中有的细节不会重复讲。

开始安装

我选择在Linux宿主机上安装,使用systemd来管理,我使用的发行版是Debian,不过支持systemd的发行版应该都是适用的。

  1. 首先确保curl unzip已经安装,可以通过sudo apt update && apt install -y curl unzip来安装
  2. 访问mosdns的release页面,选择对应架构的包,例如我是Linux系统,64位的x86处理器,那么选择mosdns-linux-amd64.zip这个包
  3. 运行命令curl -LO https://github.com/IrineSistiana/mosdns/releases/latest/download/mosdns-linux-amd64.zip下载最新版本的mosdns。如果你需要代理,那么添加-x参数,例如 curl -x socks5h://127.0.0.1:7890 -LO https://github.com/IrineSistiana/mosdns/releases/latest/download/mosdns-linux-amd64.zip
  4. 运行命令unzip -d mosdns mosdns-linux-amd64.zip,解压其中的文件到当前文件夹的mosdns目录
  5. 运行chmod +x ./mosdns/mosdns && sudo mv ./mosdns/mosdns /usr/local/bin命令将可执行文件转移到bin目录,此时执行mosdns -h应该会有相关使用帮助的输出
  6. mosdns支持自动安装为systemd服务,先运行sudo mv ./mosdns /etc把配置文件及目录转移到指定位置,然后只需要运行命令sudo mosdns service install -d /etc/mosdns -c /etc/mosdns/config.yaml即可
  7. 此时运行命令systemd status mosdns应该有相关输出,命令不报错。如果需要开机启动(通常都需要),运行命令systemd restart mosdns

以上就安装成功了,但是还没有启动,因为接下来需要进行一番配置

配置

配置思路

我个人的配置思路是这样的

  1. 首先匹配mosdns的hosts文件,主要用途就是CF优选IP,这类域名不需要再去查询,直接响应就好
  2. 然后匹配拒绝的域名列表,也就是去广告功能,可以参考这份广告域名列表,个人使用下来感觉作用不大,现在常见的广告一般不会使用专门的域名,不过偶尔确实需要屏蔽一些域名,所以需要配置下
  3. 接下来是DDNS域名,需要把TTL设置小一点
  4. 然后其他的域名都先查询缓存,这里设置的是乐观缓存,有些人不喜欢,但我实际用下来感觉没啥问题
  5. 接着我设置的是白名单,名单内的域名转发给国内的直连的DNS
  6. 如果不在名单内,或者上一步查询没有响应,那么则转发给代理的DNS上游,同时需要设置ECS和prefer_ipv4

配置文件

下面用我的配置文件分段来具体解释一下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
log:
  level: warn
  production: true

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

  - tag: cache
    type: cache
    args:
      size: 10240
      lazy_cache_ttl: 259200

  - tag: cn_forward
    type: forward
    args:
      concurrent: 3
      upstreams:
        - tag: ali_dns
          addr: "223.5.5.5"
        - tag: dnspod
          addr: "119.29.29.29"
        - tag: 114_dns
          addr: "114.114.114.114"

  - tag: proxy_forward
    type: forward
    args:
      concurrent: 3
      upstreams:
        - tag: cf_doh
          addr: "https://1.1.1.1/dns-query"
          socks5: "127.0.0.1:7890"
        - tag: google_doh
          addr: "https://8.8.4.4/dns-query"
          socks5: "127.0.0.1:7890"
        - tag: cf_dot
          addr: "tls://one.one.one.one"
          socks5: "127.0.0.1:7890"

  - tag: ddns_query
    type: sequence
    args:
      - exec: ttl 30
      - exec: $cn_forward

最上面是设置日志等级,没啥好说的,按需调整就好。然后是五个插件,分别用来做不同的事情,

  • hosts插件,指定了hosts文件的路径,这里要注意,mosdns和系统的hosts文件格式不同,规则在这里,所以不要直接拷贝系统hosts文件
  • cache插件,由于我的设备内存挺充足的,所以缓存条数设置的比较大,如果你的内存比较小,设置个1024就可以了,如果不喜欢乐观缓存,或者按照我的配置好之后总是出现网页首次加载要很久的情况,那就把lazy_cache_ttl改成0
  • cn_forward插件,我这里的就是用的是比较有名的公共DNS,没有配置DOH之类的,因为这里只会查白名单内的域名,没什么泄露污染等问题,只追求速度
  • proxy_forward插件,首先这里的代理需要自己搞定,然后这里使用DOH和DOT,原因是它们可以保证查询是加密的,相对安全一些,这里追求的是安全第一,速度第二
  • ddns_query插件,不一定处理的就是DDNS域名,其他不希望使用缓存的域名都是类似的处理流程,我这里比较简单,把ttl改成30,然后扔给cn_forward转发出去

接着就是把上面这些插件组合起来,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  - tag: main
    type: sequence
    args:
      - exec: $hosts
      - matches:
          - has_resp
        exec: accept

      - matches:
          - qname &/etc/mosdns/reject-list.txt &/etc/mosdns/my-reject-list.txt
        exec: reject 3

      - matches:
          - "qname ddns.my.domain"
        exec: goto ddns_query

      - exec: $cache
      - matches:
          - has_resp
        exec: accept

      - matches:
          - qname &/etc/mosdns/direct-list.txt &/etc/mosdns/my-direct-list.txt
        exec: $cn_forward

      - matches:
          - has_resp
        exec: accept

      - matches:
        - "!has_resp"
        exec: prefer_ipv4
      - exec: ecs 1.1.0.1
      - exec: $proxy_forward

这个main插件前面配置思路已经基本讲过了,补充说明一下没讲到的,配置prefer_ipv4是因为我的代理对于ipv6的支持很差,所以能用v4就用v4。至于ECS,是为了尽可能的获取到距离国内近的IP地址,有没有用我也没验证过,这一行可能纯粹心理安慰。然后这里补充下直连的域名集合,我用的是这个域名直连列表,格式兼容,可以直接用。

实际使用的时候,你需要把my.domain改成自己的域名或者去掉那三行,然后确保/etc/mosdns目录下有hosts.txt reject-list.txt my-reject-list.txt direct-list.txt my-direct-list.txt几个文件。

因为手动更新太麻烦了,所以肯定要搭配一个脚本的,执行sudo touch /etc/mosdns/update_domain.sh && sudo chmod +x /etc/mosdns/update_domain.sh, 然后把下面内容写进去,再添加一个cron job就搞定了。

1
2
3
4
5
#!/bin/bash

curl -x socks5h://127.0.0.1:7890 -o /etc/mosdns/direct-list.txt https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/direct-list.txt && \
curl -x socks5h://127.0.0.1:7890 -o /etc/mosdns/reject-list.txt https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/reject-list.txt && \
systemctl restart mosdns

我设置的是每天更新 30 7 * * * /etc/mosdns/update_domain.sh

配置还没完,还需要启动一个服务器

1
2
3
4
5
  - tag: udp_server
    type: udp_server
    args:
      entry: main
      listen: :53

这样就算好了,完整配置看这个gist

启动之前确保本机的53端口没有被占用,并且把代理改成了自己的,运行systemctl start mosdns启动服务,接着执行systemctl status mosdns看下是否成功。

要是失败,那我也没办法🤪 ,需要自己解决

进阶配置

这里是99%的人都不会用到的配置,如果要配置你需要有自己的域名及对应的证书

我就是想在内网用自己的DOH和DOT 😂

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
  - tag: tcp_server
    type: tcp_server
    args:
      entry: main
      listen: :853
      cert: "/etc/mosdns/dns.my.domain.pem"
      key: "/etc/mosdns/dns.my.domain.key"

  - tag: http_server
    type: http_server
    args:
      entries:
        - path: "/dns-query"
          exec: main
      src_ip_header: "X-Forwarded-For"
      listen: :443
      cert: "/etc/mosdns/dns.my.domain.pem"
      key: "/etc/mosdns/dns.my.domain.key"

验证

如果一切顺利的话,接下来就是检验成果了,假设你搭建mosdns的设备的内网地址是192.168.1.2,那么在内网的另一台设备运行命令nslookup www.baidu.com 192.168.1.2,只要有结果,就是好的。

不过nslookup没办法指定DOH和DOT服务器,这里推荐个替代工具dnslookup,使用方法就不赘述了,看README吧

参考链接