6、STUN/TURN服务器部署:Coturn搭建、中继模式配置、安全认证、负载均衡策略
说实话,WebRTC 最难搞的部分,往往不是音视频编解码,而是网络穿透。你想想看,两个用户在不同的内网里,怎么找到对方?这就是 STUN/TURN 要解决的问题。我最早接触这个坑,是在一个跨国视频会议项目里,用户死活连不上,最后发现是 TURN 服务器没配好。嗯,今天我们就来彻底搞定它。
6.1 为什么需要 STUN/TURN?
先简单说下原理。WebRTC 默认会用 ICE 框架来尝试建立 P2P 连接。ICE 会先尝试直连,不行就通过 STUN 打洞,再不行就只能走 TURN 中继了。
- STUN:帮客户端发现自己的公网 IP 和端口。说白了就是「照镜子」。
- TURN:当 P2P 走不通时,充当中间人转发数据。说白了就是「传话的」。
我个人习惯把 TURN 当作最后的保底方案。毕竟中继要消耗服务器带宽,成本不低。但有些场景,比如对称 NAT 或者防火墙严格的网络,不用 TURN 还真不行。
6.2 Coturn 是什么?
Coturn 是目前最主流的开源 STUN/TURN 服务器实现。它支持完整的 RFC 标准,性能稳定,配置灵活。我几乎所有的项目都用它,没出过什么大问题。
它的核心功能包括:
- 同时支持 STUN 和 TURN 协议
- 支持 UDP、TCP、TLS 传输
- 内置用户认证机制
- 支持多线程和负载均衡
- 提供详细的日志和统计
6.3 搭建 Coturn 服务器
搭建过程其实不复杂。我以 Ubuntu 20.04 为例,带大家走一遍。
6.3.1 安装 Coturn
# 更新包管理器
sudo apt update
# 安装 Coturn
sudo apt install coturn -y
# 检查安装是否成功
turnserver --version
安装完成后,默认配置文件在 /etc/turnserver.conf。我个人习惯先备份一份原始配置:
sudo cp /etc/turnserver.conf /etc/turnserver.conf.bak
6.3.2 基础配置
打开配置文件,修改以下几个关键参数:
# 监听的端口,默认是 3478
listening-port=3478
# TLS 监听端口,默认是 5349
tls-listening-port=5349
# 内网 IP 地址(根据实际情况修改)
listening-ip=0.0.0.0
# 公网 IP 地址(必须填写)
relay-ip=你的公网IP
# 外部 IP 映射(如果服务器在 NAT 后面)
external-ip=你的公网IP/内网IP
# 允许的最大中继会话数
max-bps=1000000
# 日志文件路径
log-file=/var/log/turnserver.log
# 是否开启详细日志
verbose
relay-ip,结果客户端虽然能连上 TURN 服务器,但数据就是转发不出去。排查了半天才发现是 IP 没绑定对。所以这个参数一定要填对。
6.3.3 启动服务
# 启动 Coturn
sudo systemctl start coturn
# 设置开机自启
sudo systemctl enable coturn
# 查看运行状态
sudo systemctl status coturn
如果一切正常,你应该能看到 active (running) 的状态。
6.4 中继模式配置
Coturn 支持多种中继模式。我常用的有三种:
| 模式 | 说明 | 适用场景 |
|---|---|---|
| UDP 中继 | 默认模式,性能最好 | 大多数实时音视频场景 |
| TCP 中继 | 通过 TCP 转发,更稳定 | 网络丢包严重或防火墙限制 UDP |
| TLS 中继 | 加密传输,安全性最高 | 对安全要求极高的场景 |
配置中继模式很简单,在 turnserver.conf 里加上对应的参数即可:
# 启用 UDP 中继(默认开启)
# 不需要额外配置
# 启用 TCP 中继
relay-tcp
# 启用 TLS 中继(需要证书)
cert=/etc/ssl/certs/turnserver.pem
pkey=/etc/ssl/private/turnserver.key
6.5 安全认证
安全认证这块,我吃过不少亏。早期有个项目没加认证,结果 TURN 服务器被恶意用户拿来当代理,流量跑了几百 GB,月底账单吓死人。所以,认证一定要配。
6.5.1 静态认证(简单但不够安全)
# 在配置文件中设置共享密钥
static-auth-secret=你的密钥
# 客户端连接时需要提供用户名和密码
# 用户名格式:timestamp:username
# 密码计算:base64(hmac-sha1(secret, username))
这种方式适合测试环境。生产环境我不推荐,因为密钥是固定的,一旦泄露就很麻烦。
6.5.2 动态认证(推荐)
动态认证需要配合一个认证服务。客户端先向你的后端服务请求一个临时凭证,然后拿着凭证去连 TURN 服务器。
配置方式:
# 使用外部认证服务
use-auth-server
# 认证服务的地址
auth-server=你的后端服务地址:端口
# 认证服务的共享密钥
auth-server-secret=你的密钥
后端服务生成凭证的示例代码(Node.js):
const crypto = require('crypto');
function generateTurnCredentials(username, secret) {
const timestamp = Math.floor(Date.now() / 1000) + 24 * 3600; // 24小时有效
const user = `${timestamp}:${username}`;
const hmac = crypto.createHmac('sha1', secret);
hmac.update(user);
const password = hmac.digest('base64');
return { username: user, password: password };
}
6.6 负载均衡策略
当用户量上来后,单台 TURN 服务器肯定扛不住。这时候就需要做负载均衡。我常用的方案有两种:
6.6.1 DNS 轮询
最简单的方式。配置多个 TURN 服务器的域名解析到同一个域名,DNS 会自动分配请求。
# 在 DNS 管理后台添加多条 A 记录
turn.example.com A 192.168.1.10
turn.example.com A 192.168.1.11
turn.example.com A 192.168.1.12
优点:配置简单,成本低。缺点:无法感知服务器负载,可能造成某些服务器过载。
6.6.2 基于 Nginx 的负载均衡
用 Nginx 做 TCP/UDP 代理,把请求分发到多台 TURN 服务器。
Nginx 配置示例:
stream {
upstream turn_servers {
least_conn; # 最少连接数策略
server 192.168.1.10:3478;
server 192.168.1.11:3478;
server 192.168.1.12:3478;
}
server {
listen 3478 udp;
proxy_pass turn_servers;
proxy_timeout 60s;
proxy_responses 1;
}
server {
listen 3478 tcp;
proxy_pass turn_servers;
proxy_timeout 60s;
}
}
我个人比较推荐这种方式。Nginx 的 least_conn 策略能比较均匀地分配连接,而且配置起来也不复杂。
6.6.3 基于 Coturn 集群
Coturn 本身也支持集群模式。通过配置 relay-threads 和 userdb 共享,可以实现多实例协同。
# 每个 Coturn 实例的配置
relay-threads=4
userdb=/var/lib/turn/turndb
# 使用 Redis 共享用户数据库
redis-userdb=redis://redis-server:6379/0
这种方式适合大规模部署。但需要额外维护 Redis,复杂度会高一些。
6.7 知识体系总览
下面这张图总结了本章的核心内容,方便你快速回顾:
6.8 避坑指南
最后,分享几个我踩过的坑:
- 防火墙端口没开:记得在服务器安全组里开放 3478(UDP/TCP)和 5349(TLS)端口。我曾经因为这个排查了一整天。
- 带宽估算不足:TURN 中继的带宽消耗是双向的。一个 1080p 视频流大约需要 4-6 Mbps,如果有 100 个用户同时使用,服务器带宽至少要 1 Gbps。
- 日志没开:出问题的时候,日志是救命稻草。建议把
verbose打开,方便排查。 - 证书过期:如果用了 TLS 中继,记得设置证书自动续期。我见过好几次因为证书过期导致连接失败的情况。
好了,关于 STUN/TURN 服务器的部署,今天就聊到这里。配置这东西,光看文档是不够的,建议你动手搭一个试试。遇到问题别慌,先看日志,八成能找到答案。