前几天看到Caddy支持ECH了,然后部署了一个逝了下,坑有点多,遂记录下整个部署过程。。。
配置过程中的问题:
我一开始看到这个版本发布说明里面写了Caddy实现了全自动的ECH,但是需要一个DNS插件,一般都是用CloudFlare。
默认情况下Caddy是不含这些DNS插件的,需要我们自己用xcaddy编译,但是我当时偷了个懒不想自己编译(嫌麻烦),因为Caddy官网有一个下载页面,可以根据你选择的插件在线帮你编译一个Caddy,我当时就用的这个方式:
后续在配置过程中就发现,如果域名本身存在SRV记录的话,ECH的DNS解析记录配置就会失败:#6975
这问题是上游libdns导致的,目前要彻底解决的话最终还是得自己用xcaddy编译- -因为我当时不想编译就临时换了个没有SRV记录的域名。
使用过程中的问题:
等到我全部配置好了,发现一个奇怪的问题:火狐浏览器正常,谷歌浏览器报TLS错误。。
整他妈半天发现这是因为Go标准库里面的BUG导致的:#6898、#6968、#71642
最终的最终,还是得自己用xcaddy编译一遍,你说这是偷的个什么懒。。
题外话:如果你不急的话,可以再等一等。不出意外的话,下个版本的Caddy应该就没这些问题了。
我还是倾向于使用官方的APT Repo来安装Caddy,因为这样安装后就不用自己去写systemd服务了,后续版本管理也容易:
apt update apt install -y debian-keyring debian-archive-keyring apt-transport-https curl curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list apt update apt install caddy
还需要安装xcaddy:
apt install -y debian-keyring debian-archive-keyring apt-transport-https curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-xcaddy-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-xcaddy.list apt update apt install xcaddy
以及Golang:
wget https://go.dev/dl/go1.24.3.linux-amd64.tar.gz tar -C /usr/local -xzf go1.24.3.linux-amd64.tar.gz echo 'export PATH=$PATH:/usr/local/go/bin' > /etc/profile.d/golang.sh source /etc/profile.d/golang.sh
编译Caddy:
xcaddy build \ --with github.com/caddy-dns/cloudflare \ --with github.com/libdns/libdns@master
将编译好的二进制文件移动并重命名为caddy.custom:
mv ./caddy /usr/bin/caddy.custom
依次执行下面的命令,将自编译的版本替换掉APT Repo里面的版本:
dpkg-divert --divert /usr/bin/caddy.default --rename /usr/bin/caddy update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.default 10 update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.custom 50 systemctl restart caddy
执行下面的命令检查CloudFlare DNS插件是否启用:
caddy list-modules
正常的话会有类似显示:
dns.providers.cloudflare Non-standard modules: 1
现在可以开始配置ECH了,编辑Caddy的配置文件:
nano /etc/caddy/Caddyfile
写入如下内容:
{ dns cloudflare {env.CLOUDFLARE_API_KEY} ech ech.example.net } ech-test.example.com { respond "ECH Test!" } doh.example.com { log { output file /var/log/caddy/doh.example.com.access.log format console } reverse_proxy /dns-query* https://dns.google { header_up Host dns.google header_up X-Real-IP {remote_host} header_up X-Forwarded-For {remote_host} header_up X-Forwarded-Proto {scheme} } }
注:
这里额外配置了一个DoH服务,因为ECH不但要服务端支持,客户端也需要支持才行,目前主流的浏览器:火狐、谷歌都是需要配置一个安全DNS服务器才会启用ECH支持,又因为国内现在把很多DoH服务器都屏蔽了,所以这里简单的用反向代理临时弄了个DoH服务。这不是必须的,如果你可以使用其他DoH服务的话可以省略这段配置。
将{env.CLOUDFLARE_API_KEY}修改为你的CloudFlare API KEY。
ech.example.net、ech-test.example.com两个域名均添加DNS A记录指向这台Caddy所在的服务器IP。
其实可以用“外部”、“内部”来简单解释一下。ech.example.net=外部,ech-test.example.com=内部。
ech.example.net是外部看到的SNI,ech-test.example.com是实际要访问的SNI。
配置完成后重载Caddy使新的配置生效:
systemctl reload caddy
如果正常的话,应该能在CloudFlare的DNS记录界面看到一条新的https记录(我这里是两条记录,因为我额外配置的DoH服务在同一个域名):
到这里服务端的配置就全部完成了。接下来是客户端的配置。客户端这边只需要修改浏览器配置让其使用DoH服务即可。
火狐:
谷歌:
谷歌浏览器一定要勾选“一律使用安全连接”,不然会出现有时支持ECH有时候又不支持的问题。。
配置完成后可以访问:https://tls-ech.dev/,进行检查。
最后用Wireshark抓包看看配置是否正常,在Wireshark内新建一个显示过滤器:
tls.handshake.extensions_server_name
当我用浏览器访问ech-test.example.com时,SNI应该是ech.example.net: