| 知乎专栏 |
cp /etc/freeswitch/vars.xml{,.backup}
cp /etc/freeswitch/sip_profiles/internal.xml{,.backup}
cp /etc/freeswitch/sip_profiles/external.xml{,.backup}
cp /etc/freeswitch/dialplan/default.xml{,.backup}
cp /etc/freeswitch/dialplan/public.xml{,.backup}
cp /etc/freeswitch/tls/wss.pem{,.backup}
修改默认密码
<X-PRE-PROCESS cmd="set" data="default_password=13113668890" />
配置SIP域
<X-PRE-PROCESS cmd="set" data="domain=pbx.netkiller.cn"/>
监听端口修改未 5061
<X-PRE-PROCESS cmd="set" data="internal_sip_port=5061"/>
<extension name="Local_Extension">
<condition field="destination_number" expression="^(1\d{2,3}|46\d{5})$">
<action application="export" data="dialed_extension=$1"/>
<!-- bind_meta_app can have these args <key> [a|b|ab] [a|b|o|s] <app> -->
<action application="bind_meta_app" data="1 b s execute_extension::dx XML features"/>
<action application="bind_meta_app" data="2 b s record_session::$${recordings_dir}/${caller_id_number}.${strftime(%Y-%m-%d-%H-%M-%S)}.wav"/>
<action application="bind_meta_app" data="3 b s execute_extension::cf XML features"/>
<action application="bind_meta_app" data="4 b s execute_extension::att_xfer XML features"/>
<action application="set" data="ringback=${us-ring}"/>
<action application="set" data="transfer_ringback=$${hold_music}"/>
<action application="set" data="call_timeout=30"/>
<!-- <action application="set" data="sip_exclude_contact=${network_addr}"/> -->
<action application="set" data="hangup_after_bridge=true"/>
<!--<action application="set" data="continue_on_fail=NORMAL_TEMPORARY_FAILURE,USER_BUSY,NO_ANSWER,TIMEOUT,NO_ROUTE_DESTINATION"/> -->
<action application="set" data="continue_on_fail=true"/>
<action application="hash" data="insert/${domain_name}-call_return/${dialed_extension}/${caller_id_number}"/>
<action application="hash" data="insert/${domain_name}-last_dial_ext/${dialed_extension}/${uuid}"/>
<action application="set" data="called_party_callgroup=${user_data(${dialed_extension}@${domain_name} var callgroup)}"/>
<action application="hash" data="insert/${domain_name}-last_dial_ext/${called_party_callgroup}/${uuid}"/>
<action application="hash" data="insert/${domain_name}-last_dial_ext/global/${uuid}"/>
<!--<action application="export" data="nolocal:rtp_secure_media=${user_data(${dialed_extension}@${domain_name} var rtp_secure_media)}"/>-->
<action application="hash" data="insert/${domain_name}-last_dial/${called_party_callgroup}/${uuid}"/>
<action application="bridge" data="user/${dialed_extension}@${domain_name}"/>
<action application="answer"/>
<action application="sleep" data="1000"/>
<action application="bridge" data="loopback/app=voicemail:default ${domain_name} ${dialed_extension}"/>
</condition>
</extension>
[root@netkiller ~]# cat autoload_configs/sofia.conf.xml
<configuration name="sofia.conf" description="sofia Endpoint">
<global_settings>
<param name="log-level" value="0"/>
<!-- <param name="abort-on-empty-external-ip" value="true"/> -->
<!-- <param name="auto-restart" value="false"/> -->
<param name="debug-presence" value="0"/>
<!-- <param name="capture-server" value="udp:homer.domain.com:5060"/> -->
<!--
the new format for HEPv2/v3 and capture ID
protocol:host:port;hep=2;capture_id=200;
-->
<!-- <param name="capture-server" value="udp:homer.domain.com:5060;hep=3;capture_id=100"/> -->
</global_settings>
<!--
The rabbit hole goes deep. This includes all the
profiles in the sip_profiles directory that is up
one level from this directory.
-->
<profiles>
<X-PRE-PROCESS cmd="include" data="../sip_profiles/*.xml"/>
</profiles>
</configuration>
[root@netkiller ~]# mv /etc/freeswitch/sip_profiles/external.xml /etc/freeswitch/sip_profiles/external.xml.backup [root@netkiller ~]# mv /etc/freeswitch/sip_profiles/external-ipv6.xml /etc/freeswitch/sip_profiles/external-ipv6.xml.backup
[root@netkiller ~]# docker exec -it freeswitch fs_cli -x "sofia status profile external" Invalid Profile! [root@netkiller ~]# ss -lnt| grep 5080
[root@netkiller ~]# vim /etc/freeswitch/sip_profiles/internal.xml <param name="aggressive-nat-detection" value="true"/>
[root@netkiller freeswitch]# docker exec -it freeswitch fs_cli -x "sofia status profile internal" ================================================================================================= Name internal Domain Name N/A Auto-NAT false DBName sofia_reg_internal Pres Hosts sip.netkiller.cn,172.22.11.170 Dialplan XML Context public Challenge Realm auto_from RTP-IP 172.22.11.170 Ext-RTP-IP 47.112.9.199 SIP-IP 172.22.11.170 Ext-SIP-IP 47.112.9.199 URL sip:mod_sofia@47.112.9.199:5061 BIND-URL sip:mod_sofia@47.112.9.199:5061;maddr=172.22.11.170;transport=udp,tcp WS-BIND-URL sip:mod_sofia@172.22.11.170:5066;transport=ws WSS-BIND-URL sips:mod_sofia@172.22.11.170:7443;transport=wss HOLD-MUSIC local_stream://moh OUTBOUND-PROXY N/A CODECS IN OPUS,G722,PCMU,PCMA,H264,VP8 CODECS OUT OPUS,G722,PCMU,PCMA,H264,VP8 TEL-EVENT 101 DTMF-MODE rfc2833 CNG 13 SESSION-TO 0 MAX-DIALOG 0 MAX-RECV-RPS 1000 NOMEDIA false LATE-NEG true PROXY-MEDIA false AGGRESSIVENAT true CALLS-IN 0 FAILED-CALLS-IN 0 CALLS-OUT 0 FAILED-CALLS-OUT 0 REGISTRATIONS 0 [root@netkiller ~]# ss -lnt| grep 5080
[root@netkiller freeswitch]# docker exec -it freeswitch fs_cli -x "sofia status profile internal reg" Registrations: ================================================================================================= Call-ID: IYijpAe8k7x7HOsdS36W28VNHrYa30yB User: 1000@sip.netkiller.cn Contact: "Neo" <sip:1000@113.80.25.220:18621;ob> Agent: Telephone 1.6 Status: Registered(UDP)(unknown) EXP(2026-09-20 02:53:09) EXPSECS(274) Ping-Status: Reachable Ping-Time: 0.00 Host: iZwz91c64odbewa32r2or7Z IP: 113.80.25.220 Port: 18621 Auth-User: 1000 Auth-Realm: sip.netkiller.cn MWI-Account: 1000@sip.netkiller.cn Total items returned: 1 =================================================================================================
openssl s_client -connect webrtc.netkiller.cn:443
检查 HTTP/1.1 101 Switching Protocols,正确响应应该是 HTTP/1.1 101 Switching Protocols。
root@spiritcloudp ~# curl --http1.1 -i -N \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
https://sip.netkiller.cn
HTTP/1.1 101 Switching Protocols
Alt-Svc: h3=":443"; ma=2592000
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Server: Caddy
Upgrade: websocket
Date: Sun, 20 Sep 2026 10:47:15 GMT
Verto 配置文件
[root@netkiller freeswitch]# cat autoload_configs/verto.conf.xml
<configuration name="verto.conf" description="HTML5 Verto Endpoint">
<settings>
<param name="debug" value="0"/>
<!-- <param name="kslog" value="true"/> -->
<!-- seconds to wait before hanging up a disconnected channel -->
<!-- <param name="detach-timeout-sec" value="120"/> -->
<!-- enable broadcasting all FreeSWITCH events in Verto -->
<!-- <param name="enable-fs-events" value="false"/> -->
<!-- enable broadcasting FreeSWITCH presence events in Verto -->
<!-- <param name="enable-presence" value="true"/> -->
</settings>
<profiles>
<profile name="default-v4">
<param name="bind-local" value="$${local_ip_v4}:8081"/>
<param name="bind-local" value="$${local_ip_v4}:8082" secure="true"/>
<param name="force-register-domain" value="$${domain}"/>
<param name="secure-combined" value="$${certs_dir}/wss.pem"/>
<param name="secure-chain" value="$${certs_dir}/wss.pem"/>
<param name="userauth" value="true"/>
<!-- setting this to true will allow anyone to register even with no account so use with care -->
<param name="blind-reg" value="false"/>
<param name="mcast-ip" value="224.1.1.1"/>
<param name="mcast-port" value="1337"/>
<param name="rtp-ip" value="$${local_ip_v4}"/>
<param name="ext-rtp-ip" value="$${external_rtp_ip}"/>
<param name="local-network" value="localnet.auto"/>
<param name="outbound-codec-string" value="opus,h264,vp8"/>
<param name="inbound-codec-string" value="opus,h264,vp8"/>
<param name="apply-candidate-acl" value="localnet.auto"/>
<param name="apply-candidate-acl" value="wan_v4.auto"/>
<param name="apply-candidate-acl" value="rfc1918.auto"/>
<param name="apply-candidate-acl" value="any_v4.auto"/>
<param name="timer-name" value="soft"/>
</profile>
<profile name="default-v6">
<param name="bind-local" value="[$${local_ip_v6}]:8081"/>
<param name="bind-local" value="[$${local_ip_v6}]:8082" secure="true"/>
<param name="force-register-domain" value="$${domain}"/>
<param name="secure-combined" value="$${certs_dir}/wss.pem"/>
<param name="secure-chain" value="$${certs_dir}/wss.pem"/>
<param name="userauth" value="true"/>
<!-- setting this to true will allow anyone to register even with no account so use with care -->
<param name="blind-reg" value="false"/>
<param name="rtp-ip" value="$${local_ip_v6}"/>
<!-- <param name="ext-rtp-ip" value=""/> -->
<param name="outbound-codec-string" value="opus,h264,vp8"/>
<param name="inbound-codec-string" value="opus,h264,vp8"/>
<param name="apply-candidate-acl" value="wan_v6.auto"/>
<param name="apply-candidate-acl" value="rfc1918.auto"/>
<param name="apply-candidate-acl" value="any_v6.auto"/>
<param name="apply-candidate-acl" value="wan_v4.auto"/>
<param name="apply-candidate-acl" value="any_v4.auto"/>
<param name="timer-name" value="soft"/>
</profile>
</profiles>
</configuration>
[root@netkiller freeswitch]# grep -r mod_verto * autoload_configs/modules.conf.xml: <load module="mod_verto"/> [root@netkiller freeswitch]# grep -r mod_rtc * autoload_configs/modules.conf.xml: <load module="mod_rtc"/>
禁用 SSL
<param name="bind-local" value="$${local_ip_v4}:8082" secure="false"/>
# 解除模块 docker exec -it freeswitch fs_cli -x "unload mod_signalwire" # 查看所有SIP profile的状态 docker exec -it freeswitch fs_cli -x "sofia status" # 查看某个profile的详细信息(如internal或external) docker exec -it freeswitch fs_cli -x "sofia status profile internal" # 查看 internal profile 下的所有注册用户信息(已注册的终端列表) docker exec -it freeswitch fs_cli -x "sofia status profile internal reg" # 重新加载XML配置(包括用户、拨号计划等) docker exec -it freeswitch fs_cli -x "reloadxml" # 列出当前所有正在运行的会议室及相关信息 docker exec -it freeswitch fs_cli -x "conference list" # 挂断指定UUID的通话 docker exec -it freeswitch fs_cli -x "uuid_kill <uuid>" # 显示当前所有活动的通道(channels),包括呼叫详情 docker exec -it freeswitch fs_cli -x "show channels" # 查看指定 UUID 的通道详细信息,UUID 是通话的唯一标识符 docker exec -it freeswitch fs_cli -x "uuid_dump 44e97f0b-bc3c-41d8-9929-936a890c3cb4" # 使用 Lua 脚本 dissolve_conference.lua 解散会议室,参数是会议室ID和发起者IP(这里示例是会议室12345,IP 154.11.80.119) docker exec -it freeswitch fs_cli -x "luarun dissolve_conference.lua 12345-154.11.80.119"
[root@testing default]# docker exec -it freeswitch fs_cli -x "sofia status"
Name Type Data State
=================================================================================================
external-ipv6 profile sip:mod_sofia@[2408:4003:1150:2600:5ec0:2ed4:4199:547e]:5080 RUNNING (0)
172.22.11.164 alias internal ALIASED
external profile sip:mod_sofia@120.79.201.161:5080 RUNNING (0)
external::example.com gateway sip:joeuser@example.com NOREG
internal-ipv6 profile sip:mod_sofia@[2408:4003:1150:2600:5ec0:2ed4:4199:547e]:5060 RUNNING (0)
internal profile sip:mod_sofia@120.79.201.161:5060 RUNNING (0)
=================================================================================================
4 profiles 1 alias
[root@netkiller ~]# docker exec -it freeswitch fs_cli -x "sofia status profile internal" ================================================================================================= Name internal Domain Name N/A Auto-NAT false DBName sofia_reg_internal Pres Hosts pbx.netkiller.cn,172.22.11.164 Dialplan XML Context public Challenge Realm auto_from RTP-IP 172.22.11.164 Ext-RTP-IP 120.79.201.161 SIP-IP 172.22.11.164 Ext-SIP-IP 120.79.201.161 URL sip:mod_sofia@120.79.201.161:5060 BIND-URL sip:mod_sofia@120.79.201.161:5060;maddr=172.22.11.164;transport=udp,tcp TLS-URL sip:mod_sofia@120.79.201.161:5061 TLS-BIND-URL sips:mod_sofia@120.79.201.161:5061;maddr=172.22.11.164;transport=tls WS-BIND-URL sip:mod_sofia@172.22.11.164:5066;transport=ws WSS-BIND-URL sips:mod_sofia@172.22.11.164:7443;transport=wss HOLD-MUSIC local_stream://moh OUTBOUND-PROXY N/A CODECS IN OPUS,G722,PCMU,PCMA,H264,VP8 CODECS OUT OPUS,G722,PCMU,PCMA,H264,VP8 TEL-EVENT 101 DTMF-MODE rfc2833 CNG 13 SESSION-TO 0 MAX-DIALOG 0 MAX-RECV-RPS 1000 NOMEDIA false LATE-NEG true PROXY-MEDIA false AGGRESSIVENAT false CALLS-IN 43 FAILED-CALLS-IN 43 CALLS-OUT 0 FAILED-CALLS-OUT 0 REGISTRATIONS 4
查看注册情况
[root@netkiller ~]# docker exec -it freeswitch fs_cli -x "sofia status profile internal reg" Registrations: ================================================================================================= Call-ID: 4640d1c4-68b2ec4e@192.168.23.21 User: 1720@pbx.netkiller.cn Contact: "1720" <sip:1720@100.64.56.237:65477;fs_nat=yes;fs_path=sip%3A1720%40183.14.132.54%3A17945> Agent: Linksys/PAP2T-5.1.6(LS) Status: Registered(UDP-NAT)(unknown) EXP(2026-02-10 03:17:18) EXPSECS(860) Ping-Status: Reachable Ping-Time: 0.00 Host: testing IP: 183.14.132.54 Port: 17945 Auth-User: 1720 Auth-Realm: pbx.netkiller.cn MWI-Account: 1720@pbx.netkiller.cn Call-ID: shfboftsbn9tnfnmk1ivib User: 4600442@pbx.netkiller.cn Contact: "" <sip:0ia9s501@qkr364fkldvi.invalid;transport=ws;fs_nat=yes;fs_path=sip%3A0ia9s501%40116.24.64.62%3A60193%3Btransport%3Dwss> Agent: JsSIP 3.13.4 Status: Registered(WSS-NAT)(unknown) EXP(2026-02-10 03:10:22) EXPSECS(444) Ping-Status: Reachable Ping-Time: 0.00 Host: testing IP: 116.24.64.62 Port: 60193 Auth-User: 4600442 Auth-Realm: pbx.netkiller.cn MWI-Account: 4600442@pbx.netkiller.cn Call-ID: 349CB636C2D53CDC0516A816AA744C0A8FFD08B0 User: 4600441@pbx.netkiller.cn Contact: "" <sip:4600441@172.16.0.24:43769;rinstance=402A5B8C;transport=tcp;fs_nat=yes;fs_path=sip%3A4600441%40183.14.29.46%3A34738%3Brinstance%3D402A5B8C%3Btransport%3Dtcp> Agent: Groundwire/5.3.6 (build 1431795; Android 8.1.0; arm64-v8a) Status: Registered(TCP-NAT)(unknown) EXP(2026-02-10 03:13:57) EXPSECS(659) Ping-Status: Reachable Ping-Time: 0.00 Host: testing IP: 183.14.29.46 Port: 34738 Auth-User: 4600441 Auth-Realm: pbx.netkiller.cn MWI-Account: 4600441@pbx.netkiller.cn Total items returned: 3 =================================================================================================