FreeSwitch 설치
- Debian 시스템에 문서에 따라 설치: https://developer.signalwire.com/freeswitch/FreeSWITCH-Explained/Installation/Linux/Debian_67240088
- 설치 후 클라이언트에 접속할 수 없는 경우 서비스 재시작:
service freeswitch restart - 설정 변경:
/etc/freeswitch/autoload_configs/event_socket.conf.xml, 확인 시 아래와 같이 이미 설정되어 있어 변경 불필요
<configuration name="event_socket.conf" description="Socket Client">
<settings>
<param name="nat-map" value="false"/>
<param name="listen-ip" value="0.0.0.0"/>
<param name="listen-port" value="8021"/>
<param name="password" value="ClueCon"/>
<!--<param name="apply-inbound-acl" value="loopback.auto"/>-->
<!--<param name="stop-on-bind-error" value="true"/>-->
</settings>
</configuration>
- 설정 변경:
/etc/freeswitch/sip_profiles/internal.xml
<param name="ext-rtp-ip" value="외부 IP 주소"/>
<param name="ext-sip-ip" value="외부 IP 주소"/>
- 명령줄 접속
fs_cli -rRS # 정상적으로 접속 가능하면 서비스가 시작된 것입니다. -p 매개변수로 비밀번호를 지정할 수 있습니다.
- 설정 변경 시 다시 로드 필요:
reloadxml - SIP 요청 및 fs 상호작용을 위한 몇 가지 Go 언어 패키지:
github.com/fiorix/go-eventsocket/eventsocket
github.com/cloudwebrtc/go-sip-ua
# fs 공식 웹사이트에서 제공하는 상호작용 라이브러리
github.com/0x19/goesl
- 설치 후 코드 연결 시 오류:
[WARNING] mod_event_socket **** Rejected by acl "loopback.auto"/etc/freeswitch/autoload_configs/event_socket.conf.xml파일의 주석 해제
<param name="apply-inbound-acl" value="loopback.auto"/>
다음으로 /etc/freeswitch/autoload_configs/acl.conf.xml 파일에 다음과 같이 추가하면, 통화 클라이언트에 소리가 나지 않게 됩니다.
<list name="loopback.auto" default="allow">
<node type="allow" domain="허용할 IP/24"/>
</list>
- fs 서비스 재시작:
service freeswitch restart
reload mod_event_socket
- 등록된 사용자 확인
sofia status profile internal reg
- fs 이벤트 메시지 본문 내용 (JSON 형식으로 변환 후)
{
"Headers": {
"Core-UUID": "0e78f0dd-a2d7-4895-beb8-c1f1277614b7",
"Event-Calling-File": "switch_scheduler.c",
"Event-Calling-Function": "switch_scheduler_execute",
"Event-Calling-Line-Number": "73",
"Event-Date-GMT": "Mon, 22 Apr 2024 01:56:29 GMT",
"Event-Date-Local": "2024-04-22 09:56:29",
"Event-Date-Timestamp": "1713750989490904",
"Event-Name": "RE_SCHEDULE",
"Event-Sequence": "60059",
"FreeSWITCH-Hostname": "ali-person",
"FreeSWITCH-IPv4": "172.25.54.1",
"FreeSWITCH-IPv6": "::1",
"FreeSWITCH-Switchname": "ali-person",
"Task-Desc": "heartbeat",
"Task-Group": "core",
"Task-ID": "1",
"Task-Runtime": "1713751009"
},
"Body": ""
}
- 클라우드 서버 사용 시 많은 SIP 요청 발견. 서버 보안 그룹에서 접속 IP 제한 후 fs 로그가 순식간에 정리됨.
- 기본 매개변수 값(비밀번호, 도메인, 포트 등)의 설정 파일 위치:
/etc/freeswitch/vars.xml - 사용자 디렉토리:
/etc/freeswitch/directory/default
통화 문제 해결
다음과 같은 설정으로 휴대폰으로 컴퓨터에 전화할 수 있으며, 휴대폰에서 소리를 들을 수 있습니다. Mac 컴퓨터에는 소리가 나지 않지만 Windows 클라이언트에는 소리가 납니다.
1.conf/vars.xml수정
<X-PRE-PROCESS cmd="stun-set" data="external_rtp_ip=공인IP"/>
<X-PRE-PROCESS cmd="stun-set" data="external_sip_ip=공인IP"/>
공인IP가 없는 경우 공인IP는 stun:stun.freeswitch.org 사용
conf/sip_profiles/internal.xml,conf/sip_profiles/external.xml수정
<param name="ext-rtp-ip" value="$${external_rtp_ip}"/>
<param name="ext-sip-ip" value="$${external_rtp_ip}"/>
autoload_configs/acl.conf.xml수정
다음 부분은 반드시 제거해야 합니다:
</list> <list name="localnet.auto" default="allow"> </list>
sip_profiles/internal.xml수정
<param name="apply-candidate-acl" value="rfc1918.auto"/>
<param name="apply-candidate-acl" value="localnet.auto"/>
테스트 명령어
- 먼저 1002에 전화하여 닉네임과 번호를 mike, 186으로 표시하고, 1001과 연결합니다. 표시할 닉네임은 jimmy, 번호는 139로 지정합니다.
originate {origination_caller_id_name="mike",origination_caller_id_number=18612345678,originate_timeout=10}user/1002 &bridge({origination_caller_id_name=jimmy,origination_caller_id_number=139****666,originate_timeout=3}user/1001)
간단한 예시:
originate user/1002 &bridge(user/1001)
- IP와 포트에 접속 가능한지 확인
nc -zv 120.197.67.50 5960
특정 IP의 포트가 열리지 않을 경우, 해당 IP에서 등록된 계정으로는 fs 측에서 IP와 포트로 통화할 수 없습니다.
originate {origination_caller_id_number=123456}sofia/external/sip:1001@120.197.67.50:5960 &echo
하지만 내선 번호로 통화는 가능하며, fs는 NAT 트래버설을 통해 통화할 수 있습니다.
originate user/1001 &echo
- 발신자 번호 02180484276으로, 39.100.136.113:5060을 통해 176 번호로 전화
originate {origination_caller_id_number=02180484276}sofia/external/17620161458@39.100.136.113:5060 &echo
ESL(Event Socket Library) 설정
이전의 ESL 활성화 로직에는 문제가 있습니다. /etc/freeswitch/autoload_configs/acl.conf.xml 파일을 수정하지 마시고, 대신 /etc/freeswitch/autoload_configs/event_socket.conf.xml을 다음과 같이 수정하세요:
<configuration name="event_socket.conf" description="Socket Client">
<settings>
<param name="nat-map" value="false"/>
<param name="listen-ip" value="0.0.0.0"/>
<param name="listen-port" value="8021"/>
<param name="password" value="ClueCon"/>
<param name="apply-inbound-acl" value="lan"/>
<param name="enable-heartbeat" value="true"/>
<param name="heartbeat-interval" value="20"/>
<param name="heartbeat-event-details" value="true"/>
</settings>
</configuration>
모듈 관리
- 로드된 모듈 확인
fs_cli -x 'show modules'
출력 예시를 통해 설치 디렉토리가 /usr/lib/freeswitch/mod/임을 알 수 있습니다:
file,vox,mod_sndfile,/usr/lib/freeswitch/mod/mod_sndfile.so
file,w64,mod_sndfile,/usr/lib/freeswitch/mod/mod_sndfile.so
file,wav,mod_sndfile,/usr/lib/freeswitch/mod/mod_sndfile.so
file,webm,mod_av,/usr/lib/freeswitch/mod/mod_av.so
file,wve,mod_sndfile,/usr/lib/freeswitch/mod/mod_sndfile.so
file,xi,mod_sndfile,/usr/lib/freeswitch/mod/mod_sndfile.so
generic,mod_logfile,mod_logfile,/usr/lib/freeswitch/mod/mod_logfile.so
json_api,channelData,mod_commands,/usr/lib/freeswitch/mod/mod_commands.so
ls -al /usr/lib/freeswitch/mod/를 실행하면 컴파일된 모듈을 볼 수 있으며, 이를 통해 build/modules.conf.in 패킹 설정 파일을 수정했는지 확인할 수 있습니다. 예를 들어, xml_int/mod_xml_curl 이행을 활성화하면 모듈 디렉토리에 mod_xml_curl.so 파일이 있습니다.
mod_xml_curl모듈 로드
fs_cli -x "reload mod_xml_curl"
오류 발생 시:
2025-06-05 10:34:00.209734 98.23% [INFO] switch_time.c:1436 Timezone reloaded 597 definitions
2025-06-05 10:34:00.209734 98.23% [ERR] mod_xml_curl.c:476 Binding has no url!
2025-06-05 10:34:00.209734 98.23% [CRIT] switch_loadable_module.c:1754 Error Loading module /usr/lib/freeswitch/mod/mod_xml_curl.so
**Module load routine returned an error**
테스트 단계에서 서비스가 먼저 시작되도록 하려면, /etc/freeswitch/autoload_configs/xml_curl.conf.xml 설정을 다음과 같이 합니다:
<configuration name="xml_curl.conf" description="cURL XML Gateway">
<bindings>
<binding name="directory">
<param name="gateway-url" value="http://127.0.0.1:9000/test.xml" bindings="directory"/>
</binding>
</bindings>
</configuration>
HTTP 서비스를 실행하기 위해 Python 사용:
cd /tmp
python3 -m http.server 9000
/tmp/test.xml 내용:
<document type="freeswitch/xml">
<section name="directory"/>
</document>
이렇게 설정하면 fs_cli -x "reload mod_xml_curl"을 실행하면 다음과 같은 로그가 표시됩니다:
2025-06-05 10:46:23.169742 97.87% [CONSOLE] switch_loadable_module.c:1772 Successfully Loaded [mod_xml_curl]
2025-06-05 10:46:23.169742 97.87% [NOTICE] switch_loadable_module.c:389 Adding API Function 'xml_curl'
확인: fs_cli -x "module_exists mod_xml_curl"도 true를 반환합니다.
mod_unimrcp 모듈 설치
- 문서에 따라 mod_unimrcp 컴파일 설치
오류 발생: configure: error: no acceptable C compiler found in $PATH
실행:
apt update
apt install build-essential
오류 발생: ./bootstrap.sh: line 2: autoreconf: command not found
실행:
apt update
apt install autoconf automake libtool
- apr 및 apr-utils 설치 시 오류
$ sudo apt-get install wget tar
$ wget https://www.unimrcp.org/project/component-view/unimrcp-deps-1-6-0-tar-gz/download -O unimrcp-deps-1.6.0.tar.gz
$ tar xvzf unimrcp-deps-1.6.0.tar.gz
$ cd unimrcp-deps-1.6.0
$ cd libs/apr
$ ./configure --prefix=/usr/local/apr
$ make
$ sudo make install
$ cd ..
$ cd apr-util
$ ./configure --prefix=/usr/local/apr
$ make
$ sudo make install
$ cd ..
$ git clone https://github.com/unispeech/unimrcp.git
$ cd unimrcp
$ ./bootstrap
$ ./configure
$ make
$ sudo make install
$ cd ..
cd apr-util 및 ./configure --prefix=/usr/local/apr 실행 시 오류:
오류: configure: error: APR could not be located. Please use the --with-apr option.
apr 지정:
./configure --prefix=/usr/local/apr --with-apr=/usr/local/apr
GitHub 문서:
$ git clone https://github.com/unispeech/unimrcp.git
$ cd unimrcp
$ ./bootstrap
$ ./configure
$ make
$ sudo make install
$ cd ..
이전에 deb를 통해 설치한 sofa는 /usr/local이 아닌 /usr/lib에 있으므로, sofa 경로를 지정해야 합니다: ./configure --with-sofia-sip=/usr. 이렇게 하면 sofa를 찾을 수 없는 오류가 발생하지 않습니다. 문서 https://www.freeswitch.org.cn/books/case-study/1.8-为freeswitch安装mod_unimrcp模块.html가 올바릅니다.
마지막으로 mod_unimrcp 설치:
git clone https://github.com/freeswitch/mod_unimrcp.git
cd mod_unimrcp
export PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig:$PKG_CONFIG_PATH
./bootstrap.sh
./configure
make
sudo make install
사용자 등록 확인 템플릿
사용자 동적 로그인 등록에 사용할 수 있지만, auth-acl에서 IP 약 30개 이상이면 오류가 발생합니다. 10개 정도는 문제없습니다.
<document type="freeswitch/xml">
<section name="directory">
<domain name="172.20.11.54">
<user id="2090">
<params>
<param name="password" value="E3rg&Fn8k"></param>
<param name="vm-password" value="2090"></param>
<param name="dial-string" value="{^^:sip_invite_domain=${dialed_domain}:presence_id=${dialed_user}@${dialed_domain}}${sofia_contact(*/${dialed_user}@${dialed_domain})},${verto_contact(${dialed_user}@${dialed_domain})}"></param>
<param name="auth-acl" value="119.131.183.236/32,119.131.178.109/32,120.24.50.157/32,119.131.180.56/32,119.131.178.14/32,119.131.171.5/32,119.131.170.163/32,119.131.168.71/32,119.130.58.7/32,180.102.181.176/32,119.131.179.99/32,119.131.182.154/32,119.131.179.14/32,119.131.199.162/32,119.131.182.143/32,119.131.181.157/32,119.131.171.221/32,180.109.104.79/32,119.131.181.70/32,119.131.183.191/32,120.197.67.50/32,121.89.217.24/32,39.103.206.129/32,39.103.167.108/32,39.98.237.145/32,120.197.67.50/32"></param>
</params>
<variables>
<variable name="toll_allow" value="domestic,international,local"></variable>
<variable name="accountcode" value="2090"></variable>
<variable name="user_context" value="default"></variable>
<variable name="effective_caller_id_name" value="Extension 2090"></variable>
<variable name="effective_caller_id_number" value="2090"></variable>
<variable name="outbound_caller_id_name" value="$${outbound_caller_name}"></variable>
<variable name="outbound_caller_id_number" value="$${outbound_caller_id}"></variable>
<variable name="callgroup" value="techsupport"></variable>
</variables>
</user>
</domain>
</section>
</document>
공식 문서를 통한 CIDR 사용
공식 문서를 통해 CIDR로 여러 IP를 지정할 수 있습니다:
<include>
<user id="1000" cidr="12.34.56.78/32,20.0.0.0/8">
<params>
<param name="password" value="1234"/>
<param name="vm-password" value="1000"/>
</params>
<variables>
<variable name="accountcode" value="1000"/>
<variable name="user_context" value="default"/>
<variable name="effective_caller_id_name" value="Extension 1000"/>
<variable name="effective_caller_id_number" value="1000"/>
</variables>
</user>
</include>