14、STUN/TURN服务器:STUN的作用、TURN的作用、搭建Coturn服务器、配置STUN/TURN地址

WebRTC 的 P2P 连接,说白了就是两个浏览器之间直接传数据。但现实世界没这么理想——你家电脑在路由器后面,对方也在路由器后面,两边都不知道对方的真实地址。这时候就需要 STUN 和 TURN 来帮忙了。

我最早接触这块时,觉得 STUN 和 TURN 不就是个地址翻译嘛,有啥难的?结果真到项目里,踩了不少坑。今天咱们就把这两个东西彻底讲清楚。

STUN 的作用:帮你找到自己的门牌号

STUN 的全称是 Session Traversal Utilities for NAT,翻译过来就是「NAT 会话穿越工具」。它的核心任务只有一个:告诉你的浏览器,你的公网 IP 和端口是什么

你想想看,你的电脑在局域网里,IP 是 192.168.1.x 这种私有地址。当你要跟另一个浏览器通信时,你得告诉对方「我在哪」。但对方要的是公网地址,不是你的内网地址。STUN 服务器就是干这个的——你发个请求过去,它看看你的源 IP 和端口,然后原封不动地返回给你。

STUN 的核心能力:

  • 获取公网 IP 和端口映射
  • 检测 NAT 类型(锥形、对称型等)
  • 判断是否可以直接 P2P 连接

我在项目中遇到过一种情况:用户在公司内网,网络环境极其复杂。STUN 返回了公网地址,但对方就是连不上。后来发现是公司的防火墙做了端口限制。嗯,这里要注意——STUN 只负责告诉你地址,不保证能连通

TURN 的作用:最后的保底方案

当 STUN 搞不定时,TURN 就上场了。TURN 的全称是 Traversal Using Relays around NAT,说白了就是「中继转发」。它不尝试穿透 NAT,而是直接让所有数据都经过服务器中转。

你可能会问:那为什么不直接用 TURN?因为成本高啊。TURN 服务器要承担所有媒体流的带宽,视频通话一小时可能跑掉几个 G 的流量。所以我们的策略是:优先用 STUN 尝试 P2P,实在不行才 fallback 到 TURN

什么时候必须用 TURN?

  • 对称型 NAT(最常见的企业网络)
  • 防火墙阻止 UDP 通信
  • 两端都在严格的 NAT 后面
  • 移动网络(4G/5G)下的某些场景

我曾经在一个视频会议项目里,发现 30% 的用户都 fallback 到了 TURN。一开始以为是 STUN 配置有问题,排查了半天才发现是用户的运营商做了端口限制。从那以后,我建议每个项目都预留足够的 TURN 带宽。

STUN 和 TURN 的工作流程

下面这张图展示了 WebRTC 建立连接时的完整流程:

WebRTC 连接建立流程(STUN/TURN 角色) 浏览器 A 浏览器 B STUN 服务器 TURN 服务器 信令服务器 ① 查询公网地址 ② 返回地址 ① 查询公网地址 ② 返回地址 ③ 交换 SDP/Candidate ④ P2P 失败,走 TURN ⑤ 媒体流经 TURN 中继 STUN 路径 TURN 路径(失败时) 信令路径

流程其实不复杂:先通过 STUN 拿到自己的公网地址,然后通过信令服务器交换给对端。如果 P2P 连不上,就退而求其次走 TURN 中继。

搭建 Coturn 服务器

Coturn 是目前最流行的开源 STUN/TURN 服务器。我个人的习惯是用 Docker 部署,省心又干净。下面给出两种方式:

方式一:Docker 部署(推荐)

# 拉取镜像
docker pull coturn/coturn

# 运行容器(简单模式)
docker run -d --network=host \
  --name=coturn \
  coturn/coturn \
  -n --log-file=stdout \
  --listening-port=3478 \
  --min-port=49152 --max-port=65535 \
  --realm=example.com \
  --user=webrtc:password123

参数说明:

  • --network=host:使用宿主机网络,避免端口映射问题
  • --listening-port:STUN/TURN 监听端口,默认 3478
  • --min-port / --max-port:TURN 中继使用的端口范围
  • --user:用户名:密码,多个用户用逗号分隔

方式二:源码编译安装

# 安装依赖
sudo apt-get install libssl-dev libevent-dev libsqlite3-dev

# 下载源码
wget https://github.com/coturn/coturn/archive/refs/tags/4.6.2.tar.gz
tar -xzf 4.6.2.tar.gz
cd coturn-4.6.2

# 编译安装
./configure
make
sudo make install

# 启动服务
turnserver -c /usr/local/etc/turnserver.conf

我曾经在生产环境用过源码编译,后来发现升级维护太麻烦。现在一律用 Docker,配置改起来也方便。

配置 STUN/TURN 地址

服务器搭好了,怎么在 WebRTC 里用?关键在 RTCPeerConnection 的配置里:

const pcConfig = {
  iceServers: [
    {
      urls: 'stun:stun.example.com:3478'
    },
    {
      urls: 'turn:turn.example.com:3478',
      username: 'webrtc',
      credential: 'password123'
    }
  ]
};

const pc = new RTCPeerConnection(pcConfig);

重要提醒:

  • STUN 不需要认证,TURN 必须要有用户名和密码
  • 生产环境不要硬编码密码,建议通过信令服务器动态下发
  • 可以配置多个 STUN/TURN 地址,WebRTC 会自动选择最优的
  • TURN 的端口范围要开放,否则中继会失败

这里有个坑:很多人只配了 STUN,没配 TURN。结果在复杂网络下连接失败,还以为是代码问题。我建议永远同时配置 STUN 和 TURN,哪怕 TURN 只用做 fallback。

验证配置是否生效

配置完了怎么知道好不好使?打开浏览器的开发者工具,看 chrome://webrtc-internals

字段 说明 正常值
candidateType 候选者类型 host / srflx / relay
relayProtocol 中继协议 udp / tcp / tls
localCandidate 本地候选者 内网 IP 或公网 IP
remoteCandidate 远端候选者 对端的 IP 和端口

如果看到 relay 类型的 candidate,说明 TURN 生效了。如果只有 hostsrflx,说明走的是 P2P 或 STUN。

一句话总结:

STUN 帮你找到路,TURN 帮你铺条路。能走 STUN 就走 STUN,走不通再走 TURN。搭建 Coturn 用 Docker 最省事,配置时记得 STUN 和 TURN 一起配。

嗯,STUN/TURN 这块就讲这么多。实际项目中,你可能会遇到各种网络环境,但核心逻辑不变——理解 NAT 穿透的原理,比死记硬背配置参数重要得多。


公众号:蓝海资料掘金营,微信 deep3321