2024-03-13 13:06阅读: 2084评论: 0推荐: 0

使用 AdGuard Home 搭建自用 DoH 服务

众所周知,AdGuard Home 是一款很不错的自建 DNS 服务器软件,除了广告拦截之外的功能都挺好用。自己搭建也很简单,参照官方文档几行命令就能搞定。这几年我也一直在使用家里树莓派上搭建的 AdGuard Home 作为局域网 DNS 服务器,体验很不错。这里要分享的是如何通过 Docker Compose 部署 AdGuard Home 并搭建一个私有自用的 DoH 服务,以及如何使用 AdGuard Home 实现 DNS 分流解析。

搭建 AdGuard Home

国内搭建公共 DNS 服务需要申请无法申请的牌照,用国外服务器搭建也会被抢答或者阻断,53(UDP)和 853(DoT)都是重点关注对象,所以目前只推荐使用 443(DoH 或 DoQ)的方式连接。

Docker 的安装使用可以参考前面的文章:Debian 系统安装 Docker 教程

在合适的路径下(假设为 /home/adguardhome)新建一个 docker-compose.yaml 文件,我们只需要 DoH 服务,因此可以只映射容器内的 443 端口出来,3000 端口是 Web 管理页面,可以根据自己需求修改。此外,这里可以选择添加一个 Volume 用来映射域名证书文件,避免后面手动粘贴的麻烦。

免费的 SSL 证书申请可以参考前面的文章:使用 acme.sh 自动签发和更新证书

同时,当你全部配置好正常运行后会发现控制面板首页的统计数据中来源 IP 全是 Docker 的 172 内网 IP 段,这里需要在配置文件中设置 trusted_proxies 参数,指定受信任的来源 IP 地址列表,AdGuard Home 才会获取代理标头(如 X-Real-IP,X-Forwarded-For 等)中的客户端真实 IP 地址。这里也可以先设置 Docker 容器的 IP 地址段,方便后面在配置文件中添加。

综上,你的 docker-compose.yaml 文件可以写成下面这样:

version: "3"
services:
adguardhome:
image: adguard/adguardhome:latest
container_name: adguardhome
restart: unless-stopped
ports:
- 127.0.0.1:8443:443/tcp
- 127.0.0.1:3000:3000/tcp
volumes:
- /home/adguardhome/work:/opt/adguardhome/work
- /home/adguardhome/conf:/opt/adguardhome/conf
- /path/to/ssl:/opt/adguardhome/cert
networks:
agh_net:
ipv4_address: 172.18.1.2
networks:
agh_net:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.18.1.0/24

使用 docker compose up 命令拉取镜像生成相关文件后再 ctrl + c 停止,修改 conf/AdGuardHome.yaml 配置文件,找到 trusted_proxies 参数,后面添加一行 172.18.1.0/24:

trusted_proxies:
- 127.0.0.0/8
- ::1/128
- 172.18.1.0/24

PS:有个配置建议,可以打开 AdGuardHome.yaml 在 dns 下面增加 trusted_proxies,主要是能够获取到上游的真实请求地址,方便 ECS 的运行。

dns:
trusted_proxies:
- 0.0.0.0/0

然后 docker compose up -d 启动容器服务。

配置 Nginx 和 DoH 服务

在公网搭建 AdGuard Home 最怕的是主动探测和各种扫描,地址暴露后可能会变成公共 DNS 或者被各种攻击,导致你的域名或服务器被玩坏。你可以自行探索 Nginx 鉴权的方法 ,同时 AdGuard Home 本身也支持设置白名单客户端,两种方式相结合可以提高安全性,降低暴露风险。

配置 Nginx

https://adguard-dns.io/kb/ru/adguard-home/faq/#reverseproxy

你应该将 AdGuard Home 服务写在 443 server 块中,这里略去其它相关配置,只贴出关键 location 块:

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://127.0.0.1:3000/;
}
location /dns-query {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass https://127.0.0.1:8443/dns-query;
}

这里请将 location /dns-query 路径修改为其它随机字符串,防止主动探测,同时也可以将控制面板路径修改为复杂地址。

你还可以顺便在这里限制来源 IP,只允许你常用的 IP 访问,一般可以设置为你所在地区的公网 IP 段,这种限制方式的缺点是不够灵活。最后你的 Nginx 配置可以类似这样:

location /aghome/ {
allow 192.168.1.1;
allow 172.16.0.0/16;
deny all;
proxy_cookie_path / /aghome/;
proxy_redirect / /aghome/;
proxy_set_header Host $host;
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:3000/;
}
location /random-string {
allow 192.168.1.1;
allow 172.16.0.0/16;
deny all;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass https://127.0.0.1:8443/dns-query;
}

重载 Nginx 后打开你的域名地址进行安装,只需将第一步中的管理页面地址(Admin Web Interface)端口修改为和上面对应的 3000,其余可以保持默认一直下一步直到完成安装。

配置 DoH 服务

登陆控制面板后台,进入 设置-加密设置 页面,☑️ 启用加密,服务器名称中输入域名,HTTPS 端口填写 443,DNS-over-TLS 端口和 DNS-over-QUIC 端口如果不需要用到留空即可。下面的证书路径填写前面 docker-compose.yaml 中对应的文件路径。

优化后的 Nginx 配置示例

location /doh-query {
proxy_pass https://127.0.0.1:83/dns-query;
# 基本配置
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
# 启用 SSL 服务器名称指示(SNI)
proxy_ssl_server_name on;
# 启用 HTTP/1.1 Keepalive
proxy_http_version 1.1;
proxy_set_header Connection "";
# 优化缓冲区大小
proxy_buffers 16 16k;
proxy_buffer_size 32k;
# 优化超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 启用 Gzip 压缩
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1000;
gzip_vary on;
# 添加安全头
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
# 启用缓存(可选)
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=adguard_cache:10m max_size=1g inactive=60m use_temp_path=off;
proxy_cache adguard_cache;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
}

优化点详解

1. 启用 HTTP/1.1 Keepalive

  • 通过 proxy_http_version 1.1proxy_set_header Connection "",启用 HTTP/1.1 Keepalive,减少连接建立的开销,提升性能。

2. 优化缓冲区大小

  • 调整 proxy_buffersproxy_buffer_size,确保 Nginx 能够高效处理较大的响应数据。

3. 调整超时设置

  • 设置合理的超时值(如 proxy_connect_timeoutproxy_send_timeoutproxy_read_timeout),避免请求长时间挂起。

4. 启用 Gzip 压缩

  • 通过 gzip 压缩响应数据,减少传输的数据量,提升客户端加载速度。

5. 添加安全头

  • 添加以下安全头,增强安全性:
    • Strict-Transport-Security:强制使用 HTTPS。
    • X-Content-Type-Options:防止 MIME 类型嗅探。
    • X-Frame-Options:防止点击劫持。
    • X-XSS-Protection:防止跨站脚本攻击(XSS)。

6. 启用缓存(可选)

  • 如果 AdGuard Home 的响应内容变化不频繁,可以启用 Nginx 缓存,减少对后端服务器的请求压力。

7. 启用 SSL 服务器名称指示(SNI)

  • 通过 proxy_ssl_server_name on,确保 Nginx 能够正确传递 SNI 信息,避免 SSL 握手失败。

其他建议

1. 启用 HTTP/2

如果你的 Nginx 支持 HTTP/2,可以在监听端口时启用:

listen 443 ssl http2;

2. 优化 SSL 配置

使用现代的 SSL 配置,确保安全性和性能:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

3. 日志优化

如果不需要详细日志,可以关闭或减少日志记录,以降低磁盘 I/O 压力:

access_log off;
error_log /var/log/nginx/error.log warn;

4. 限制请求速率

如果需要防止滥用,可以限制请求速率:

limit_req_zone $binary_remote_addr zone=adguard_limit:10m rate=10r/s;
location /doh-query {
limit_req zone=adguard_limit burst=20 nodelay;
# 其他配置
}

测试配置

在应用配置后,使用以下命令测试 Nginx 配置是否正确:

sudo nginx -t

如果测试通过,重新加载 Nginx:

sudo systemctl reload nginx

通过以上优化,你的 AdGuard Home Nginx 反向代理应该能够更高效、安全地运行。

限制 ClientID

AdGuard Home 0.105.0 及之后版本支持为部分加密查询方式设置 ClientID,你可以限制白名单内 ClientID 才能进行查询。对于 DoH 查询,只需要在地址最后加上一段字符串即可,这里以随机 UUID(7017d85e-99d3-46df-bcbc-77a0a33c9cee)举例。

为了方便查看日志,你可以先设置一个持久客户端名称,在 设置-客户端 中添加客户端:

设置-DNS 设置-访问设置-允许的客户端 中输入该 UUID:

完成以上设置后,你可以尝试通过 https://xxx.example.org/random-string/7017d85e-99d3-46df-bcbc-77a0a33c9cee 链接进行 DNS 查询了,并且基本可以确保只有你自己才能使用。

题外话:自建 DNS 服务器在代理过程中的作用

这里说点题外话,如果你是为了搭建无污染的 DNS 在代理工具中使用,效果可能并不明显。在基于 IP 规则分流的代理过程中,DNS 的作用仅仅是在客户端发起请求的第一步中解析获得 IP 地址用来做规则匹配,即使得到的是错误的 IP,只要命中代理规则,多数代理工具依然会封装域名后发送到远程服务器上解析并建立连接,与前面客户端解析获得的 IP 没有关系,所以不会对访问造成影响。

而且这一作用也被今天主流使用的 fake-ip 所弱化,fake-ip 跳过了上面所述的第一步,命中规则的域名不会在本地进行 DNS 解析,代理工具会直接返回一个内网 IP 地址并建立映射关系,同时在远程服务器上解析并连接后通过该内网 IP 地址进行代理。fake-ip 的优势很明显,加快了响应速度,同时也不会造成 DNS 泄漏。但域名规则是写不完的,总有些规则之外的漏网之鱼(小众域名)需要一个可靠的 DNS 解析兜底。 此外 fake-ip 有一些老生常谈的小问题,我个人是不大喜欢的,仍是 redir-host 的余党。

由此,自建无污染 DNS 服务器在代理过程中的意义只是为了应对部分特殊情况以及获得更好的隐私性,顺便解决被各种「焦虑化」的 DNS 泄漏问题,对大多数人来说属于可有可无的东西。

设置 DNS 分流解析

AdGuard Home 0.107.3 及之后版本支持为指定域名设置 DNS 上游的,也可以直接使用文件列表。前面提到我还有一台树莓派在局域网内运行 AdGuard Home 服务,这时便解锁了一个新的玩法,树莓派上的 AdGuard Home 设置 DNS 分流解析。

可以实现国内域名通过 AliDNS 或 DNSPod 进行解析,其余域名通过自建的海外 DoH 服务进行解析,配合 AdGuard Home 的乐观缓存,也不会对速度造成多大影响。不过由于国内域名列表肯定是不完整的,不在列表中的域名会通过海外 DoH 解析,得到的 IP 结果是国内的还好,可以直接连接,否则会通过远程服务器连接,此时要是该域名有国内 CDN 节点就绕远了。因此比较依赖规则文件的及时更新和准确性,最后选择了使用 dnsmasq-china-list 项目。

这里写了一个 shell 脚本将 dnsmasq-china-list 发布的文件转换为 AdGuard Home 能识别的格式,如有需要可以参考修改。

#!/bin/bash
# Writen by ATP on Jan 25, 2024
# Website: https://atpx.com
# AdGuard Home 项目路径
AGH_PATH="/home/adguardhome"
# 国内 DNS 服务器,多个用空格隔开
CN_DNS="https://223.6.6.6/dns-query https://120.53.53.53/dns-query"
# 海外 DNS 服务器
GLOBAL_DNS="https://xxx.example.org/random-string/7017d85e-99d3-46df-bcbc-77a0a33c9cee"
# dnsmasq-china-list 规则文件,无法下载的话可以找 CDN 或自建反代
accelerated_domains="https://raw.githubusercontent.com/felixonmars/dnsmasq-china-list/master/accelerated-domains.china.conf"
apple_domains="https://raw.githubusercontent.com/felixonmars/dnsmasq-china-list/master/apple.china.conf"
# 下载文件并合并
wget -O "$AGH_PATH/cn-domains.conf" $accelerated_domains
wget -O "$AGH_PATH/cn-apple.conf" $apple_domains
cat "$AGH_PATH/cn-apple.conf" >> "$AGH_PATH/cn-domains.conf"
# 转换为 AdGuard Home 格式
awk -v CN_DNS="$CN_DNS" -F/ '/server=/{print "[/"$2"/]"CN_DNS}' "$AGH_PATH/cn-domains.conf" > "$AGH_PATH/cn-dns.txt"
# 添加默认海外 DNS
sed -i "1i\\$GLOBAL_DNS" "$AGH_PATH/cn-dns.txt"
# 移动文件到 AdGuard Home 目录
mv "$AGH_PATH/cn-dns.txt" "$AGH_PATH/work/data/"
# 清理临时文件
rm "$AGH_PATH/cn-domains.conf"
rm "$AGH_PATH/cn-apple.conf"
echo "规则转换完成"
# 重启 AdGuard Home
# cd $AGH_PATH
# docker compose restart

停止 AdGuard Home 后编辑目录下配置文件 conf/AdGuardHome.yaml,找到 upstream_dns_file: "" 参数,修改为:

upstream_dns_file: /opt/adguardhome/work/data/cn-dns.txt

然后启动 AdGuard Home 即可实现 DNS 分流解析。最后你可以设置一个 crontab 任务,定时执行脚本自动更新域名规则并重启 AdGuard Home,这里不再赘述。

原文
https://atpx.com/blog/adguard-home-doh-server-with-docker/
参考
https://www.xukecheng.tech/use-mosdns-and-adguardhome-to-build-your-own-dns
https://blog.timochan.cn/adguard_home_configuration_guide
https://www.nange.cn/dns-over-https-for-adguard.html
https://shiina-rimo.cafe/p/hello-world/
https://www.isisy.com/1387.html
https://blog.tsinbei.com/archives/780/
https://video.nginx-cn.net/blog/using-nginx-as-dot-doh-gateway/

本文作者:xututu6

本文链接:https://www.cnblogs.com/xututu6/p/18070399

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   xututu6  阅读(2084)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起