改了 REALITY 的 target,代理当场就断了
2026-10-08 · 9 分钟阅读
我想让代理和网页共用 443:正常浏览器访问看到博客,代理客户端照常翻墙。做法是把 REALITY 入站的 target 从 www.samsung.com:443 改成 127.0.0.1:9443(本地 caddy 上的网页)。
配置改完、服务重启,网页正常打开——但代理直接死了。
现象
客户端能连上(服务端日志显示 accepted),但流量出不去。curl 走代理全是 HTTP 000,超时约 2 秒。
奇怪的是:网页本身完全正常,说明 443 端口、caddy、证书都没问题。
排查过程
先确认改动范围——对比改前改后的完整配置,只差一行:
- "target": "www.samsung.com:443",
+ "target": "127.0.0.1:9443",
其他字段(serverNames、privateKey、shortIds、客户端 flow)一字未动。所以不是配置写坏了。
那就得想清楚 REALITY 到底拿 target 干什么。查文档才发现关键点:target 不只是回落目标,它同时是 REALITY 校验客户端时的握手依据。
也就是说,服务端需要能对 target 那个地址完成一次合法的 TLS 握手,用它来参与判定。
现在 target 指向了 caddy,但 serverNames 还写着 www.samsung.com。caddy 根本没有 samsung 这个站点——它收到这个 SNI 会怎么响应?直接测:
$ echo | openssl s_client -connect 127.0.0.1:9443 -servername www.samsung.com
...
tlsv1 alert internal error
no peer certificate available
SSL alert number 80
caddy 拒绝了握手。 根因就在这里——REALITY 的校验链断了。
修复
原则很简单:target 和 serverNames 必须指向同一个站点。
既然回落目标换成了自己的网页,SNI 也得换成自己的域名:
{
"streamSettings": {
"security": "reality",
"realitySettings": {
"target": "127.0.0.1:9443",
"serverNames": ["hy2hk.503300013.xyz"]
}
}
}
重启后立刻验证:
$ curl -s -o /dev/null -w '%{http_code}' --socks5 127.0.0.1:10889 https://www.google.com/
200
$ curl -s --socks5 127.0.0.1:10889 https://api.ipify.org
141.11.76.7
代理恢复。
连带影响
客户端那边的 servername 也得同步改,否则一样连不上:
# mihomo 节点配置
servername: hy2hk.503300013.xyz # 原来是 www.samsung.com
这个容易漏——服务端改完测通了,但客户端还拿着旧 SNI,用户那边依然不通。
伪装还有效吗
有人会担心:SNI 换成自己的域名,是不是就不像"伪装"了?
实际上 REALITY 区分代理流量和浏览器流量靠的是握手密钥材料,不是 SNI。所以:
- 持正确密钥的客户端 → 走代理
- 用正确 SNI 但没密钥的访问 → 落到你的网页,看到一个正常的 HTTPS 站点
- 证书是真的(Let's Encrypt),浏览器不会有任何警告
外人看到的就是一个普通的技术博客,看不出背后有代理。
教训
target 时,serverNames 必须一起改,客户端也要同步。三者是绑定的:服务端 target、服务端 serverNames、客户端 servername —— 指向同一个域名,缺一不可。
更一般的经验:REALITY 的配置项之间是有耦合的,不能当独立参数单独调。 改之前先想清楚每个字段在握手流程里扮演什么角色。