Debian 服务器 sing-box 代理踩坑实录:VLESS 被精准封杀之后
前言
手上有一台海外 VPS,上面跑了 sing-box 服务端,配了双协议:VLESS + Reality 走 TCP 443,Hysteria2 走 UDP 8443。目标很简单 —— 给内网一台 Debian 13 VM 装上 sing-box 客户端,连到这台 VPS 做透明代理,解决 GitHub、Docker Hub 之类海外资源拉不动的问题。
结果比想象中折腾得多。VLESS Reality 在 GFW 面前完全没扛住,TCP 握手能过,ClientHello 一发出去就被 RST。最后还是靠 Hysteria2 的 UDP 通道才跑通。
这篇文章把整个过程和踩过的坑都记下来,省得下次再踩一遍。
安装 sing-box
VM 本身访问不了 GitHub,所以官方的一键脚本直接报废。绕路方案是用 GitHub 镜像站拼 deb 包的直链下载。
# 逐个版本试,镜像不稳定,哪个能下用哪个for ver in 1.11.7 1.11.6 1.11.5; do curl -fsSL -o /tmp/sing-box.deb \ "https://ghfast.top/https://github.com/SagerNet/sing-box/releases/download/v${ver}/sing-box_${ver}_linux_amd64.deb" [ $? -eq 0 ] && breakdone
dpkg -i /tmp/sing-box.deb这里有两个细节值得说一下。镜像站本身就不稳定,版本号是逐个试出来的,不能直接写死最新版。如果装 1.12+,配置文件的字段名有 breaking changes(比如 inet4_address 改成了 address 数组),直接用服务端的配置模板会报错。
客户端配置
从服务端私钥推导 Reality 公钥
服务端的 Reality 配置里只有 private_key,但客户端需要 public_key 来完成 TLS 握手。X25519 的私钥和公钥是一一对应的,用 Python 几行就能推出来。
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKeyimport base64
private_key_b64 = "<YOUR_PRIVATE_KEY>"private_bytes = base64.b64decode(private_key_b64 + "==")private_key = X25519PrivateKey.from_private_bytes(private_bytes)public_key = private_key.public_key()pub_b64 = base64.urlsafe_b64encode( public_key.public_bytes_raw()).decode().rstrip("=")这里踩了一个编码坑。sing-box 用的是 URL-safe base64,- 和 _ 分别替代 + 和 /,而且不带 = 补齐。用标准 base64 编码带 / 字符的话,sing-box 会报 illegal base64 data at input byte 24。正确的公钥是类似 mIXry4FE5HzXqBhBxpp9uBDc_RdCSbmDmJk8O6Uzh1Y 这种格式。
VLESS Reality:翻车实录
VLESS Reality 的客户端配置看起来没什么问题:
{ "outbounds": [{ "type": "vless", "tag": "proxy", "server": "<YOUR_VPS_IP>", "server_port": 443, "uuid": "<YOUR_UUID>", "flow": "xtls-rprx-vision", "tls": { "enabled": true, "server_name": "www.microsoft.com", "utls": {"enabled": true, "fingerprint": "chrome"}, "reality": { "enabled": true, "public_key": "<YOUR_PUBLIC_KEY>",5 collapsed lines
"short_id": "<YOUR_SHORT_ID>" } } }]}TCP 三次握手能完成 ——nc -zv 测 443 端口显示 open。但 sing-box 在 TLS ClientHello 发出去之后 1-2 毫秒就收到了 RST:
ERROR connection: open outbound connection: read tcp 192.168.3.216:33642-><VPS_IP>:443: read: connection reset by peer用 openssl s_client 裸测也一样 ——ClientHello 发出后服务端 0 字节回应,连接直接被 reset。
换 Hysteria2:通了
Hysteria2 基于 QUIC / UDP,GFW 对 UDP 的检测能力远弱于 TCP,而且 Hysteria2 本身对协议指纹的隐藏做得更好。
{ "outbounds": [{ "type": "hysteria2", "tag": "proxy", "server": "<YOUR_VPS_IP>", "server_port": 8443, "password": "<YOUR_PASSWORD>", "tls": { "enabled": true, "server_name": "localhost", "insecure": true } }]}测试结果:
=== Google ===HTTP 200 (1.325s)=== GitHub ===HTTP 200 (0.855s)=== IP check ==={"origin": "<YOUR_VPS_IP>"}出口 IP 确认是 VPS 的 IP,代理正常工作。
最终配置
sing-box 客户端配置
{ "log": {"level": "info", "timestamp": true}, "inbounds": [ { "type": "mixed", "tag": "mixed-in", "listen": "127.0.0.1", "listen_port": 2080 } ], "outbounds": [ { "type": "hysteria2", "tag": "proxy", "server": "<YOUR_VPS_IP>",16 collapsed lines
"server_port": 8443, "password": "<YOUR_PASSWORD>", "tls": { "enabled": true, "server_name": "localhost", "insecure": true } }, {"type": "direct", "tag": "direct"} ], "route": { "auto_detect_interface": true, "rules": [{"ip_is_private": true, "outbound": "direct"}], "final": "proxy" }}几个关键设计决策:
- 只用了
mixedinbound(HTTP + SOCKS5),没有开 TUN 模式。在服务器环境(尤其有 Docker 网桥的时候),TUN 的auto_route+strict_route会劫持全部路由,而代理链路本身也走默认路由,形成死循环导致整机断网。这个坑在 PVE 虚拟化环境里尤其容易触发。 - 内网 IP 走直连(
ip_is_private),其余全部走代理出口。 - 域名类规则(
geosite:cn之类的)因为没下载 geoip.db 就没加,如果后续需要可以手动补上。
系统环境变量
写入 /etc/environment,让系统级别的工具(apt、curl 等)自动走代理:
http_proxy=http://127.0.0.1:2080https_proxy=http://127.0.0.1:2080no_proxy=localhost,127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,.cn,.localno_proxy 里把内网网段和 .cn 域名都排除了,避免国内访问绕路。
Docker 守护进程代理
Docker 拉镜像不走系统环境变量,得单独给 Docker daemon 配。创建 /etc/systemd/system/docker.service.d/http-proxy.conf:
[Service]Environment="HTTP_PROXY=http://127.0.0.1:2080"Environment="HTTPS_PROXY=http://127.0.0.1:2080"Environment="NO_PROXY=localhost,127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,.cn,.local"然后 systemctl daemon-reload && systemctl restart docker 生效。
后续:Hysteria2 突然断连的排查
代理跑了两天之后突然挂了。Hermes Gateway 疯狂报 API 超时,curl 走代理也全部 timeout。下面是把整个排查过程拆开讲。
现象
curl -x http://127.0.0.1:2080 http://ip.sb 直接卡死,sing-box 日志反复报:
ERROR: open outbound connection: http3: parsing frame failed: timeout: no recent network activity看起来像是 VPS 没响应,第一反应是 GFW 又开始搞 UDP 了。
排查过程
第一步:确认 VPS 是不是挂了。 SSH 到 VPS,systemctl status sing-box 显示 running,ss -ulnp | grep 8443 端口在监听,证书也没过期。而且 VPS 日志里能看到它成功接收了来自 VM 公网 IP 的 Hysteria2 连接,说明 UDP 包确实能到达 VPS。
第二步:怀疑 ISP 丢 UDP。 用 conntrack 看了 VM 的连接跟踪表,UDP NAT 映射状态是 ESTAB + ASSURED,看起来一切正常。但错误持续出现,不是偶发丢包 —— 是完全不通。
第三步:发现版本差了两代。 VPS 装的 1.13.11,VM 装的是 1.11.7。Go 版本也不一样(1.25 vs 1.24),QUIC 库实现有差异。1.11 和 1.13 之间 QUIC 协议参数可能已经不兼容了 —— 握手能过,但 HTTP / 3 帧解析阶段客户端和服务端对不上。
升级客户端
VM 没有互联网,不能直接从 GitHub 下。绕路方案:Mac 下载 → scp 到 VM → dpkg 安装。
# 在能上网的机器上下载(Mac / VPS 都行)curl -fsSL -o /tmp/sing-box.deb \ "https://github.com/SagerNet/sing-box/releases/download/v1.13.11/sing-box_1.13.11_linux_amd64.deb"
# scp 到 VMscp /tmp/sing-box.deb root@192.168.3.216:/tmp/
# 在 VM 上执行DEBIAN_FRONTEND=noninteractive dpkg -i --force-confold /tmp/sing-box.debsystemctl daemon-reloadsystemctl restart sing-box--force-confold 保留现有配置文件,避免 dpkg 问是否覆盖。
升级后版本对齐,curl -x http://127.0.0.1:2080 http://ip.sb 立刻返回 VPS IP。Hermes Gateway 的 Telegram 和飞书也瞬间连上了。
踩坑总结
| 坑 | 现象 | 解决 |
|---|---|---|
| GitHub 被墙 | 官方 deb 下不了 | 用镜像站拼直链逐个版本试 |
| GeoIP 自动下载 | sing-box 启动时尝试下载 geoip.db,被阻断后 FATAL | 不用 geoip 规则,或设 ENABLE_DEPRECATED_GEOIP=true |
| Reality 公钥编码 | illegal base64 data at input byte 24 | sing-box 用 URL-safe base64,无 padding |
| VLESS TCP 被 RST | ClientHello 后 1-2ms connection reset | GFW 深度包检测精准识别,放弃 TCP 走 UDP |
| TUN 模式断网 | 整台服务器失联 | 服务器环境不要用 TUN,用 HTTP / SOCKS5 proxy |
| sing-box 版本差异 | inet4_address deprecated | 1.12+ 改用 address 数组格式 |
| 客户端版本不匹配 | Hysteria2 突然断连,http3: parsing frame failed: timeout | 升级到与服务端一致(1.13.11),排查时先看版本再看 GFW |
给 PVE 宿主机的备忘
如果以后要给 PVE 宿主机(也是 Debian)装代理:
- 同一套流程:装 sing-box → 写 Hysteria2 客户端配置 → 启动
- PVE 宿主机同样不要开 TUN,用 mixed inbound
- 更简单的做法:直接让 PVE 走这台 VM 的代理,
export https_proxy=http://192.168.3.216:2080,不用额外装 sing-box
最后说一句,GFW 的升级速度比很多人想象的快。VLESS Reality 在 2024 年还能用,到 2025 年 TCP 层面的检测已经能做到毫秒级 RST 注入了。UDP 协议(Hysteria2、TUIC 等)目前还算可用,但谁也说不准能撑多久。有条件的还是备几个不同协议的方案,别把鸡蛋放一个篮子里。