外观
FreeSWITCH 网络模式、IP 绑定与 NAT / STUN 专题
本文详细介绍 FreeSWITCH 容器化环境下的网络模式选型、vars.xml 预处理变量体系、本地套接字绑定(Binding IP)与外网广告(Advertising IP)机制、STUN 探测行为以及三大典型落地场景的配置最佳实践。
1. 网络模式选型与约束 (docker-compose.yml)
FreeSWITCH 容器必须且仅支持以 Host 主机网络模式 (network_mode: "host") 部署:
yaml
services:
freeswitch:
image: freeswitch-runtime:1.11.2-trixie
container_name: fs-app
restart: always
network_mode: "host"
cap_add:
- SYS_NICE
- NET_ADMIN为什么必须使用 Host 模式?
- 避免 RTP 媒体流单通与丢包:VoIP 通信涉及海量动态分配的 RTP 音频流 UDP 端口(如
30000-30199/UDP),使用 Docker 容器网桥(Bridge)进行端口映射会导致极高的端口转发损耗、NAT 穿透异常以及严重的语音单通/无声问题; - SIP 协议栈与 SDP 准确性:SIP 信令与 SDP 协商中需要向对端通告准确的媒体接收 IP 与端口,Host 模式下 FreeSWITCH 可直接绑定宿主机真实物理/虚拟网卡,杜绝 Docker 内部网桥 IP(如
172.17.0.x)泄漏到 SDP 中导致媒体流无法送达; - 实时调度与网络性能:配合
cap_add: [SYS_NICE, NET_ADMIN],使 FreeSWITCH 能在宿主机网络栈上直接以极低延迟调度与收发实时音频流。
2. 核心概念:内网绑定 IP、外网广告 IP 与解耦宏体系
FreeSWITCH 的网络机制严格区分 本机套接字绑定地址(Binding IP) 与 SDP 协商通告地址(Advertising IP)。为了解决传统配置中 IP 硬编码分散、环境迁移繁琐的问题,当前配置引入了 ops_* 解耦宏体系:
| 参数类别 | 关联变量 / 字段 | 典型取值 | 核心作用与严格约束 |
|---|---|---|---|
| 本机绑定 IP | $${local_ip_v4}sip-ip / rtp-ip | 172.21.38.245 或 192.168.2.246 | 必须是宿主机本地网卡真实存在的 IP(Linux 执行 ip addr 可见),FreeSWITCH 依此创建底层 UDP/TCP Socket 监听。⚠️ 严禁在此处绑定公网弹性 IP (EIP),否则会抛出 Cannot assign requested address 错误导致启动失败! |
| 核心解耦 IP | $${ops_local_ip_v4} | 192.168.2.246 或 123.57.205.60 | 服务对外暴露的核心 IPv4 地址。环境部署或迁移时只需修改此处单点,即可自动驱动 domain、external_rtp_ip 与 external_sip_ip 全局联动生效,消除多处硬编码。 |
| 外网广告 IP | $${external_sip_ip}$${external_rtp_ip}ext-sip-ip / ext-rtp-ip | 继承 $${ops_local_ip_v4}或显式公网 IP / 域名 | 用于 SIP Contact/Via 头域与 SDP 媒体描述(c=IN IP4 <ip>)。告诉对端终端或网关:“请把 SIP 响应与 RTP 语音流发送到此地址”。在 NAT/云主机环境下必须与外部可达入口一致,否则会导致单通或无声。 |
| 业务 ESL 地址 | $${esl_host} | 192.168.2.246:9911 | callflow-esl Outbound 业务流转中台的监听地址。dialplan 中的呼叫统一通过 <action application="socket" data="$${esl_host} async full"/> 接入智能业务控制中心。 |
| 核心数据 DSN | $${ops_db_dsn} | pgsql://hostaddr=... | PostgreSQL 核心数据库连接串。FreeSWITCH 核心并发通道与 Sofia 注册状态由 SQLite 升级为高性能 PG 集群存储。 |
| SIP 注册认证域 | $${domain}$${domain_name} | 继承 $${ops_local_ip_v4}或业务公网域名 | SIP 终端注册与鉴权上下文。分机注册时填写的 Domain 必须与该值一致,directory/ 中的所有用户分机默认继承该变量。 |
| 分机默认密码 | $${default_password} | 自定义强密码 | 分机账户初始注册密码。生产环境暴露在公网(5060/5080/7443)时必须修改,防止全网扫描器盗打(Toll Fraud)。 |
⚠️ 预处理器避坑铁律:FreeSWITCH 的
<X-PRE-PROCESS>属于 XML 预编译指令,不能直接用<!-- -->进行 XML 注释(预处理器在解析 XML 注释前就会执行该指令!)。若需临时禁用某行,必须直接删除该行或使用<X-NO-PRE-PROCESS>替换。
3. 全局解耦宏与对外广告 IP 的配置机制与选型
在 freeswitch-install/etc/freeswitch/vars.xml 中,对外地址与核心业务服务实现了高度解耦:
架构优势:单点修改,全局联动生效 ⭐️
xml
<!-- 1. 在 vars.xml 顶部定义核心解耦宏 -->
<X-PRE-PROCESS cmd="set" data="ops_local_ip_v4=123.57.205.60"/>
<X-PRE-PROCESS cmd="set" data="esl_host=123.57.205.60:9911"/>
<!-- 2. 下游配置自动引用,无需逐个文件修改 -->
<X-PRE-PROCESS cmd="set" data="domain=$${ops_local_ip_v4}"/>
<X-PRE-PROCESS cmd="set" data="domain_name=$${domain}"/>
<X-PRE-PROCESS cmd="set" data="external_rtp_ip=$${ops_local_ip_v4}"/>
<X-PRE-PROCESS cmd="set" data="external_sip_ip=$${ops_local_ip_v4}"/>无论将整套平台部署到阿里云 VPC(单网卡 + 公网 EIP 映射)、企业局域网,还是本地开发环境,仅需修改 ops_local_ip_v4 与 esl_host 一处,整套系统的 SIP 域、RTP 广播与信令地址即全面自动同步!
语法选型对照:
方案 A:单点静态解耦(推荐 ⭐️ 生产与自建环境默认)
主流云厂商(阿里云、腾讯云、华为云、AWS)均采用 1:1 NAT 架构(主机网卡仅有私网 IP 如 172.21.x.x,公网 EIP 绑定在 VPC 网关):
xml
<!-- 将 ops_local_ip_v4 设为宿主机对外可达 IP(公网 EIP 或局域网主 IP) -->
<X-PRE-PROCESS cmd="set" data="ops_local_ip_v4=123.57.205.60"/>
<!-- 媒体与信令广告直接继承 -->
<X-PRE-PROCESS cmd="set" data="external_rtp_ip=$${ops_local_ip_v4}"/>
<X-PRE-PROCESS cmd="set" data="external_sip_ip=$${ops_local_ip_v4}"/>方案 B:STUN 自动探测(动态公网 IP / 家宽测试环境)
如果部署在动态公网 IP(如家庭宽带、动态拨号机房)环境,可启用 STUN 探测:
xml
<!-- 启动时通过公共 STUN 服务器动态解析当前出口公网 IP -->
<X-PRE-PROCESS cmd="stun-set" data="external_rtp_ip=stun:stun.freeswitch.org"/>
<X-PRE-PROCESS cmd="stun-set" data="external_sip_ip=stun:stun.freeswitch.org"/>⚠️ STUN 局限性:若公共 STUN 服务器网络超时或不可达,会导致 FreeSWITCH 启动/重载时卡顿 10~30 秒,甚至因探测失败回退为错误 IP 引发通话无声。因此具备固定公网 IP 的生产环境严禁使用
stun-set。
方案 C:纯内网 / 专网私有化部署(无公网 NAT)
若服务仅在企业局域网或内网单机测试:
xml
<!-- 直接填写局域网静态 IP -->
<X-PRE-PROCESS cmd="set" data="ops_local_ip_v4=192.168.2.246"/>
<X-PRE-PROCESS cmd="set" data="external_rtp_ip=$${ops_local_ip_v4}"/>
<X-PRE-PROCESS cmd="set" data="external_sip_ip=$${ops_local_ip_v4}"/>4. 三大典型部署场景配置对照表
| 配置字段 | 场景 1:本地 WSL / 局域网开发测试 | 场景 2:公网云服务器 (阿里云/腾讯云) | 场景 3:公网反代 + WebRTC 域名接入 |
|---|---|---|---|
ops_local_ip_v4 | 192.168.2.246 (开发机局域网 IP) | 123.57.xxx.xxx (实际公网 EIP) | 123.57.xxx.xxx (实际公网 EIP) |
esl_host | 192.168.2.246:9911 | 127.0.0.1:9911 或 内网中台 IP | 127.0.0.1:9911 或 内网中台 IP |
ops_db_dsn | pgsql://hostaddr=127.0.0.1 ... | pgsql://hostaddr=pg-host ... | pgsql://hostaddr=pg-host ... |
default_password | myfs1234 | 自定义高强度密码 (必须修改) | 自定义高强度密码 (必须修改) |
domain | $${ops_local_ip_v4} | $${ops_local_ip_v4} | fs.yourdomain.com (与 SSL 域名一致) |
domain_name | $${domain} | $${domain} | $${domain} |
bind_server_ip | auto | auto | auto |
external_rtp_ip | $${ops_local_ip_v4} | $${ops_local_ip_v4} | $${ops_local_ip_v4} |
external_sip_ip | $${ops_local_ip_v4} | $${ops_local_ip_v4} | $${ops_local_ip_v4} |
global_codec_prefs | OPUS,G722,PCMU,PCMA,H264,VP8 | OPUS,G722,PCMU,PCMA,H264,VP8 | OPUS,G722,PCMU,PCMA,H264,VP8 |
rtp_video_max_bandwidth_in | 3mb | 800kb ~ 1.5mb (防带宽打满) | 800kb ~ 1.5mb |
5. 完整 vars.xml 核心配置样例
文件路径:freeswitch-install/etc/freeswitch/vars.xml(已包含全量中文精准注释):
xml
<include>
<!--
【核心安全配置】
default_password: 默认分机密码 (用于 1000 - 1019 等内置分机)。
生产环境必须修改为高强度密码,防止 SIP 暴力破解与盗打盗拨。
-->
<X-PRE-PROCESS cmd="set" data="default_password=myfs1234"/>
<!--
【核心网络与服务接入配置】
ops_local_ip_v4: 本机核心 IPv4 地址。
- 容器单网卡/单机环境: 填入宿主机局域网或公网 IP 地址。
- 当需要对外提供服务时,其他配置项(如 domain、external_rtp_ip 等)将基于此变量展开。
-->
<X-PRE-PROCESS cmd="set" data="ops_local_ip_v4=192.168.2.246"/>
<!--
【核心数据存储 DSN 配置】
ops_db_dsn: 数据库连接字符串 (支持 pgsql / mariadb / odbc)。
FreeSWITCH 核心与 sofia 注册表、通道表将由原本的本地 SQLite 迁移至高性能 PostgreSQL。
-->
<X-PRE-PROCESS cmd="set" data="ops_db_dsn=pgsql://hostaddr=127.0.0.1 port=5432 dbname=freeswitch user='postgres' password='postgres' options='-c statement_timeout=3000' connect_timeout=5 keepalives=1 keepalives_idle=30 keepalives_interval=5 keepalives_count=3"/>
<!--
【ESL 业务服务地址】
esl_host: callflow-esl Outbound 业务流转中台监听地址。
dialplan 收到呼入或呼出呼叫后,会将控制权交由该地址的 ESL 服务进行智能路由与流式 ASR/TTS 调度。
-->
<X-PRE-PROCESS cmd="set" data="esl_host=192.168.2.246:9911"/>
<!--
【SIP 域与呼叫默认配置】
domain: 核心 SIP 域名/IP。分机注册及认证请求将校验此域名。
domain_name: SIP 认证域名别名。
hold_music: 呼叫保持时播放的等待音乐 (Music on Hold, 默认走 local_stream 流)。
use_profile: 默认使用的 SIP Profile 配置文件名称。
-->
<X-PRE-PROCESS cmd="set" data="domain=$${ops_local_ip_v4}"/>
<X-PRE-PROCESS cmd="set" data="domain_name=$${domain}"/>
<X-PRE-PROCESS cmd="set" data="hold_music=local_stream://moh"/>
<X-PRE-PROCESS cmd="set" data="use_profile=external"/>
<!--
【媒体协商编解码器优先级】
global_codec_prefs: 系统支持协商的全部编解码器及优先级。
outbound_codec_prefs: 系统外呼出局呼叫时 SDP 携带的媒体协商编解码顺序。
-->
<X-PRE-PROCESS cmd="set" data="global_codec_prefs=OPUS,G722,PCMU,PCMA,H264,VP8"/>
<X-PRE-PROCESS cmd="set" data="outbound_codec_prefs=OPUS,G722,PCMU,PCMA,H264,VP8"/>
<!--
【SIP 协议栈监听与外部 NAT / RTP 穿透配置】
bind_server_ip: SIP Profile 默认绑定的网络接口,auto 代表绑定内核检测的本地 IP。
external_rtp_ip: 声明在 SDP 中向对端暴露的 RTP 媒体接收 IP (NAT 环境至关重要)。
external_sip_ip: 声明在 SIP 信令中向对端暴露的 Contact / Via IP。
- 公网部署或容器 Host 模式时,设置为 $${ops_local_ip_v4};
- 若位于对称 NAT / 云厂商内网且对外提供服务,需填写真实公网 IP。
-->
<X-PRE-PROCESS cmd="set" data="bind_server_ip=auto"/>
<X-PRE-PROCESS cmd="set" data="external_rtp_ip=$${ops_local_ip_v4}"/>
<X-PRE-PROCESS cmd="set" data="external_sip_ip=$${ops_local_ip_v4}"/>
<!-- 拨号计划循环展开优化: 设为 true 提升 XML 规则匹配性能 -->
<X-PRE-PROCESS cmd="set" data="unroll_loops=true"/>
<!--
【Sofia SIP Profile 端口与鉴权参数】
-->
<X-PRE-PROCESS cmd="set" data="internal_auth_calls=true"/>
<X-PRE-PROCESS cmd="set" data="internal_sip_port=5060"/>
<X-PRE-PROCESS cmd="set" data="internal_tls_port=5061"/>
<X-PRE-PROCESS cmd="set" data="internal_ssl_enable=false"/>
<X-PRE-PROCESS cmd="set" data="external_auth_calls=false"/>
<X-PRE-PROCESS cmd="set" data="external_sip_port=5080"/>
<X-PRE-PROCESS cmd="set" data="external_tls_port=5081"/>
<X-PRE-PROCESS cmd="set" data="external_ssl_enable=false"/>
<!--
【媒体流优化与高级控制参数】
suppress_cng: 抑制舒适静音生成 (Comfort Noise Generation, 对 AI 语音流式 VAD 检测至关重要)。
-->
<X-PRE-PROCESS cmd="set" data="rtp_video_max_bandwidth_in=3mb"/>
<X-PRE-PROCESS cmd="set" data="rtp_video_max_bandwidth_out=3mb"/>
<X-PRE-PROCESS cmd="set" data="suppress_cng=true"/>
<X-PRE-PROCESS cmd="set" data="rtp_liberal_dtmf=true"/>
</include>6. 运行时 IP 诊断与核验指令
修改配置并执行 fs_cli -x "reloadxml" 后,可随时通过以下指令在控制台验证当前变量解析是否正确:
bash
# 查看本地网卡探测到的 IPv4 地址(内核底层检测)
docker exec -it fs-app fs_cli -x "eval \$\${local_ip_v4}"
# 查看核心解耦 IP 宏变量取值
docker exec -it fs-app fs_cli -x "eval \$\${ops_local_ip_v4}"
# 查看当前生效的 ESL 业务中台地址
docker exec -it fs-app fs_cli -x "eval \$\${esl_host}"
# 查看当前生效的数据库连接串
docker exec -it fs-app fs_cli -x "eval \$\${ops_db_dsn}"
# 查看当前生效的外网 RTP 广告 IP
docker exec -it fs-app fs_cli -x "eval \$\${external_rtp_ip}"
# 查看当前生效的外网 SIP 广告 IP
docker exec -it fs-app fs_cli -x "eval \$\${external_sip_ip}"
# 查看当前生效的认证 Domain
docker exec -it fs-app fs_cli -x "eval \$\${domain}"
# 查看 internal Profile 实际绑定的 SIP/RTP URL 与端口
docker exec -it fs-app fs_cli -x "sofia status profile internal"