跳到正文

FreeSWITCH 网络模式、IP 绑定与 NAT / STUN 专题 ​

⬅️ 返回 FreeSWITCH 容器化部署总览

本文详细介绍 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 模式? ​

  1. 避免 RTP 媒体流单通与丢包:VoIP 通信涉及海量动态分配的 RTP 音频流 UDP 端口(如 30000-30199/UDP),使用 Docker 容器网桥(Bridge)进行端口映射会导致极高的端口转发损耗、NAT 穿透异常以及严重的语音单通/无声问题;
  2. SIP 协议栈与 SDP 准确性:SIP 信令与 SDP 协商中需要向对端通告准确的媒体接收 IP 与端口,Host 模式下 FreeSWITCH 可直接绑定宿主机真实物理/虚拟网卡,杜绝 Docker 内部网桥 IP(如 172.17.0.x)泄漏到 SDP 中导致媒体流无法送达;
  3. 实时调度与网络性能:配合 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:9911callflow-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_v4192.168.2.246 (开发机局域网 IP)123.57.xxx.xxx (实际公网 EIP)123.57.xxx.xxx (实际公网 EIP)
esl_host192.168.2.246:9911127.0.0.1:9911 或 内网中台 IP127.0.0.1:9911 或 内网中台 IP
ops_db_dsnpgsql://hostaddr=127.0.0.1 ...pgsql://hostaddr=pg-host ...pgsql://hostaddr=pg-host ...
default_passwordmyfs1234自定义高强度密码 (必须修改)自定义高强度密码 (必须修改)
domain$${ops_local_ip_v4}$${ops_local_ip_v4}fs.yourdomain.com (与 SSL 域名一致)
domain_name$${domain}$${domain}$${domain}
bind_server_ipautoautoauto
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_prefsOPUS,G722,PCMU,PCMA,H264,VP8OPUS,G722,PCMU,PCMA,H264,VP8OPUS,G722,PCMU,PCMA,H264,VP8
rtp_video_max_bandwidth_in3mb800kb ~ 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"

文档与代码在同一仓库维护,现有 Markdown 是唯一内容源。