作者:james.zhu
来源:SIP实验室
原文:https://mp.weixin.qq.com/s/EmMxO7KjQ7tR80_iGNUvmQ
马孔多的老乞丐对猴子说,家,房子需要一个入户们,单元们,另外还要一个小区大门。这是为了安全。IPPBX也是一样。很多公网环境的使用要求越来越多,服务器端为了实现拓扑隐藏,需要投入更多的额外的成本。WebRTC可以和开源FreeSWITCH实现无缝的集成。
很多时候,WebRTC终端可能部署在异地和外网环境中。WebRTC外网注册和实现和内部SIP之间的通信就需要代理服务器或者SBC来实现转发扩展。如果用户不能使用SBC的话,可以考虑通过FRPS/FRPC方式实现和内网FreeSWITCH的信令转发处理,然后利用STUN实现媒体的转发处理。当然,用户为了支持以上的环境需求,需要部署多台服务器,并且确保这些转发代理服务器具有公网地址,通过公网转发实现和内网FreeSWITCH的音视频通信。部署了多台公网的服务器,用户需要关注更多的其他风险,例如安全问题,维护问题和扩展等问题。我们根据以上的这些挑战和大家分享关于使用FRPS实现的WEBRTC终端和内网FreeSWITCH的交互。
1. 概述
随着远程办公和分布式通信需求的增长,企业越来越需要构建能够支持外部WebRTC终端接入内部通信系统的解决方案。本文详细阐述了一种基于FreeSWITCH的完整解决方案,通过FRPS作为SIP信令代理服务器和STUN负责媒体转发,使外网的WebRTC终端能够安全、高效地注册到内网的FreeSWITCH服务器。
该解决方案充分考虑了网络安全、NAT穿透、会话管理和媒体传输等关键因素,为构建企业级VoIP系统提供了可靠的技术框架。本文将从系统架构、详细配置、安全性、扩展性以及维护挑战等多个维度进行深入探讨。
2. 系统架构
2.1 部署场景图例
互联网 | 企业内网
|
+-------------+ |
| WebRTC | |
| 终端用户 | |
+------+------+ |
| |
v |
+------+------+ +---------------+ | +-------------+ +--------------+
| STUN 服务器 +---->+ FRPS 代理服务器 +------------->+ FRPC 客户端 +---->+ FreeSWITCH |
+-------------+ +---------------+ | +-------------+ +--------------+
^ ^ | ^ ^
| | | | |
+------+------+ +------+------+ | +-------+-------+ +------+-------+
| WebRTC | | SIP 信令流 | | | 媒体流转发 | | 数据库/认证 |
| 信令/媒体流 | | | | | | | |
+-------------+ +-------------+ | +---------------+ +--------------+
2.2 组件介绍
2.2.1 FreeSWITCH
FreeSWITCH是一个开源的通信平台,支持多种协议如SIP、WebRTC等,能够处理语音、视频和文本通信。在我们的架构中,FreeSWITCH部署在企业内网,负责处理所有的呼叫控制和媒体流处理。
2.2.2 FRPS/FRPC
FRPS (Fast Reverse Proxy Server) 是一个高性能的反向代理服务器,部署在公网上,用于将外部请求安全地转发到内网。FRPC是其客户端组件,部署在内网中,与FRPS建立持久连接。
2.2.3 STUN服务器
STUN (Session Traversal Utilities for NAT) 服务器帮助WebRTC客户端发现其公网IP地址和端口,解决NAT穿透问题,确保媒体流能够正确传输。
2.2.4 WebRTC终端
WebRTC终端是基于浏览器或专用应用的客户端,支持实时音视频通信,通过SIP协议注册到FreeSWITCH服务器。
3. 详细配置
3.1 FreeSWITCH配置
3.1.1 安装与基础配置
首先确保FreeSWITCH已正确安装并启用了必要的模块:
# 安装FreeSWITCH及相关模块
apt-get install freeswitch freeswitch-mod-sofia freeswitch-mod-verto freeswitch-mod-opus freeswitch-mod-vpx
# 确保mod_sofia和mod_verto已加载
fs_cli -x "load mod_sofia"
fs_cli -x "load mod_verto"
3.1.2 SIP配置
修改/etc/freeswitch/sip_profiles/external.xml
文件,确保WebRTC支持:
<profile name="external">
<settings>
<param name="sip-port" value="5060"/>
<param name="tls-port" value="5061"/>
<param name="wss-binding" value=":7443"/>
<param name="ws-binding" value=":7080"/>
<!-- WebRTC 支持 -->
<param name="liberal-dtmf" value="true"/>
<param name="rtp-timeout-sec" value="300"/>
<param name="rtp-hold-timeout-sec" value="1800"/>
<param name="enable-timer" value="false"/>
<param name="dtmf-duration" value="2000"/>
<param name="dtmf-type" value="rfc2833"/>
<param name="auto-rtp-bugs" value="clear"/>
<param name="inbound-codec-prefs" value="OPUS,VP8,H264,G722,PCMU,PCMA"/>
<param name="outbound-codec-prefs" value="OPUS,VP8,H264,G722,PCMU,PCMA"/>
<!-- TLS 配置 -->
<param name="tls" value="true"/>
<param name="tls-only" value="false"/>
<param name="tls-cert-dir" value="/etc/freeswitch/tls"/>
<param name="tls-version" value="tlsv1.2"/>
</settings>
</profile>
3.1.3 WebRTC配置
创建或修改/etc/freeswitch/autoload_configs/verto.conf.xml
:
<configuration name="verto.conf" description="Verto Endpoint">
<settings>
<param name="debug" value="0"/>
<param name="enable-binding-local" value="false"/>
<param name="enable-binding-remote" value="false"/>
<param name="userauth-no-params" value="false"/>
<param name="root-password" value="securerootpassword"/>
<param name="max-wire-size" value="65536"/>
<param name="write-queue-size" value="0"/>
<param name="attach-timeout" value="120"/>
</settings>
<profiles>
<profile name="default">
<param name="bind-local" value="0.0.0.0:8081"/>
<param name="bind-local-secure" value="0.0.0.0:8082"/>
<param name="force-register-domain" value="$${domain}"/>
<param name="secure-combined" value="/etc/freeswitch/tls/wss.pem"/>
<param name="inbound-codec-string" value="opus,vp8,h264,vp9"/>
<param name="outbound-codec-string" value="opus,vp8,h264,vp9"/>
<param name="rtp-ip" value="$${local_ip_v4}"/>
<param name="ext-rtp-ip" value="auto-nat"/>
<param name="local-network" value="192.168.0.0/16"/>
<param name="outbound-codec-string" value="opus,vp8,h264"/>
<param name="apply-candidate-acl" value="wan.auto"/>
<param name="apply-candidate-acl" value="lan.auto"/>
</profile>
</profiles>
</configuration>
3.1.4 TLS证书配置
WebRTC要求使用安全连接,需配置SSL证书:
# 生成自签名证书
mkdir -p /etc/freeswitch/tls
cd /etc/freeswitch/tls
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout wss.key -out wss.crt
cat wss.key wss.crt > wss.pem
chmod 600 wss.*
# 更新FreeSWITCH配置使用新证书
fs_cli -x "sofia profile external restart"
fs_cli -x "reload mod_verto"
3.2 FRPS代理服务器配置
3.2.1 安装FRPS
在公网服务器上安装FRPS:
# 下载FRPS
wget https://github.com/fatedier/frp/releases/download/v0.41.0/frp_0.41.0_linux_amd64.tar.gz
tar -zxvf frp_0.41.0_linux_amd64.tar.gz
cd frp_0.41.0_linux_amd64
# 配置FRPS
cp frps.ini /etc/frps.ini
# 创建systemd服务
cat > /etc/systemd/system/frps.service << EOF
[Unit]
Description=FRP Server
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/frps -c /etc/frps.ini
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
# 安装frps
cp frps /usr/local/bin/
chmod +x /usr/local/bin/frps
# 启动服务
systemctl daemon-reload
systemctl enable frps
systemctl start frps
3.2.2 FRPS配置文件
编辑/etc/frps.ini
:
[common]
bind_addr = 0.0.0.0
bind_port = 7000
vhost_http_port = 80
vhost_https_port = 443
# SIP (UDP) 代理配置
bind_udp_port = 7001
# 控制台配置
dashboard_addr = 0.0.0.0
dashboard_port = 7500
dashboard_user = admin
dashboard_pwd = strongpassword
# 授权验证
authentication_method = token
token = your_auth_token_here
# 日志设置
log_file = /var/log/frps.log
log_level = info
log_max_days = 3
# 允许类型
allow_ports = 5060-5070,8000-9000,16384-32768
3.3 STUN服务器配置
3.3.1 安装STUN服务器
在公网服务器上安装STUN服务器:
# 安装STUN服务器
apt-get install coturn
# 配置turnserver
cat > /etc/turnserver.conf << EOF
listening-port=3478
listening-ip=YOUR_PUBLIC_IP
external-ip=YOUR_PUBLIC_IP
realm=yourdomain.com
fingerprint
no-tls
no-dtls
min-port=16384
max-port=32768
log-file=/var/log/turn.log
EOF
# 启动服务
systemctl enable coturn
systemctl start coturn
3.3.2 FreeSWITCH中配置ICE/STUN
修改/etc/freeswitch/sip_profiles/external.xml
以支持STUN:
<param name="ext-rtp-ip" value="YOUR_PUBLIC_IP"/>
<param name="ext-sip-ip" value="YOUR_PUBLIC_IP"/>
<param name="stun-enabled" value="true"/>
<param name="stun-auto-disable" value="false"/>
<param name="rtcp-audio-interval-msec" value="5000"/>
<param name="rtcp-video-interval-msec" value="3000"/>
<param name="force-register-domain" value="YOUR_PUBLIC_IP"/>
<param name="force-subscription-domain" value="YOUR_PUBLIC_IP"/>
<param name="force-register-db-domain" value="YOUR_PUBLIC_IP"/>
3.4 WebRTC客户端配置
3.4.1 JavaScript示例代码
以下是基于SIP.js的WebRTC客户端示例代码:
// 引入SIP.js库
const domain = 'your_domain.com';
const wsServer = `wss://${domain}:7443`;
// 配置SIP UA
const configuration = {
uri: `sip:extension@${domain}`,
authorizationUser: 'extension',
password: 'password',
transportOptions: {
wsServers: [wsServer],
traceSip: true
},
stunServers: ['stun:stun.yourdomain.com:3478'],
turnServers: [
{
urls: 'turn:turn.yourdomain.com:3478',
username: 'turnuser',
password: 'turnpassword'
}
],
sessionDescriptionHandlerFactoryOptions: {
peerConnectionOptions: {
rtcConfiguration: {
iceServers: [
{ urls: 'stun:stun.yourdomain.com:3478' },
{
urls: 'turn:turn.yourdomain.com:3478',
username: 'turnuser',
credential: 'turnpassword'
}
]
}
}
}
};
// 创建UA实例
const ua = newSIP.UA(configuration);
// 注册事件
ua.on('registered', () => {
console.log('Successfully registered');
});
ua.on('registrationFailed', (response, cause) => {
console.error('Registration failed', cause);
});
// 启动UA
ua.start();
3.4.2 HTML页面示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>WebRTC SIP客户端</title>
<script src="https://cdn.jsdelivr.net/npm/sip.js@0.20.0/dist/sip.min.js"></script>
</head>
<body>
<h1>WebRTC SIP客户端</h1>
<div id="login">
<input type="text" id="username" placeholder="用户名">
<input type="password" id="password" placeholder="密码">
<button id="register">注册</button>
</div>
<div id="call-controls" style="display:none;">
<input type="text" id="target" placeholder="呼叫目标">
<button id="call">呼叫</button>
<button id="hangup">挂断</button>
</div>
<div id="media">
<audio id="remoteAudio" autoplay></audio>
<video id="remoteVideo" autoplay></video>
<video id="localVideo" muted autoplay></video>
</div>
<script src="app.js"></script>
</body>
</html>
4. 网络穿透与媒体流传输
WebRTC媒体流的传输是该解决方案的核心挑战之一。在我们的架构中,通过以下方式确保媒体流的高效传输:
- 1. ICE框架:利用ICE(Interactive Connectivity Establishment)框架进行NAT穿透,先尝试直连,再通过STUN服务器,最后通过TURN中继
- 2. STUN服务器:帮助WebRTC终端发现自己的公网IP和端口
- 3. 媒体优化:
- • 配置适当的编解码器优先级(OPUS音频、VP8/H.264视频)
- • 启用RTCP反馈,优化媒体质量
- • 合理设置抖动缓冲区,平衡延迟和音质
FreeSWITCH的媒体处理配置示例:
<param name="rtp-timeout-sec" value="30"/>
<param name="rtp-hold-timeout-sec" value="180"/>
<param name="media-option" value="resume-media-on-hold"/>
<param name="media-option" value="bypass-media-after-att-xfer"/>
<param name="jitterbuffer-msec" value="60"/>
<param name="rtp-timer-name" value="soft"/>
5. 安全性考量
在构建此类跨网络的通信系统时,安全性至关重要:
5.1 传输层安全
• 所有信令使用WSS(WebSocket Secure)和TLS确保加密传输
• 媒体流使用SRTP(Secure Real-time Transport Protocol)加密
• 证书管理与更新机制,防止证书过期导致服务中断
5.2 认证与授权
• 强密码策略与定期轮换
• 实施IP限制和访问控制列表
• 考虑双因素认证(2FA)
• 基于角色的访问控制(RBAC)
5.3 防护措施
FreeSWITCH安全配置:
<!-- 防SIP扫描攻击 -->
<param name="challenge-realm" value="auto_from"/>
<param name="apply-inbound-acl" value="trusted"/>
<param name="apply-register-acl" value="domains"/>
<param name="auth-calls" value="true"/>
<param name="auth-all-packets" value="false"/>
<param name="log-auth-failures" value="true"/>
<param name="drop-non-matching-registration" value="true"/>
<!-- 限制注册尝试频率 -->
<param name="max-registrations-per-extension" value="3"/>
<param name="accept-blind-reg" value="false"/>
<param name="accept-blind-auth" value="false"/>
<param name="multiple-registrations" value="false"/>
5.4 FRPS安全加固
# 强身份验证
authentication_method = token
token = complex_random_token_string
# 限制允许的端口范围
allow_ports = 5060-5070,8000-9000,16384-32768
# 启用日志审计
detailed_logs = true
# TLS加密
tls_only = true
tls_cert_file = /path/to/server.crt
tls_key_file = /path/to/server.key
6. 扩展性与未来规划
6.1 水平扩展
• FreeSWITCH集群:使用共享数据库实现会话状态同步
• 负载均衡:多FRPS实例+DNS轮询或专用负载均衡器
• 媒体服务器分离:考虑使用专用媒体服务器如Janus或MediaSoup处理大量媒体流
6.2 功能扩展
• WebRTC录制:结合FreeSWITCH的录制功能实现通话录制
• 实时转码:按需转换不同终端使用的编解码器
• 会议系统集成:可扩展为多方视频会议系统
• WebRTC<->SIP网关:实现与传统SIP终端互通
6.3 监控与分析
• 实施Prometheus+Grafana监控系统
• 开发自定义指标采集器,监控关键性能指标
• 通话质量监控(MOS评分、抖动、丢包率等)
7. 技术挑战与维护
7.1 常见问题与解决方案
问题描述 | 可能原因 | 解决方案 |
WebRTC注册失败 | TLS证书问题 | 检查证书有效性和信任链 |
单向音频 | NAT穿透失败 | 调整ICE配置,确保STUN服务可用 |
媒体质量差 | 网络抖动或丢包 | 调整抖动缓冲区,启用前向纠错 |
FRPS连接断开 | 网络不稳定 | 增加心跳频率,实现自动重连 |
高CPU使用率 | 转码负担重 | 统一编解码标准,或增加服务器资源 |
7.2 日常维护任务
• 日志分析:定期审查FreeSWITCH和FRPS日志
• 性能监控:实时监控系统资源使用情况
• 安全更新:及时应用系统和组件安全补丁
• 容量规划:根据使用模式预测资源需求
• 备份策略:定期备份配置和关键数据
7.3 升级策略
• 建立测试环境,先在测试环境验证升级
• 实施蓝绿部署模式,降低升级风险
• 制定详细的回滚计划,应对升级失败情况
• 采用配置管理工具(如Ansible)自动化部署过程
8. 结论
本文详细阐述了外网WebRTC终端通过SIP信令、FRPS代理和STUN媒体转发注册到内网FreeSWITCH的完整解决方案。这一架构充分考虑了安全性、可扩展性和维护性,为企业通信系统提供了强大的技术支持。
通过合理配置FreeSWITCH、FRPS和STUN服务器,企业可以构建一个安全、高效、可靠的WebRTC通信平台,满足远程办公和跨网络通信的需求。随着WebRTC技术的不断发展,该解决方案还可以进一步扩展,支持更多高级功能和更大规模的部署。
9. 参考资料
1. FreeSWITCH官方文档: https://freeswitch.org/confluence/
2. FRP项目文档: https://github.com/fatedier/frp
3. WebRTC官方文档: https://webrtc.org/getting-started/overview
4. SIP.js文档: https://sipjs.com/api/0.20.0/
5. RFC 5389: STUN协议规范: https://tools.ietf.org/html/rfc5389
6. RFC 5766: TURN协议规范: https://tools.ietf.org/html/rfc5766
7. RFC 8445: ICE协议规范: https://tools.ietf.org/html/rfc8445
8. Anthony Minessale II, “FreeSWITCH Cookbook”, Packt Publishing, 2012
9. Michael S. Collins, “FreeSWITCH 1.8”, Packt Publishing, 2017
10. Alan B. Johnston, “WebRTC: APIs and RTCWEB Protocols of the HTML5 Real-Time Web”, Digital Codex LLC, 2013
版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。