nginx与coredns加dnscrypt-proxy实现自建DOH及China分流

于 2023-03-15 发布

如果只要实现DOH那很简单,CoreDNS本身就可以整一个出来。但是关键是如何避免被扫描到而被滥用、避免被扫描到然后被枪毙。之前看到过一个reddit老哥分享的方法,就是用很长的字符串替换标准DOH的/dns-queryuri来充当password,实现避免除了自己人都无法访问这个DOH服务器的效果。

假设要用sF5FWjUk来作为URI,那么nginx中需要配置一个Location块:

1
2
3
4
5
6
7
8
9
location /sF5FWjUk {
  proxy_redirect off;
  proxy_http_version 1.1;
  proxy_set_header Host $http_host;
  # show real IP
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_pass http://127.0.0.1:8443/dns-query;
}

就是说匹配/sF5FWjUk的访问,都转发(proxy_pass)到监听在127.0.0.1的8443端口的CoreDNS所提供的DOH服务上。而CoreDNS的文档里有说明,CoreDNS提供一种特殊的DOH模式:CoreDNS自己不作为TLS终点,也就是CoreDNS虽然提供DOH服务但是不对请求进行HTTPS加解密,而是让另一个软件(比如nginx)负责这个工作。因此CoreDNS的配置文件只需要这样写:

1
2
3
4
https://.:8443 {
    bind 127.0.0.1
    forward . 127.0.0.1:8053
}

简简单单,功能类似于:把接收到的DoH请求转换成普通DNS请求,转发给监听在8053端口的dnscrypt-proxy。

所以整个流程下来就实现了:

  1. 非公开DoH,防止被探测和滥用
  2. DoH服务
  3. dnscrypt-proxy所提供的ECS、加密DNS请求、中国域名分流请求

等功能。其实dnscrypt-proxy那一部份不是必要的,如果不需要edns-client-subnet之类的功能,对于log也不是特别在意的话,把CoreDNS的forward写成比如forward . 8.8.8.8:53就完事了。

目录