ShadowTLS v3 搭建:检查外层用户与内层密钥

ShadowTLS v3 搭建:检查外层用户与内层密钥

Marcus Reid
2026年10月11日· 7 分钟阅读

ShadowTLS v3 搭建需要两套独立秘密:外层 ShadowTLS 用户密码与内层代理密钥。TLS 握手成功,不能证明任一层已授权实际代理请求。本文限定双端 Ubuntu 24.04 LTS x64、sing-box 1.14.3、v3 strict,以及一种 Shadowsocks 2022 方法。[1][2]

关键要点

  • 服务端使用 v3 users,不用 v2 的顶层 password 字段。
  • 外层用户和内层代理分别生成独立秘密。
  • 握手目标采用自有 TLS 1.3 站点,关闭 wildcard SNI。
  • 内层监听保持私密,检查真实应用转发。
  • 分别检查错误外层密码、错误内层密钥及握手站点故障。

本文依据文末官方来源整理,未完成完整端到端实测。版本只表示文档适用范围,不是作者受测环境。先用自建管理责任与恢复清单确认条件。

ShadowTLS v3 搭建要保护哪些边界?

客户端路径为:应用→本地 SOCKS→Shadowsocks 加密→ShadowTLS 传输→服务端 Shadowsocks→目的地。外层握手使用独立 TLS 站点,其证书名称不自动等于代理服务器地址。可借助协议与传输分层说明区分职责。

只管理获授权主机。SSH 对专用、独立核验的 known_hosts 严格检查,保留控制台恢复能力,并备份现有服务和防火墙策略。未知、变更或撤销的主机密钥均应停止。预留空闲 TCP 8443 给外层、仅回环 TCP 24444 给内层,变更前用 sudo ss -lntup 检查占用。

另需自己管理的独立 HTTPS 站点,支持 TLS 1.3,证书受公众信任并覆盖 handshake.example.com。示例握手站点地址为 203.0.113.20,代理服务器为 203.0.113.10;两者都须换成真实授权地址。使用数字地址避免本例握手目标的额外 DNS 引导;站点续证和可用性仍由你维护。

双层服务增加一项可用性依赖。如果不需要实现层控制,可先比较 VPS 与 VPN 的责任。ShadowTLS 不承诺无法被识别;TLS 指纹识别与凭据有效是不同问题。

步骤 1:安装 sing-box 并核验自有握手站点

从官方 v1.14.3 发行下载 Linux amd64 归档,查看发行、迁移、安全说明和公开验证材料,在私密暂存目录解包。双端程序放到 /opt/sing-box-shadowtls/1.14.3/sing-box,归 root、权限 0755。以完整路径检查版本,不静默替换成开发构建。[1]

从代理服务器所在网络检查自有站点:

openssl s_client -connect 203.0.113.20:443 -servername handshake.example.com -tls1_3 -verify_hostname handshake.example.com -verify_return_error </dev/null

应确认协商 TLS 1.3,并通过证书链和名称校验;连接成功或网页可读还不足够。先修复 TLS 设置、证书、时钟或可达性。v3 strict 的握手前提不构成放宽验证的理由。[3]

创建无登录 shell 的服务账号 shadowtls-proxy,将 /etc/sing-box-shadowtls 设置为 root:shadowtls-proxy、0750。两层防火墙仅对预期客户端放行 TCP 8443,并允许服务器访问握手站点和授权目的地。保留 SSH 与救援入口,不对外开放 TCP 24444。

分别生成两套秘密

在私密管理员终端,用安装好的程序运行:

/opt/sing-box-shadowtls/1.14.3/sing-box generate rand --base64 32
/opt/sing-box-shadowtls/1.14.3/sing-box generate rand --base64 16

第一项结果用作 REPLACE_OUTER_PASSWORD,第二项用作 REPLACE_INNER_KEY。2022-blake3-aes-128-gcm 要求 base64 编码的 16 字节密钥;不能复用外层密码或换成随意口令。私密保存,截图和共享命令历史中不出现真实值。[4]

步骤 2:sing-box ShadowTLS 配置与内层服务

用 sudoedit 创建 /etc/sing-box-shadowtls/server.json,替换示例 IP 和两套秘密。固定 v3 路线使用 users、strict_mode: true 和 wildcard_sni: off,不转发任意 SNI 名称。[2]

{
  "log": {"level": "warn"},
  "dns": {
    "servers": [{"type": "local", "tag": "system-dns"}]
  },
  "inbounds": [
    {
      "type": "shadowtls",
      "tag": "st-in",
      "listen": "0.0.0.0",
      "listen_port": 8443,
      "version": 3,
      "users": [{"name": "trial-user", "password": "REPLACE_OUTER_PASSWORD"}],
      "handshake": {"server": "203.0.113.20", "server_port": 443},
      "strict_mode": true,
      "wildcard_sni": "off",
      "detour": "ss-in"
    },
    {
      "type": "shadowsocks",
      "tag": "ss-in",
      "listen": "127.0.0.1",
      "listen_port": 24444,
      "network": "tcp",
      "method": "2022-blake3-aes-128-gcm",
      "password": "REPLACE_INNER_KEY"
    }
  ],
  "outbounds": [{"type": "direct", "tag": "direct", "domain_resolver": "system-dns"}],
  "route": {"final": "direct"}
}

入站 detour 将认证后的外层流注入指定内层入站,并不是直达公网的出站路由。内层仅回环监听,只启用 TCP。应用目的地名称由服务端本地解析器解析,这不代表相对于该解析器的 DNS 隐私保证。[4][5][6]

配置文件设为 root:shadowtls-proxy、0640,备份保持同样限制。服务账号与客户端均无须替换 root 持有的二进制文件。

步骤 3:让客户端依次经过两层

在 Ubuntu 客户端创建当前用户持有、权限 0700 的目录,保存权限 0600 的 client.json。替换代理 IP 和两套秘密,但保留自有握手站点的证书名称。

{
  "log": {"level": "warn"},
  "inbounds": [{
    "type": "mixed",
    "tag": "local",
    "listen": "127.0.0.1",
    "listen_port": 1082,
    "set_system_proxy": false
  }],
  "outbounds": [
    {
      "type": "shadowsocks",
      "tag": "ss-out",
      "server": "127.0.0.1",
      "server_port": 24444,
      "method": "2022-blake3-aes-128-gcm",
      "password": "REPLACE_INNER_KEY",
      "network": "tcp",
      "detour": "st-out"
    },
    {
      "type": "shadowtls",
      "tag": "st-out",
      "server": "203.0.113.10",
      "server_port": 8443,
      "version": 3,
      "password": "REPLACE_OUTER_PASSWORD",
      "tls": {
        "enabled": true,
        "server_name": "handshake.example.com",
        "min_version": "1.3",
        "insecure": false
      }
    }
  ],
  "route": {"final": "ss-out"}
}

Shadowsocks 出站提供内层加密,其 detour 选择 st-out;固定版本的 ShadowTLS 出站连接自身配置的服务端,忽略上游传入的拨号目的地。因此这里的 127.0.0.1:24444 不意味着客户端要连接本机服务器。不能删掉 detour,也不能将 final 改成 st-out 而跳过内层加密。[7][8]

启动前检查双端配置:

sudo -u shadowtls-proxy /opt/sing-box-shadowtls/1.14.3/sing-box check -c /etc/sing-box-shadowtls/server.json
/opt/sing-box-shadowtls/1.14.3/sing-box check -c ./client.json

均须成功退出。检查能验证配置,不能证明整个转发路径正常。占位符、密钥格式、字段或读取权限错误应直接修正,不绕过验证。

步骤 4:启动独立服务并检查转发

以 root 创建 /etc/systemd/system/sing-box-shadowtls.service:

[Unit]
Description=ShadowTLS v3 and inner Shadowsocks
After=network-online.target
Wants=network-online.target

[Service]
User=shadowtls-proxy
Group=shadowtls-proxy
ExecStart=/opt/sing-box-shadowtls/1.14.3/sing-box run -c /etc/sing-box-shadowtls/server.json
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
UMask=0077

[Install]
WantedBy=multi-user.target

运行 sudo systemctl daemon-reload,再执行 sudo systemctl start sing-box-shadowtls。确认该服务持有 TCP 8443,内层 TCP 24444 仅在回环监听。客户端用固定程序执行 run -c ./client.json,保持前台;确认 mixed 入口仅为 127.0.0.1:1082,本次试验不打开系统代理或 TUN。

通过受控 HTTPS 端点检查已知内容:

curl --fail --show-error --noproxy '' --proxy socks5h://127.0.0.1:1082 https://check.example.net/health

替换为自有授权端点,要求返回预期应用响应,再检查小型受控上传和下载。TLS 握手成功、服务 active 或本地 socket 已连接,都不是完整验收结果。将一个测试浏览器配置到本地 SOCKS,打开IP 地址工具。结果仅涵盖这次请求,不证明所有 DNS、IPv6、UDP 或全部应用都经过该路径。

如何隔离 ShadowTLS 认证失败的位置?

复制私密客户端配置,每次只改变一个条件。先停止旧前台进程,再在同一本地端口启动副本。各负例之间恢复正确文件,并重做正例请求。

检查方法预期行为失败处理
外层密码、内层密钥均正确受控 HTTPS 请求正常转发分开检查本地监听、握手目标、外层认证、内层认证和目的地
仅换成另一个随机外层密码不能获得有效的认证代理请求即使 TLS 握手可能完成,也不证明授权转发
仅换成另一个有效的 16 字节 base64 内层密钥内层代理认证失败不用畸形密钥,否则只是测试解析器
独立试验配置使用不可达握手目标试验转发不能完成恢复目标,不改无关生产网络
独立试验指向自有仅支持 TLS 1.2 的测试站strict v3 路线不能满足 TLS 1.3 条件恢复获准的 TLS 1.3 站点,不削弱客户端校验
只重启该服务,再发新请求授权转发恢复检查权限、目标可用性和启动归属

握手目标故障场景使用可丢弃的独立实例与空闲端口,或明确安排的隔离测试窗口。不要关闭共享网站来制造负例。日志保持受限,分享错误报告前删除凭据、私密地址和目的地元数据。

如何更新、撤销并恢复服务?

升级前私密保存程序、双端配置、单元和握手站点配置。跟进 sing-box 发行与迁移说明,将新版放入另一目录,检查双端文件,重做分层矩阵。握手站点的证书续期同样需要维护:即使代理程序没变,外部依赖到期也会导致故障。

撤销时从服务端移除相应外层用户并验证配置。重启这个专用服务,以载入变化并终止旧连接;同实例其他用户也会中断。验证使用被移除密码的新连接失败。共享内层密钥是另一边界,轮换它须同步所有共享该密钥的授权客户端。退役试验时两套秘密都应作废。

回退恢复兼容的保存配置和本单元程序路径,再做正例与拒绝检查,不能无限期使用有漏洞的版本。彻底停用时恢复应用原代理设置、停止客户端,执行 sudo systemctl disable --now sing-box-shadowtls,仅删除它的 TCP 防火墙规则。确认两个监听均消失。若握手站点仍供其他任务使用,应保持运行;删除代理不授权删除独立站点。

总结

外层用户、内层密钥、握手站点和目的地转发是不同检查项。正确配置只是前提,验收还需要真实转发、拒绝、重启与撤销行为;本文不声称已有端到端部署结果。

常见问题

外层 ShadowTLS 密码等于 Shadowsocks 密钥吗?

不是,应独立生成。这里的 Shadowsocks 2022 方法要求 base64 编码的 16 字节密钥,外层密码则负责 ShadowTLS 认证。

v3 服务端可以直接使用 v2 password 字段吗?

本配置应使用 v3 users 数组。混用不同版本字段会模糊实际认证边界,也使故障定位更困难。

TLS 握手成功能证明双层代理正常吗?

不能。须经完整内外层链路访问受控目的地,再确认错误凭据无法获得同样的有效转发。

为什么选自己管理的握手站点?

自有站点便于维护证书和 TLS 策略、授权流量及安排恢复,不把无关公共网站变成你的运行依赖。

开启 wildcard SNI 能改善这条路线吗?

本路线保持关闭,只使用一个批准的握手目标,不授权任意服务名转发,也不扩展多目标组合。

为什么 Shadowsocks 内层只监听回环?

外层在服务进程内将流注入内层。公开内层监听会额外暴露认证入口,超出本次限定配置范围。

移除外层用户会同时轮换内层密钥吗?

不会,两者独立。移除外层用户并结束会话后,仍须另行轮换共享内层密钥,并更新所有受影响授权客户端。

来源:

  1. sing-box release v1.14.3 — https://github.com/SagerNet/sing-box/releases/tag/v1.14.3
  2. sing-box: ShadowTLS inbound — https://sing-box.sagernet.org/configuration/inbound/shadowtls/
  3. ShadowTLS: v3 protocol — https://github.com/ihciah/shadow-tls/wiki/V3-Protocol
  4. sing-box: Shadowsocks inbound — https://sing-box.sagernet.org/configuration/inbound/shadowsocks/
  5. sing-box: listen fields and inbound detour — https://sing-box.sagernet.org/configuration/shared/listen/
  6. sing-box: dial fields and domain resolver — https://sing-box.sagernet.org/configuration/shared/dial/
  7. sing-box: Shadowsocks outbound — https://sing-box.sagernet.org/configuration/outbound/shadowsocks/
  8. Pinned sing-box ShadowTLS outbound implementation — https://github.com/SagerNet/sing-box/blob/v1.14.3/protocol/shadowtls/outbound.go

Sources checked 2026 年 10 月 11 日。

延伸阅读:

开启 3 天免费试用

注册即可免费体验全部高级功能。

*仅限新用户;每位用户只能获得一次试用。

ShadowTLS v3 搭建:检查外层用户与内层密钥 | AethoVPN