DNS是上网的第一步,每次访问网站前,系统都要先通过DNS把域名解析成IP地址。问题是传统DNS查询走的是UDP 53端口,内容完全明文,同一网络里的任何人、你的ISP、甚至运营商的劫持设备都能清楚看到你访问了哪些域名。DoH(DNS over HTTPS)的出现就是为了解决这个问题,它把DNS查询封装在HTTPS加密通道里,外部只能看到你和DNS服务器之间存在加密流量,看不到具体查询内容。本文以Fedora为平台,从原理到实操完整讲一遍DoH的配置过程。

DoH的工作原理与DoT的区别
理解DoH之前先回顾传统DNS的流程:客户端向DNS服务器发送UDP请求,服务器返回解析结果,整个过程没有加密和认证。这意味着查询内容可以被窃听,返回结果也可以被篡改,早年运营商插广告弹窗的丑闻正是利用了这个缺陷。
DoH的全称是DNS over HTTPS,它的思路很直接:把DNS报文塞进HTTPS的POST或GET请求里,和普通网页流量混在一起走443端口。由于流量特征与访问普通网站几乎一致,网络层面的封锁和识别难度大大增加。RFC 8484标准定义了DoH的报文格式,目前主流公共DNS服务商如Cloudflare的1.1.1.1、Google的8.8.8.8、Quad9都提供DoH端点。
另一个容易混淆的概念是DoT(DNS over TLS),它使用853端口专门传输加密DNS。两者安全性相当,但DoT有独立端口,容易被网络管理员识别并封锁;DoH共用443端口,隐蔽性更好。对于家庭或办公网络环境,DoH通常是更稳妥的选择。Fedora下两种方案都能实现,本文以DoH为主线。
使用dnscrypt-proxy在Fedora上配置DoH
Fedora官方仓库里有dnscrypt-proxy,它同时支持DoH和DNSCrypt协议,是目前最省心的方案。先安装软件包并了解服务结构:
# 安装 dnscrypt-proxy sudo dnf install dnscrypt-proxy -y # 查看服务状态,确认是否已自动启动 systemctl status dnscrypt-proxy
dnscrypt-proxy默认监听本机的127.0.2.1:53,配置文件位于/etc/dnscrypt-proxy/dnscrypt-proxy.toml。用文本编辑器打开它,重点修改两处:一是server_names指定上游DoH服务器,二是确认监听地址。示例如下:
# 编辑主配置文件 sudo vi /etc/dnscrypt-proxy/dnscrypt-proxy.toml # 关键配置项 server_names = ['cloudflare', 'google'] listen_addresses = ['127.0.2.1:53'] # 开启DNS缓存,减少重复查询 cache = true cache_size = 4096 cache_min_ttl = 2400 cache_max_ttl = 86400
配置文件里server_names的取值必须与同目录dnscrypt-resolvers.csv中列出的名称一致,Cloudflare和Google都是默认支持的。修改保存后重启服务并设置开机自启:
sudo systemctl restart dnscrypt-proxy sudo systemctl enable dnscrypt-proxy # 测试本地代理是否正常解析 dnscrypt-proxy -resolve ippipp.com
让系统流量真正走DoH通道
dnscrypt-proxy只是在本机开了一个代理入口,还需要把系统DNS指向它才算完成闭环。Fedora默认使用NetworkManager管理网络,最简单的方式是通过nmcli命令把当前连接的DNS改为127.0.2.1:
# 查看当前连接名称 nmcli connection show # 将指定连接的DNS指向本地代理 sudo nmcli connection modify "Wired connection 1" \ ipv4.dns "127.0.2.1" \ ipv4.ignore-auto-dns yes # 重新激活连接使配置生效 sudo nmcli connection up "Wired connection 1" # 验证 resolv.conf 已指向本地代理 cat /etc/resolv.conf
如果你使用Wi-Fi,把连接名换成对应的SSID即可。另一个更底层的方案是使用systemd-resolved:编辑/etc/systemd/resolved.conf,设置DNS=127.0.2.1并开启DNSStubListenerExtra,然后重启systemd-resolved服务。两种方式二选一即可,不要同时配置,避免端口冲突。
需要注意,dnscrypt-proxy默认监听的127.0.2.1:53可能和systemd-resolved的本地存根监听冲突。如果遇到解析失败,可以将dnscrypt-proxy改监听到127.0.2.1:5353这类非标准端口,再在resolved配置里指向该端口,或者干脆禁用systemd-resolved的存根功能,让resolv.conf直接指向dnscrypt-proxy。
验证加密效果与日常使用建议
配置完成后必须验证流量确实走了加密通道。Cloudflare提供了一个专门的检测地址:浏览器访问1.1.1.1的官方帮助页面,或使用命令行检测:
# 使用 kdig 检测 DoH 是否生效(需安装 knot-dnsutils) sudo dnf install knot-dnsutils -y kdig -d @127.0.2.1 +https ippipp.com # 抓包确认没有明文DNS流量发往外网53端口 sudo tcpdump -i any port 53 and not src host 127.0.0.1
如果tcpdump在过滤掉本机回环流量后仍然捕获到发往外部53端口的包,说明还有应用绕过了系统DNS直连,常见 culprit 是浏览器独立配置的DNS。Firefox和Chrome都支持在浏览器层面单独开启DoH,建议同时在浏览器设置里启用,并选择与dnscrypt-proxy一致或不同的服务商做冗余。
日常使用中还有几点值得留意:其一,某些企业内网需要解析内部域名,可以在dnscrypt-proxy配置中通过cloaking_rules或forwarding_rules把特定域名转发给内网DNS;其二,切换DoH后解析延迟通常会增加几毫秒,但本地缓存能显著抵消这一开销;其三,定期检查服务商的隐私政策,确认其承诺不记录查询日志。配置完成后,你的域名解析流量就从明文裸奔变成了加密传输,日常上网的隐私边界向前推进了一大步。