外观
FreeSWITCH SIP Profiles 架构、配置与外呼网关专题
本文详细剖析 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/*.xml | sip_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 旁路媒体流;
- 核心特点:挂载在
internalprofile 下,走 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 rescansofia profile internal rescan | 重新扫描 sip_profiles/external/ 或 internal/ 目录,无缝上线新网关(零中断) |
| 重新发起指定网关注册 | sofia profile external register <gateway_name> | 强制向运营商网关重新发起一次 SIP REGISTER 注册 |
| 注销指定网关 | sofia profile external unregister <gateway_name> | 卸载并注销指定网关 |
| 重启 internal Profile | sofia profile internal restart | 重启 internal SIP 协议栈(会断开当前 internal 会话) |
| 重启 external Profile | sofia profile external restart | 重启 external SIP 协议栈并重新发起全部网关注册 |
| 实时抓取 SIP 信令报文 | sofia profile internal siptrace onsofia profile external siptrace on | 在 fs_cli 终端实时打印 SIP INVITE / REGISTER / ACK / 200 OK 报文 |
| 停止 SIP 信令报文抓取 | sofia profile internal siptrace off | 关闭实时报文打印 |