−25%

Windows 年繳方案適用,至 10 月 31 日。 檢視方案

EQVPS
開始使用

WebRTC TURN 伺服器(coturn)VPS

在嚴格 NAT 後面失敗的通話需要 TURN 中繼。在有獨立 IPv4 的伺服器上執行 coturn:連接埠、有時效的憑證、經過實測的設定與合適的方案。

你的 WebRTC 應用程式在自己的 Wi-Fi 下正常,偏偏在那位從飯店打來的客戶那裡失敗。點對點媒體需要雙方之間有一條路徑;當雙方都在嚴格 NAT 之後,或者防火牆丟棄 UDP,就沒有路徑,通話根本連不上。誰也看不到錯誤訊息——只有一個沒完沒了的「連線中…」。

TURN 伺服器就是這類通話的備援方案:雙方把媒體串流送給它,由它轉送。如果你在應用程式裡加入視訊或語音、為團隊運行 Matrix 或 Jitsi,或者幫遊戲做語音聊天,你就需要一台。coturn 是標準的開源實作,而且很輕巧。

選哪個方案

TURN 對 CPU 和記憶體的消耗很小。它消耗的是頻寬:每條中繼串流進出各經過伺服器一次,共兩次。我們方案的流量在 1 Gbit/s 下不限量,所以問題在於同時有多少通話在中繼,而不是要付多少錢。

同時中繼的通話數方案
幾通——一個團隊、一個小應用程式Nano-IP:2 vCPU、1 GB、15 GB(每月 $8)
幾十通Micro-IP:2 vCPU、2 GB、25 GB(每月 $10)
更多,或把 TURN 放在應用程式伺服器旁邊Small-IP:4 vCPU、4 GB、35 GB(每月 $16)

必須是有獨立 IPv4 的方案——TURN 的核心就是大量連接埠上的入站連線,而 NAT 方案從外部只接受 SSH。在我們的獨立 IP 方案上,公用位址直接設定在伺服器的網路介面上,所以 coturn 不需要 external-ip 這一行就能找到它。把伺服器放在離使用者近的地方:伺服器位於歐盟,共有兩個地點,下單時可看到哪裡有空位。如果你在意,可以用加密貨幣付款,無需 KYC。

需要開放的連接埠:UDP 和 TCP 3478,中繼媒體用的 UDP 49152–65535,如果加 TLS 再開 TCP 5349。

安裝與設定

在 Ubuntu 24.04 或 Debian 12 上以 root 身分執行:

apt install -y coturn
ip -4 addr    # 網卡上應該看得到你的公用 IP

用一組新的共享密鑰寫入設定:

SECRET=$(openssl rand -hex 32)
cat > /etc/turnserver.conf <<EOF
listening-port=3478
fingerprint
use-auth-secret
static-auth-secret=$SECRET
realm=turn.example.com
min-port=49152
max-port=65535
no-cli
no-multicast-peers
denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=100.64.0.0-100.127.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=169.254.0.0-169.254.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.168.0.0-192.168.255.255
EOF
echo "$SECRET"    # 後端需要這個值
systemctl restart coturn
ufw allow 22/tcp && ufw allow 3478 && ufw allow 49152:65535/udp && ufw enable

別省略 denied-peer-ip 這幾行。少了它們,任何持有有效憑證的人都能藉你的中繼存取私有位址——包括伺服器自身內部一側的服務。我們驗證過:有了這些行,往私有位址的中繼會被以「403 Forbidden IP」拒絕。

會過期的憑證

使用 use-auth-secret 時,coturn 接受包含到期時間的使用者名稱,以及作為該名稱 HMAC 的密碼。它們由你的後端產生;密鑰從不離開伺服器端。用 Node.js:

const crypto = require("crypto");

// 臨時 TURN 使用者名稱/密碼(coturn 透過 use-auth-secret 支援的 TURN REST API 方案)
function turnCredentials(secret, user, ttlSeconds = 3600) {
  const username = `${Math.floor(Date.now() / 1000) + ttlSeconds}:${user}`;
  const credential = crypto.createHmac("sha1", secret).update(username).digest("base64");
  return { username, credential };
}

console.log(JSON.stringify(turnCredentials(process.env.TURN_SECRET, "alice")));

在瀏覽器裡向後端要一組新憑證,交給 RTCPeerConnection:

const { username, credential } = await fetch("/api/turn-credentials").then((r) => r.json());

const pc = new RTCPeerConnection({
  iceServers: [
    { urls: "stun:turn.example.com:3478" },
    {
      urls: ["turn:turn.example.com:3478?transport=udp", "turn:turn.example.com:3478?transport=tcp"],
      username,
      credential,
    },
  ],
});

測試

在伺服器上,用 openssl 依同樣的方案產生(得到的密碼與 Node.js 程式碼完全一致——我們比對過):

U="$(( $(date +%s) + 3600 )):test"
P=$(echo -n "$U" | openssl dgst -binary -sha1 -hmac "$SECRET" | base64)
turnutils_uclient -y -n 10 -u "$U" -w "$P" YOUR_SERVER_IP

最後你希望看到「Total lost packets 0」。密碼錯誤時,用戶端會停在「Cannot complete Allocation」——這表示伺服器在正常工作。

我們也用真正的 Chromium 驗證過:設定 iceTransportPolicy: "relay" 並使用新憑證時,瀏覽器從伺服器拿到了 relay 候選;密碼錯誤時一個都沒有。想用同樣方法測試你的設定,可以暫時打開這個選項——它會強制所有通話走 TURN。

需要時再加 TLS

有些網路會封鎖 UDP,對一般 TCP 也很挑剔;以 TLS 承載的 TURN 能穿過其中更多網路。為 turn.example.com 申請憑證(certbot 就行)。憑證檔案只有 root 能讀,而 coturn 以 turnserver 使用者身分執行,所以要給 coturn 一份它自己的副本:

mkdir -p /etc/coturn
cp /etc/letsencrypt/live/turn.example.com/fullchain.pem /etc/letsencrypt/live/turn.example.com/privkey.pem /etc/coturn/
chown turnserver: /etc/coturn/*.pem && chmod 640 /etc/coturn/privkey.pem
cat >> /etc/turnserver.conf <<'EOF'
tls-listening-port=5349
cert=/etc/coturn/fullchain.pem
pkey=/etc/coturn/privkey.pem
EOF
systemctl restart coturn && ufw allow 5349/tcp

在 urls 清單中加入 turns:turn.example.com:5349?transport=tcp。憑證效期很短,所以請把複製步驟放進 certbot 的 deploy hook——否則 TLS 會在第一次續期時悄悄失效。

值得知道

  • TURN 不會把糟糕的連線變好。它多加了一跳,所以要把伺服器放在需要它的人附近。
  • 如果你運行 SFU——例如 Jitsi 的 videobridge——那是另一個元件。TURN 幫助的是無法直接連到它的用戶端。
  • 整個安全模型就是那組密鑰。不要放進前端,一旦外洩就立刻更換。

相關內容

準備好部署了嗎?以加密貨幣付款,免 KYC——大約一分鐘上線。

立即部署 →

常見問題

WebRTC 通話為什麼需要 TURN 伺服器?

WebRTC 會嘗試直接連接通話雙方,通常都能成功。當雙方都位於對稱型 NAT 或會丟棄 UDP 的防火牆之後——飯店 Wi-Fi、辦公網路、部分行動電信業者——就沒有直連路徑,通話會無聲無息地失敗。TURN 伺服器正是為這些通話中繼媒體串流;常被引用的比例大約是十通裡有一通。

TURN 能跑在 NAT 方案上嗎?

不能。用戶端要連到 UDP 和 TCP 3478 以及中繼連接埠範圍,而 NAT 方案從外部只接受你的 SSH 連接埠。你需要有獨立 IPv4 的方案。

它用多少頻寬?

每條中繼串流都會經過伺服器兩次——從一方進來,再出去到另一方。每個方向 1–2 Mbit/s 的一對一視訊通話,在伺服器上就是幾 Mbit/s。CPU 和記憶體幾乎感覺不到;真正的上限是 1 Gbit/s 連接埠。

為什麼不直接在應用程式裡寫死使用者名稱和密碼?

因為瀏覽器 JavaScript 裡的一切都是公開的,而密碼已知的 TURN 伺服器就是給整個網際網路用的免費中繼。使用 use-auth-secret,你的後端會發放會過期的憑證,用瀏覽器永遠看不到的密鑰簽署。

5349 連接埠需要 TLS 嗎?

在封鎖 UDP、又對一般 TCP 很嚴格的網路裡有幫助。等一般 TURN 運作正常後再加:給 coturn 一張 TURN 主機名稱的憑證,並開放 5349/tcp。我們也測試過透過 TLS 的中繼。

評論

目前還沒有評論。歡迎成為第一位。

發表評論

評論在顯示前會經過審核。