FreeSWITCH呼入呼出配置实战:SIP中继与拨号计划避坑指南
发布时间:2026/10/24 18:17:43 锦皓数字建站

简介这份文档面向使用 Freeswitch 搭建 VoIP 通信平台的运维与开发人员聚焦呼入呼出路由配置这一关键环节帮助读者理清拨号计划、SIP 中继与对等中继模式下的外呼实现思路。资源包内共 1 个 doc 文件约 221KB内容围绕 Freeswitch 整体架构展开涵盖程序启动流程、消息分发机制、mod_sofia 模块组成与启动过程等核心知识点并配有术语定义与条目编号规范便于按模块查阅。文档以个人学习总结的形式梳理了系统介绍与组件架构适合作为理解 Freeswitch 内部运行机制、排查路由配置问题的参考材料。目前已有 6455 人学习下载对需要掌握呼入呼出路由与中继设置的初中级读者具有一定参考价值。1. 从一次“能注册不能呼出”的翻车说起上周帮一个做客服系统的朋友排查问题FreeSWITCH 装好了SIP 话机注册正常内部分机互拨也没毛病但一拨外线就静默挂断日志里连个像样的报错都没有。这种“能注册不能呼出”的场景几乎是每个刚接触 FreeSWITCH 的运维都会踩的坑——问题不在安装本身而在呼入呼出路由和 SIP 中继的配置没对齐。FreeSWITCH 这套软交换环境在呼叫中心、企业 PBX、语音通知系统里太常见了装不好轻则单通、回铃音丢失重则整个中继打满导致业务停摆。这篇笔记面向的是已经装完 FreeSWITCH、正卡在路由配置上的开发者从版本选择、模块加载、拨号计划到中继参数一步步把呼入呼出跑通最后给出验证方法和排错思路。我用的环境是 FreeSWITCH 1.2.7 这个老版本做参照新版 1.10.x 在目录结构和模块名上有差异文中会标注。2. 装前把环境列清版本、模块与目录约定2.1 版本选择与平台差异FreeSWITCH 的版本跨度很大1.2.7 是很多老项目还在跑的稳定版1.6 之后目录结构做了调整1.10.x 是目前社区维护的主力。选版本的核心原则是中继网关和 SIP 话机厂商的兼容性优先于版本新旧。我一般会先确认网关设备支持的 SIP 协议细节比如是否支持 RFC 2833 DTMF、是否强制要求 PRACK再决定用哪个 FreeSWITCH 版本。1.2.7 在 Windows 和 Linux 下都能跑Windows 平台的模块文件是mod_sofia.dll这种形式Linux 下是mod_sofia.so配置文件路径统一在安装目录的conf/下。跨平台支持是 FreeSWITCH 的设计目标之一Windows、Linux、BSD、Solaris 的 32 位和 64 位平台都在支持范围内但生产环境我建议用 LinuxWindows 下模块加载和路径处理容易出玄学问题。安装方式上源码编译能精确控制模块包管理器安装省事但模块裁剪不可控。源码编译的关键是modules.conf这个文件决定了哪些模块会被编译进系统。默认配置里mod_sofia是启用的但如果你用的是精简版安装包很可能这个模块根本没编进去后面配中继时就会发现sofia命令不存在。2.2 核心模块与 mod_sofia 的加载关系FreeSWITCH 的架构是核心加模块核心提供通用函数和状态机模块增强功能。SIP 相关的功能全部落在mod_sofia上它由 FreeSWITCH 的 SIP 应用层和底层的 Sofia-SIP 协议栈库组成。Sofia-SIP 本身分 NTA 和 NUA 两层FreeSWITCH 的 SIP 应用直接和 NUA 打交道NUA 再依赖 NTA 做事务处理。这个分层意味着你配的中继参数最终是传给 NUA 的而传输层用 UDP 还是 TCP 对应用层是透明的所以配中继时不用纠结底层传输重点在 NUA 层面的参数。模块加载由conf/autoload_configs/modules.conf控制。启动时 FreeSWITCH 先加载集成模块CORE_SOFTTIMER_MODULE、CORE_PCM_MODULE然后遍历modules.conf加载配置的模块再遍历post_load_modules.conf。如果这两个文件里配置的模块数为零才会从模块目录加载所有 mod。这个逻辑很关键——很多人改了modules.conf但没重启或者把mod_sofia注释掉了却以为还在加载结果中继死活起不来。configuration namemodules.conf descriptionModules modules !-- 日志类模块先加载方便排查后续模块问题 -- load modulemod_console/ load modulemod_logfile/ !-- SIP 端点模块呼入呼出全靠它 -- load modulemod_sofia/ !-- 拨号计划相关 -- load modulemod_dialplan_xml/ /modules /configuration这段配置里mod_console和mod_logfile放最前面是为了让后续模块的加载日志能落盘出问题时至少有日志可查。mod_sofia是 SIP 端点没有它就没有任何 SIP 能力。mod_dialplan_xml负责解析 XML 拨号计划呼入呼出的路由规则都写在拨号计划里。改完这个文件必须重启 FreeSWITCH热加载模块虽然支持但mod_sofia这种端点模块热加载容易残留旧状态我一般直接重启。2.3 目录结构与配置文件分布FreeSWITCH 的配置目录结构在 1.2.7 和 1.10.x 之间差异不大核心目录包括conf/autoload_configs/放自动加载的模块配置conf/dialplan/放拨号计划 XMLconf/sip_profiles/放 SIP 配置文件conf/directory/放用户目录。呼入呼出路由的配置主要落在dialplan/和sip_profiles/两个目录。sip_profiles/下的internal.xml和external.xml是两个默认的 SIP profile分别对应内部分机和外部中继。呼入路由的入口在dialplan/public.xml外呼路由的规则在dialplan/default.xml。这个分布不是随意的——public上下文处理来自外部中继的呼叫default上下文处理内部注册用户的呼叫。搞混这两个上下文就会出现“外线打进来进了内部拨号计划”或者“内部分机拨外线走了 public 上下文”的错乱。3. 配 SIP 中继对等中继模式的参数取舍3.1 中继配置文件的骨架SIP 中继是 FreeSWITCH 和网关设备之间的桥梁。对等中继模式peer trunk下FreeSWITCH 不向网关注册而是网关把呼叫直接送到 FreeSWITCH 的 IP 和端口FreeSWITCH 也直接把呼叫发往网关的 IP 和端口。这种模式省掉了注册开销但要求双方的 IP 和端口必须精确匹配。中继配置写在conf/sip_profiles/external.xml里核心是gateway节点。下面是一个对等中继的最小配置gateway namegw_pstn !-- 网关地址填对端设备的实际 IP -- param nameproxy value192.168.10.1/ !-- 对等模式不注册设为 false -- param nameregister valuefalse/ !-- 呼出时携带的主叫号码按网关要求填 -- param namecaller-id-in-from valuetrue/ !-- 传输协议网关支持 UDP 就用 UDP减少握手开销 -- param nametransport valueudp/ !-- 认证用户名和密码对等模式有些网关不校验但填上更稳妥 -- param nameusername valuefreeswitch/ param namepassword valueyour_password/ !-- 呼出前缀网关要求加拨特定号码时用 -- param nameprefix value/ /gatewayproxy是对端网关的地址对等模式下这是唯一必须精确匹配的地址。register设为false是对等中继和注册中继的分水岭——注册中继需要 FreeSWITCH 主动向网关发起 REGISTER 请求对等中继则是网关主动把呼叫推过来。caller-id-in-from控制主叫号码放在 From 头还是 P-Asserted-Identity 头不同网关要求不同配错了会出现“对方看不到主叫号码”的问题。transport选 UDP 还是 TCP 取决于网关能力UDP 延迟低但不可靠TCP 可靠但握手开销大语音场景一般用 UDP。3.2 呼出路由从拨号计划到网关呼出路由的本质是用户拨了一个号码拨号计划匹配到这个号码然后通过bridge应用把呼叫送到中继网关。拨号计划写在conf/dialplan/default.xml里下面是一个典型的外呼规则extension nameoutbound_pstn !-- 匹配以 0 开头的号码0 是外线前缀 -- condition fielddestination_number expression^0(\d)$ !-- 把前缀 0 去掉取后面的实际号码 -- action applicationset dataeffective_caller_id_number1001/ !-- 通过 gw_pstn 中继呼出$1 是正则捕获的号码 -- action applicationbridge datasofia/gateway/gw_pstn/$1/ /condition /extensiondestination_number的正则^0(\d)$匹配以 0 开头、后面跟数字的号码$1捕获的是去掉 0 之后的实际号码。effective_caller_id_number设置主叫号码这个号码会出现在网关看到的 From 头里填错了对方会拒接。bridge的格式是sofia/gateway/网关名/号码网关名必须和external.xml里gateway name...的名字一致写错了会报gateway not found。这里有个容易翻车的点拨号计划的上下文。default.xml属于default上下文只有内部注册用户发起的呼叫才会进这个上下文。如果外呼是从其他上下文发起的比如从 public 上下文转过来的这条规则不会生效。排查时先看日志里的context字段确认呼叫落在哪个上下文。3.3 呼入路由public 上下文的处理逻辑呼入路由处理的是从网关进来的呼叫。网关把呼叫送到 FreeSWITCH 的 external profile 后呼叫进入public上下文由conf/dialplan/public.xml处理。典型配置如下extension nameinbound_pstn !-- 匹配网关送来的被叫号码这里假设网关送的是完整号码 -- condition fielddestination_number expression^(\d)$ !-- 转接到内部注册用户 1001 -- action applicationtransfer data1001 XML default/ /condition /extensiontransfer应用把呼叫转到default上下文的 1001 分机XML default指定了拨号计划类型和上下文。这里的关键是public 上下文只负责“接进来”具体转给谁、怎么振铃交给 default 上下文处理。这种分层设计让呼入路由可以灵活组合——可以先查数据库决定转哪个分机也可以先放 IVR 再转人工。如果网关送来的号码带了前缀或者格式不标准正则要相应调整。比如网关送的是8613800138000这种带国家码的格式正则就得写成^86(\d)$捕获后再做号码变换。号码格式对不上是呼入失败最常见的原因日志里会显示No route to destination或者直接404。4. 避坑与排查五个真实踩过的坑4.1 坑一中继显示注册成功但呼出静默失败现象sofia status显示网关状态UP但拨外线后呼叫直接挂断日志里只有NORMAL_CLEARING没有更多信息。原因对等中继模式下register设成了trueFreeSWITCH 向网关发了 REGISTER 请求网关返回 200 让状态显示 UP但网关实际不处理这个注册呼出时 SIP 请求发过去被静默丢弃。对等中继和注册中继是两种模式混用会导致状态显示和实际能力不一致。解决确认网关的工作模式对等中继把register改成false注册中继才设true。改完重启mod_sofia或整个 FreeSWITCH再用sofia status gateway gw_pstn确认状态。4.2 坑二呼入能振铃但一接就断现象外线打进来内部分机正常振铃但一摘机通话立即断开日志显示MEDIA_TIMEOUT或CODEC_NEGOTIATION_FAILED。原因编码协商失败。网关只支持 G.711 A-law而 FreeSWITCH 的 profile 里配置的编码列表第一个是 G.729协商时双方找不到共同编码。G.729 需要授权没授权的 FreeSWITCH 根本编不了但配置里写了就会参与协商。解决在external.xml的 profile 设置里把inbound-codec-prefs和outbound-codec-prefs改成PCMA,PCMU确保 G.711 优先。改完用show codec确认可用编码列表没有授权的编码不要写进配置。4.3 坑三拨号计划改了不生效现象修改了default.xml里的外呼规则重启 FreeSWITCH 后新规则依然不生效旧规则还在跑。原因拨号计划有缓存mod_dialplan_xml加载后会缓存 XML 解析结果。只重启mod_sofia不会刷新拨号计划缓存必须执行reloadxml或者重启整个 FreeSWITCH。另外如果改的是public.xml但呼叫实际落在default上下文规则当然不生效。解决改完拨号计划后在控制台执行reloadxml然后用show dialplan确认规则已加载。排查时在日志里搜context确认呼叫实际落在哪个上下文上下文对不上就改对应的 XML 文件。4.4 坑四主叫号码丢失导致对方拒接现象外呼能接通但对方网关拒接或者接通后对方看不到主叫号码日志显示403 Forbidden。原因主叫号码的传递方式不匹配。有些网关要求主叫号码放在P-Asserted-Identity头有些要求放在From头caller-id-in-from参数配反了就会导致号码丢失。另外effective_caller_id_number没设置时FreeSWITCH 会用默认值默认值可能不符合网关要求。解决先抓包看 SIP 信令里主叫号码在哪个头再对照网关文档调整caller-id-in-from参数。拨号计划里显式设置effective_caller_id_number不要依赖默认值。抓包用tcpdump -i any -w call.pcap port 5060然后用 Wireshark 分析。4.5 坑五多中继场景下路由串线现象配了两条中继一条走 PSTN 网关一条走另一个 SIP 服务商结果外呼时随机走错线路有时能通有时不通。原因拨号计划的bridge里写死了网关名但多条规则的正则范围有重叠先匹配到的规则生效。比如^0(\d)$和^(\d)$两条规则后者会匹配所有号码如果它排在前面所有呼叫都会走它指定的网关。解决拨号计划的规则按精确度排序越精确的规则越靠前。用breakon-false控制条件匹配失败后的行为避免规则穿透。多中继场景下给每条规则加注释说明适用场景改的时候不容易搞混。5. 装完怎么验证从信令到语音的完整检查配置改完不代表跑通验证要分三层信令层、路由层、媒体层。信令层看 SIP 消息是否正常收发路由层看拨号计划是否匹配到正确规则媒体层看语音是否双向通。我一般按下面的顺序走一遍。先看模块和中继状态。控制台执行sofia status确认externalprofile 是RUNNING网关状态是UP或REGED取决于中继模式。如果 profile 没起来检查modules.conf里mod_sofia是否加载端口 5060 是否被占用。网关状态不对检查proxy地址和register参数。# 查看 sofia 整体状态 sofia status # 查看指定网关详情 sofia status gateway gw_pstn # 查看当前注册用户 sofia status profile internal reg这三条命令覆盖了中继和分机的基本状态。sofia status输出里重点看RUNNING和UP两个状态词任何一个不对都说明配置有问题。然后验证路由匹配。用originate命令模拟一次外呼不实际拨号只看路由是否匹配# 模拟从 1001 拨 013800138000只走路由不实际呼叫 originate user/1001 013800138000如果路由匹配成功日志里会显示bridge到sofia/gateway/gw_pstn/13800138000如果匹配失败会显示No route。这一步能快速定位是拨号计划的问题还是中继的问题。最后验证媒体。实际拨一通电话用uuid_record录制通话音频确认双向语音都有声音# 对指定通话录音确认媒体流正常 uuid_record uuid start /tmp/test_call.wav录完用播放器听一下只有单边声音说明媒体路由有问题通常是 NAT 或编码协商导致的。双向都没声音但信令正常检查rtp端口范围是否被防火墙拦截。验证通过的标准是sofia status全绿、originate路由匹配正确、实际通话双向语音清晰、DTMF 按键能被网关正确识别。这四项都过了呼入呼出才算真正跑通。从那以后我每次配完中继都会先用originate空跑一遍路由再实际拨测最后录音确认媒体三步缺一不可。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。