跳到正文

FreeSWITCH SIP Profiles 架构、配置与外呼网关专题 ​

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

本文详细剖析 FreeSWITCH 的 Sofia-SIP 用户代理(User Agent, UA)架构,深入解析 internal.xml、external.xml、WebRTC 媒体传输以及第三方运营商 SIP Trunk 网关的配置实战与动态运维指令。


1. Sofia Profile 架构模型与前后端隔离 ​

在 FreeSWITCH 中,SIP 协议栈由核心模块 mod_sofia 驱动。每个 SIP Profile 代表一个独立的 SIP 用户代理(UA)实例。每个 Profile 维护独立的:

  • 网络 Socket 监听:独立的 IP 与端口(如 5060 / 5080);
  • 身份认证策略:是否启用 401 挑战认证(auth-calls);
  • 编解码协商规则:inbound-codec-prefs 与协商策略(generous vs greedy);
  • NAT / ACL 穿越逻辑:local-network-acl 与 apply-candidate-acl;
  • 外呼网关注册列表:独立的 gateways/ 集合。

FreeSWITCH 默认采用经典的前后端职责隔离设计:


2. internal 与 external 核心定位对比 ​

维度internal Profile (internal.xml)external Profile (external.xml)
主要定位内部分机注册、WebRTC 网页音视频通话、坐席软电话接入对接运营商/线路商 SIP Trunk 网关、PSTN 呼入线路
默认监听端口5060/UDP, 5060/TCP($${internal_sip_port})5080/UDP, 5080/TCP($${external_sip_port})
WebRTC 端口5066/WS, 7443/WSS(支持浏览器原生接入)默认不开启 WebRTC
身份认证 (auth-calls)true(强制认证):所有注册与呼叫必须匹配 directory/ 中的用户密码false(免认证):信任运营商送来的呼叫,由 Dialplan 校验来源 IP
默认呼入 Context注册成功后进入 default context;未注册进入 public外部进线统一直接进入 public context 进行隔离过滤
网关包含目录sip_profiles/internal/*.xmlsip_profiles/external/*.xml(外呼 Trunk 存放地)
典型业务流1000~1019 分机注册、Web 端软电话拨打、callflow 交互式 IVR外呼打电话给真实手机号、400/DID 线路入局

3. internal.xml 深度配置剖析与关键参数 ​

配置文件路径:freeswitch-install/etc/freeswitch/sip_profiles/internal.xml

xml
<profile name="internal">
  <!--
      FreeSWITCH Sofia SIP 内部协议栈配置 (internal.xml)
      =============================================================================
      定位与职责:
      1. 监听端口: 默认 5060 (UDP/TCP), 5061 (TLS), 5066 (WebRTC WS), 7443 (WebRTC WSS)
      2. 核心用途: 局域网/办公软电话 SIP 话机注册、WebRTC 网页坐席音频通话、内部分机互拨
      3. 呼叫流向: 经由此 Profile 认证的呼叫送入 default 拨号计划上下文 (context="default")
      4. 鉴权机制: 强制启用 SIP Digest 认证 (auth-calls="true"),分机账号匹配 directory/ 目录
      =============================================================================
  -->

  <!-- 网关加载入口: 支持通过 internal profile 级联内部 SIP 服务与下游节点 -->
  <gateways>
    <X-PRE-PROCESS cmd="include" data="internal/*.xml"/>
  </gateways>

  <domains>
    <domain name="all" alias="true" parse="false"/>
  </domains>

  <settings>
    <!-- 日志调试与核心软时钟 -->
    <param name="debug" value="0"/>
    <param name="sip-trace" value="no"/>
    <param name="sip-capture" value="no"/>
    <param name="rtp-timer-name" value="soft"/>                <!-- 推荐 soft 软时钟,消除物理时钟漂移 -->

    <!-- ================================================================= -->
    <!-- 1. SIP 信号与传输层 Socket 绑定                                   -->
    <!-- ================================================================= -->
    <param name="sip-port" value="$${internal_sip_port}"/>    <!-- 默认 5060 -->
    <param name="sip-ip" value="$${local_ip_v4}"/>            <!-- 宿主机网卡真实 IP -->
    <param name="rtp-ip" value="$${local_ip_v4}"/>            <!-- 宿主机网卡真实 IP -->

    <!-- ================================================================= -->
    <!-- 2. NAT 穿越与外网 SDP 媒体流广播 (用于公网/云服务器)                 -->
    <!-- ================================================================= -->
    <param name="ext-sip-ip" value="$${external_sip_ip}"/>    <!-- 广播 IP,默认继承 $${ops_local_ip_v4} -->
    <param name="ext-rtp-ip" value="$${external_rtp_ip}"/>    <!-- 广播 IP,默认继承 $${ops_local_ip_v4} -->
    <param name="NDLB-force-rport" value="true"/>             <!-- 强制遵循 RFC3581 rport 修复 NAT 响应 -->
    <param name="aggressive-nat-detection" value="true"/>     <!-- 自动检测客户端 NAT 端口漂移 -->

    <!-- ================================================================= -->
    <!-- 3. WebRTC SIP over WebSocket 端口绑定                             -->
    <!-- ================================================================= -->
    <param name="ws-binding" value=":5066"/>                  <!-- SIP over WS 端口 -->
    <param name="wss-binding" value=":7443"/>                 <!-- SIP over Secure WSS 端口 -->

    <!-- ================================================================= -->
    <!-- 4. 身份认证与用户域绑定                                          -->
    <!-- ================================================================= -->
    <param name="auth-calls" value="$${internal_auth_calls}"/> <!-- 强制开启分机呼叫鉴权 (true) -->
    <param name="auth-subscriptions" value="true"/>           <!-- 订阅事件鉴权 -->
    <param name="inbound-reg-force-matching-username" value="true"/> <!-- 强制注册用户名一致性 -->
    <param name="force-register-domain" value="$${domain}"/>   <!-- 强制使用 vars.xml 定义的域鉴权 -->
    <param name="force-subscription-domain" value="$${domain}"/>
    <param name="force-register-db-domain" value="$${domain}"/>
    <param name="multiple-registrations" value="contact"/>     <!-- 允许同一账号在多台终端/软电话同时在线 -->

    <!-- ================================================================= -->
    <!-- 5. 编解码器协商策略                                              -->
    <!-- ================================================================= -->
    <param name="inbound-codec-prefs" value="$${global_codec_prefs}"/>   <!-- OPUS,G722,PCMU,PCMA,H264,VP8 -->
    <param name="outbound-codec-prefs" value="$${global_codec_prefs}"/>
    <!-- generous: 优先尊重对端客户端提议的编解码顺序; greedy: 强制使用服务端首选顺序 -->
    <param name="inbound-codec-negotiation" value="generous"/>
    <!-- late-negotiation: 允许呼叫先进入 Dialplan 解析后再协商编解码(业务灵活性更高) -->
    <param name="inbound-late-negotiation" value="true"/>

    <!-- ================================================================= -->
    <!-- 6. 媒体超时与心跳保活机制                                        -->
    <!-- ================================================================= -->
    <param name="rtp-timeout-sec" value="300"/>                <!-- RTP 媒体流无数据超时(秒) -->
    <param name="rtp-hold-timeout-sec" value="1800"/>          <!-- 保持呼叫超时(秒) -->
    <param name="nat-options-ping" value="true"/>              <!-- 向 NAT 后的分机定时发送 OPTIONS 保持穿透 -->
    <param name="all-reg-options-ping" value="true"/>          <!-- 向所有注册终端定时发送 OPTIONS 心跳探活 -->
    <param name="unregister-on-options-fail" value="false"/>   <!-- 默认只观测状态,避免误剔除不响应 OPTIONS 的可用终端 -->

    <!-- ================================================================= -->
    <!-- 7. WebRTC 穿透与 ACL 高级配置 (结合 coturn)                       -->
    <!-- ================================================================= -->
    <!-- 当使用 Nginx 反代或 WSS 时,设为 none 强制走 NAT 广告 ext-rtp-ip -->
    <param name="local-network-acl" value="none"/>
    <!-- 配合 coturn: 强制过滤 WebRTC ICE Candidate,仅保留指定 relay 候选 -->
    <param name="apply-candidate-acl" value="softphone-turn-relay"/>
    <param name="apply-inbound-acl" value="domains"/>

    <!-- ================================================================= -->
    <!-- 8. 录音持久化模版                                                 -->
    <!-- ================================================================= -->
    <param name="record-path" value="$${recordings_dir}"/>
    <param name="record-template" value="${caller_id_number}.${target_domain}.${strftime(%Y-%m-%d-%H-%M-%S)}.wav"/>
  </settings>
</profile>

nat-options-ping 与 all-reg-options-ping 周期性向 NAT 后终端或全部注册发送 OPTIONS,供 Sofia 更新 ping_status / ping_time。unregister-on-options-fail 默认关闭:部分仍能正常注册和 接听 INVITE 的终端会忽略 OPTIONS、返回非 200/486 状态或遭遇瞬时网络抖动;在默认阈值下, 一次失败就可能使注册进入不可达并被加速过期。只有完成终端兼容性与网络抖动验证后,才应把自动 注销作为显式 opt-in。

人工诊断与清理由 callflow-esl 的 POST /freeswitch/registrations/probe、 POST /freeswitch/registrations/flush 提供:probe 读取最近一次 Sofia 心跳/注册状态,不额外触发 一轮 OPTIONS;flush 用于运维人员确认后立即移除指定注册。完整鉴权、请求、响应与错误语义见 apps/callflow-esl/docs/http-runtime-api.md。


4. external.xml 深度配置剖析 ​

配置文件路径:freeswitch-install/etc/freeswitch/sip_profiles/external.xml

xml
<profile name="external">
  <!--
      FreeSWITCH Sofia SIP 外部协议栈配置 (external.xml)
      =============================================================================
      定位与职责:
      1. 监听端口: 默认 5080 (UDP/TCP) 与 5081 (TLS)
      2. 核心用途: 对接外部电信运营商 SIP Trunk、IMS 核心网、企业 SBC 以及呼出中继网关
      3. 呼叫流向: 外部呼入的通话默认进入 public 拨号计划上下文 (context="public")
      4. 鉴权机制: 对外中继通常关闭 SIP Digest 认证 (auth-calls="false"),依靠网络层 IP ACL 白名单保障安全
      =============================================================================
  -->

  <!-- 外部网关加载入口: 引入 external/ 目录下配置的所有外部运营商 SIP 中继网关 -->
  <gateways>
    <X-PRE-PROCESS cmd="include" data="external/*.xml"/>
  </gateways>

  <domains>
    <domain name="all" alias="false" parse="true"/>
  </domains>

  <settings>
    <!-- SIP 调试与信令追踪 -->
    <param name="debug" value="0"/>
    <param name="sip-trace" value="no"/>
    <param name="sip-capture" value="no"/>

    <!-- RFC 2833 DTMF 载荷类型 (默认 101) -->
    <param name="rfc2833-pt" value="101"/>

    <!-- 1. SIP 信号与端口绑定: 外部 profile 默认采用 5080 端口,避开内部 5060 端口 -->
    <param name="sip-port" value="$${external_sip_port}"/>
    <param name="sip-ip" value="$${local_ip_v4}"/>
    <param name="rtp-ip" value="$${local_ip_v4}"/>

    <!-- 2. NAT 媒体与信令广告 -->
    <param name="ext-sip-ip" value="$${external_sip_ip}"/>
    <param name="ext-rtp-ip" value="$${external_rtp_ip}"/>

    <!-- 3. 安全隔离:关闭认证并将呼入路由引导至 public context -->
    <param name="auth-calls" value="false"/>                  <!-- 外部中继通常基于 IP 信任,关闭认证 -->
    <param name="context" value="public"/>                    <!-- 必须为 public context,隔离内部资源 -->

    <!-- 4. 编解码协商与软时钟 -->
    <param name="inbound-codec-prefs" value="$${global_codec_prefs}"/>
    <param name="outbound-codec-prefs" value="$${outbound_codec_prefs}"/>
    <param name="inbound-codec-negotiation" value="generous"/>
    <param name="inbound-late-negotiation" value="true"/>
    <param name="rtp-timer-name" value="soft"/>
    <param name="nonce-ttl" value="60"/>
  </settings>
</profile>

5. SIP Trunk 与级联网关配置实战 ​

FreeSWITCH 支持在 internal/ 与 external/ 两个 profile 下分别挂载网关:

5.1 内部级联与直连网关 (sip_profiles/internal/*.xml) ​

用于多台 FreeSWITCH 内部级联、私网 SBC 旁路直连或微服务集群内 SIP 路由。 部署包中已预置配置模板 sip_profiles/internal/example.xml:

xml
<!-- freeswitch-install/etc/freeswitch/sip_profiles/internal/example.xml -->
<include>
  <!--
      【内部 SIP Trunk / 级联网关配置模板】
      此文件配置通过 internal profile (5060 端口) 对接的内部 SIP 网关或下游 FreeSWITCH 节点。
      免注册直连场景: proxy 填目标服务 IP 与端口,register 设为 false。
  -->
  <gateway name="local-freeswitch-internal">
    <!-- 目标 SIP 代理地址 (IP:Port) -->
    <param name="proxy" value="192.168.2.246:5060"/>
    <!-- 是否向该网关发起 SIP 注册 (对接内部系统通常为 false 免注册) -->
    <param name="register" value="false"/>
    <!-- 外呼时是否将呼入主叫号码透传在 From 标头中 (true 代表主叫透传) -->
    <param name="caller-id-in-from" value="true"/>
  </gateway>
</include>
  • 应用场景:两台 FreeSWITCH 分布在内网不同物理机上需要互通通话,或者通过本地 5060 免鉴权通道直连 AI 旁路媒体流;
  • 核心特点:挂载在 internal profile 下,走 5060 端口信令,register=false 实现基于网络互信的免注册直连;
  • 呼叫语法:sofia/gateway/local-freeswitch-internal/<被叫号码或分机>。

5.2 外部账号密码注册型网关 (Registration Trunk,sip_profiles/external/*.xml) ​

适用于需要向电信运营商 SIP 服务器发起 REGISTER 注册的线路:

xml
<!-- freeswitch-install/etc/freeswitch/sip_profiles/external/provider_register.xml -->
<include>
  <gateway name="my_provider_reg">
    <!-- 运营商 SIP 服务器地址/域名 -->
    <param name="realm" value="sip.provider.com"/>
    <!-- 认证账号与密码 -->
    <param name="username" value="88001234"/>
    <param name="password" value="YourPasswordHere"/>
    <!-- 是否主动向运营商发送 REGISTER 注册包 -->
    <param name="register" value="true"/>
    <!-- 传输协议:udp / tcp / tls -->
    <param name="register-transport" value="udp"/>
    <!-- 注册失败重试间隔(秒) -->
    <param name="retry-seconds" value="30"/>
    <!-- 定时心跳 OPTIONS 检测周期(秒),保持链路存活 -->
    <param name="ping" value="25"/>
    <param name="ping-max" value="3"/>
    <!-- 将真实主叫号码填入 SIP From 头域 -->
    <param name="caller-id-in-from" value="true"/>
    <!-- 呼入时将主叫引导的分机号 -->
    <param name="extension" value="5000"/>
  </gateway>
</include>

5.3 外部 IP 白名单免注册型中继 (IP Peering Trunk,sip_profiles/external/*.xml) ​

适用于企业专线或云通信平台(基于双方公网 IP 互信,无需发送 REGISTER 报文):

xml
<!-- freeswitch-install/etc/freeswitch/sip_profiles/external/provider_ip_trunk.xml -->
<include>
  <gateway name="carrier_ip_trunk">
    <!-- 运营商公网网关 IP 与端口 -->
    <param name="realm" value="203.0.113.50:5060"/>
    <!-- 免注册模式 -->
    <param name="register" value="false"/>
    <!-- 呼叫时向对端展示的主叫域名 -->
    <param name="from-domain" value="203.0.113.50"/>
    <!-- 定时心跳探测 -->
    <param name="ping" value="30"/>
    <param name="caller-id-in-from" value="true"/>
  </gateway>
</include>

呼叫语法说明: 在 callflow-esl 发起外呼或在 Dialplan 中桥接外线时,呼叫字符串语法为: sofia/gateway/<gateway_name>/<被叫手机号> 例如:sofia/gateway/carrier_ip_trunk/13800138000。


6. IPv6 Profiles 处理说明 ​

安装包包含 internal-ipv6.xml 与 external-ipv6.xml。在仅支持纯 IPv4 的环境中,如不需要监听 IPv6,可在 freeswitch-install/etc/freeswitch/autoload_configs/sofia.conf.xml 中将对应 XML include 行注释或移除:

xml
<configuration name="sofia.conf" description="sofia Endpoint">
  <profiles>
    <X-PRE-PROCESS cmd="include" data="../sip_profiles/internal.xml"/>
    <X-PRE-PROCESS cmd="include" data="../sip_profiles/external.xml"/>
    <!-- 纯 IPv4 环境可禁用 IPv6 profile:
    <X-PRE-PROCESS cmd="include" data="../sip_profiles/internal-ipv6.xml"/>
    <X-PRE-PROCESS cmd="include" data="../sip_profiles/external-ipv6.xml"/>
    -->
  </profiles>
</configuration>

7. sip_profiles 动态运维与诊断管理指令速查 ​

修改 sip_profiles/ 配置文件或新增网关后,无需重启容器,直接在宿主机通过 fs_cli 执行热管理:

运维场景fs_cli 执行指令说明
查看所有 Profile 概要sofia status查看 internal/external 的监听 IP、端口、运行状态及活跃呼叫数
查看 internal 详细状态sofia status profile internal查看已注册用户数、监听 URL、绑定的 Codec 与 ACL 配置
查看 external 详细状态sofia status profile external查看外部监听端口及所有已加载的 Gateway 列表
查看所有网关注册状态sofia status gateway列出所有网关的在线注册状态(REGED 表示注册成功,NOREG 表示无需注册)
查看指定网关注册详情sofia status gateway <gateway_name>查看运营商网关的具体注册响应状态码(如 200 OK、403 Forbidden)
热加载新增/修改的网关sofia profile external rescan
sofia profile internal rescan
重新扫描 sip_profiles/external/ 或 internal/ 目录,无缝上线新网关(零中断)
重新发起指定网关注册sofia profile external register <gateway_name>强制向运营商网关重新发起一次 SIP REGISTER 注册
注销指定网关sofia profile external unregister <gateway_name>卸载并注销指定网关
重启 internal Profilesofia profile internal restart重启 internal SIP 协议栈(会断开当前 internal 会话)
重启 external Profilesofia profile external restart重启 external SIP 协议栈并重新发起全部网关注册
实时抓取 SIP 信令报文sofia profile internal siptrace on
sofia profile external siptrace on
在 fs_cli 终端实时打印 SIP INVITE / REGISTER / ACK / 200 OK 报文
停止 SIP 信令报文抓取sofia profile internal siptrace off关闭实时报文打印

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