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