| name | whatsapp |
| description | Use when someone needs to build, configure, deploy, verify, or troubleshoot a Meta WhatsApp Business Calling SIP-mode gateway that bridges to Cisco Webex Contact Center or a Webex AI Agent through FreeSWITCH, Docker, and AWS EC2. |
Skill: WhatsApp Business Calling → Cisco Webex CC via SIP Gateway
When to Activate This Skill
Use this skill when a user asks to connect Meta WhatsApp voice calls to Cisco Webex Contact Center, set up a SIP proxy for Meta Business Calling, or route WhatsApp callers to a Webex AI agent or human agents. Walk them through the entire journey from scratch. Do not assume anything is already set up.
Hard-Won Production Lessons
- Meta-facing calls use SIP mode, Opus, TLS 5061, and SDES-SRTP. Do not switch Meta to DTLS.
- Webex-facing calls use PCMU/PCMA only. Do not offer G.722 for this gateway; it caused ASR/AI-agent quality problems and the module is not compiled in the known build.
- The Meta WhatsApp Business number and the Webex CC entry point DID are different numbers. FreeSWITCH dials the Webex entry point DID, not the public WhatsApp number.
- Keep
caller-id-in-from=false on the cisco_webex gateway. The real WhatsApp caller number goes in PAI/RPID headers.
- For the AI-agent greeting to fire reliably, answer the Meta leg first, then play 500ms of silence with
playback silence_stream://500, then bridge to Webex. Passive sleep(500) can stall on a cold first call.
- Do not add SIP OPTIONS ping to the Meta inbound gateway; it broke inbound behavior in testing. Webex OPTIONS keepalive is OK and useful.
Part 1: What This Is and Why It Works This Way
What Meta WhatsApp Business Calling Is
Meta offers voice calling as part of the WhatsApp Business Platform. Businesses can receive and initiate calls through WhatsApp. The official documentation is at:
https://developers.facebook.com/documentation/business-messaging/whatsapp/calling
Meta offers two fundamentally different modes for handling these calls. The user must understand which mode they need before anything else:
SIP Mode — Meta sends calls as standard SIP INVITEs to a business-owned SIP server (this gateway). The business owns all call signaling and media. No call event webhooks from Meta in this mode. This is the correct mode when connecting to existing telephony infrastructure like Cisco Webex CC.
Graph API + WebRTC Mode — Meta sends call event webhooks to an HTTPS server. The business controls calls via the Graph API and handles media via WebRTC. This is the correct mode for browser-based apps or bots connecting directly to cloud AI services.
This project uses SIP Mode because Cisco Webex CC speaks SIP. When SIP mode is enabled on a WhatsApp Business Account, Graph API call control endpoints are disabled and call event webhooks are not sent.
Why a Gateway Is Needed
Meta WhatsApp SIP and Cisco Webex CC are fundamentally incompatible:
| Meta WhatsApp SIP | Cisco Webex CC |
|---|
| Codec | Opus/48kHz only | G.711 PCMU/PCMA 8kHz (no Opus, no G.722) |
| Re-INVITEs | Not supported | Fully supported |
| SRTP | SDES mandatory | SDES |
| SIP Auth | Digest challenge per INVITE | Registration-based trunk |
| TLS | Required | Required |
A SIP B2BUA (Back-to-Back User Agent) sits between them, terminates each leg independently, and transcodes audio. FreeSWITCH is used because it has native Opus support via mod_opus, handles SDES-SRTP natively, and runs as a Docker container with no licensing cost.
Why SDES and Not DTLS
Meta supports two SRTP key exchange methods. SDES puts crypto keys inline in the SDP body (a=crypto: lines) — no ICE needed, works from the first INVITE. DTLS negotiates keys via a TLS handshake after ICE connectivity checks.
Meta's SIP infrastructure is ICE-lite: it only responds to STUN requests, never sends them. FreeSWITCH's DTLS start condition requires ICE to complete on both sides. With an ICE-lite peer this never happens, DTLS never starts, no audio is established, and calls drop at ~20 seconds.
SDES bypasses ICE entirely. Always configure Meta with srtp_key_exchange_protocol: "SDES".
Part 2: Accounts and Access to Obtain First
Guide the user to get all of these before touching any configuration. Some take days to approve.
Meta Business Account Setup
- Create a Meta Business Account at https://business.facebook.com if not already done
- Create a Meta Developer App at https://developers.facebook.com
- Add the WhatsApp product to the app
- Apply for access to the WhatsApp Business API — this requires a verified business
- Once approved, obtain a WhatsApp Business Account (WABA) and a WhatsApp Business Phone Number
- In the Developer Portal under WhatsApp → API Setup, note the Phone Number ID (numeric) and generate a permanent Access Token (not the temporary test token)
- SIP calling must be explicitly enabled by Meta on the account — it is not enabled by default. Use the Graph API call in Part 4 to enable it. The SIP credentials (username and password) are generated by Meta when SIP is enabled.
Meta's calling documentation: https://developers.facebook.com/documentation/business-messaging/whatsapp/calling
Cisco Webex Requirements
- Webex CC tenant with admin access
- Webex CC license that includes AI Agents (CCAI) if using virtual agent
- Webex Calling enabled on the tenant
- Ability to provision a Premises-based PSTN trunk in Control Hub
- A Webex Calling phone number (DID) to assign as the CC entry point — this is separate from the Meta WhatsApp number
AWS Requirements
- AWS account with EC2 access
- A domain name with DNS control (e.g.
gateway.company.com) — needed for TLS
Part 3: AWS EC2 Setup
Launch Instance
- AMI: Ubuntu 22.04 LTS
- Instance type: t3.medium minimum — Opus↔PCMU transcoding is CPU-intensive. t3.micro will run out of memory under concurrent calls.
- Storage: 20GB gp3
- Elastic IP: required. Both Meta and Webex need a stable IP that does not change.
Security Group — Every Port Matters
TCP 22 your IP only SSH
TCP 5061 0.0.0.0/0 Meta SIP TLS — Meta sends INVITEs here
TCP 5062 0.0.0.0/0 Webex SIP TLS — FreeSWITCH registers and sends calls here
TCP 5060 0.0.0.0/0 Plain SIP — for local testing only
UDP 10000-20000 0.0.0.0/0 RTP media — all voice audio travels here
TCP 8021 127.0.0.1 only FreeSWITCH ESL — internal only, never expose externally
UDP 10000-20000 is the most commonly missed. Without it calls connect (SIP signaling works) but there is complete silence in both directions.
Install Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker ubuntu
docker --version && docker compose version
TLS Certificate
sudo apt update && sudo apt install -y certbot
sudo certbot certonly --standalone -d gateway.company.com
The entrypoint.sh script reads /etc/letsencrypt at container startup and builds agent.pem (combined cert+key) for both SIP profiles automatically. No manual cert handling needed after this.
Important: Why Host Networking
Docker's default bridge networking NATs container traffic. SIP embeds IP addresses inside SDP bodies and Contact headers. With bridge networking, these IPs become internal Docker addresses (172.x.x.x) — Meta and Webex send RTP to addresses that do not exist externally. Result: calls connect but no audio.
Both containers use network_mode: host in docker-compose.yml. This gives them direct access to the host's network stack. Do not change this.
Part 4: Meta Graph API — Enable SIP Calling
There is no UI for this in the Meta Developer Portal. It is configured entirely via API.
curl -X POST \
"https://graph.facebook.com/v20.0/YOUR_PHONE_NUMBER_ID/settings" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"calling": {
"srtp_key_exchange_protocol": "SDES",
"sip": {
"status": "ENABLED",
"servers": [{
"hostname": "gateway.company.com",
"port": 5061,
"request_uri_user_params": { "TGRP": "wacall" }
}]
}
}
}'
Expected response: {"success": true}
Field explanations:
srtp_key_exchange_protocol: "SDES" — mandatory for this gateway. See Part 1 for why DTLS fails.
hostname — the gateway's domain name pointing to the EC2 Elastic IP
port: 5061 — must be exactly 5061. Port 5062 is the Webex-facing port. Setting 5062 here causes Meta INVITEs to land on the wrong FreeSWITCH profile and calls fail with no obvious error.
TGRP: "wacall" — trunk group tag appended to the SIP Request-URI. Meta's INVITE arrives addressed to +447956828011;TGRP=wacall. The dialplan regex ^(.+)$ catches this.
After this API call succeeds, go back to the Meta Developer Portal under WhatsApp → Calling settings to retrieve the SIP credentials (username and password) that Meta generated.
Part 5: Webex Control Hub Setup
Do each step in order.
5a. Create a Location
Control Hub → Management → Locations → Add location.
- Name: anything descriptive (e.g.
WhatsApp Gateway) — label only, no routing effect
- Country/Region, Address: required fields, administrative only, do not affect SIP routing
5b. Create a Trunk on that Location
Control Hub → PSTN & Routing → Gateway configurations → Trunk tab → Add trunk.
- Location: the location just created
- Device type: Cisco CUBE Local Gateway — correct even though FreeSWITCH is used. This device type tells Webex it is a registration-based premises gateway.
- Name: e.g.
whatsapp_trk
Save. Webex provisions the trunk and generates SIP credentials.
5c. Collect Trunk Credentials
Click the trunk just created. A details panel shows:
- Registrar Domain →
cisco_sip_host in vars.xml
- Trunk Group OTG/DTG →
cisco_trunk_otg in vars.xml
- Line/Port — shows as
something@domain.webex.com. Use only the part before @ → cisco_trunk_line_port in vars.xml
- Outbound Proxy Address →
cisco_outbound_proxy in vars.xml
Scroll to Authentication Information → click "Retrieve Username and Reset Password".
- Every click generates a new password. The old one stops working immediately.
- Copy both username and password right now.
- Username →
cisco_trunk_username in vars.xml
- Password →
cisco_trunk_password in vars.xml
5d. Enable Dual Identity Support
Still in the trunk details panel, find Dual Identity Support toggle. Enable it (blue).
When ON: From header (trunk label, used for Webex routing) and P-Asserted-Identity header (real WhatsApp caller number, used for customer_phone in CC flow variables) are treated independently.
When OFF: Webex forces PAI to equal From — the real caller number never reaches the AI agent.
5e. Assign the Meta WhatsApp Number to the Location
Control Hub → PSTN & Routing → Numbers → Manage → Add numbers.
Add the Meta WhatsApp Business number (e.g. +447956828011) to the location created in 5a.
This anchors the trunk. FreeSWITCH does NOT dial this number — it is a trunk registration anchor only.
5f. Select an Available Entry Point DID
Control Hub → PSTN & Routing → Numbers.
Any number where the "Assigned to" column is empty is available. Pick one. This is what FreeSWITCH dials to reach the Webex CC flow. Set it as webex_entry_point_number in vars.xml. It is never given to customers.
5g. Create the Webex CC Channel
Contact Center → Channels → Create channel.
- Channel type: Inbound Telephony — must be this type. A digital or WhatsApp channel type causes CCAI to fail because calls arrive as standard SIP voice, not a digital messaging session.
- Routing flow: the AI agent flow
- Phone numbers: assign the Entry Point DID from 5f
Save and set Active.
Part 6: The Only Config File to Edit
freeswitch/conf/vars.xml is the only file that changes between deployments. Everything else (SIP profiles, dialplan, Dockerfile) reads from these variables and never needs editing.
<X-PRE-PROCESS cmd="set" data="external_ip=YOUR_EC2_ELASTIC_IP"/>
<X-PRE-PROCESS cmd="set" data="domain=gateway.company.com"/>
<X-PRE-PROCESS cmd="set" data="meta_sip_server=wa.meta.vc"/>
<X-PRE-PROCESS cmd="set" data="meta_sip_port=5061"/>
<X-PRE-PROCESS cmd="set" data="meta_sip_username=YOUR_META_SIP_USERNAME"/>
<X-PRE-PROCESS cmd="set" data="meta_sip_password=YOUR_META_SIP_PASSWORD"/>
<X-PRE-PROCESS cmd="set" data="cisco_sip_host=REGISTRAR_DOMAIN"/>
<X-PRE-PROCESS cmd="set" data="cisco_outbound_proxy=OUTBOUND_PROXY_ADDRESS"/>
<X-PRE-PROCESS cmd="set" data="cisco_trunk_line_port=LINE_PORT_BEFORE_AT_SIGN"/>
<X-PRE-PROCESS cmd="set" data="cisco_trunk_otg=TRUNK_GROUP_OTG_DTG"/>
<X-PRE-PROCESS cmd="set" data="cisco_trunk_username=AUTH_USERNAME"/>
<X-PRE-PROCESS cmd="set" data="cisco_trunk_password=AUTH_PASSWORD"/>
<X-PRE-PROCESS cmd="set" data="webex_entry_point_number=ENTRY_POINT_DID"/>
Also update .env:
META_WHATSAPP_PHONE_NUMBER_ID=numeric_id_from_meta_portal
META_WHATSAPP_ACCESS_TOKEN=your_access_token
GATEWAY_PUBLIC_IP=your_elastic_ip
GATEWAY_FQDN=gateway.company.com
Part 7: The FreeSWITCH Config Files (Pre-Built — Verify Only)
These files are already in the repository. The AI should show them to the user for understanding and verify they are present and unmodified. Only vars.xml needs editing.
freeswitch/conf/sip_profiles/meta_inbound.xml
This profile faces Meta's SIP infrastructure on port 5061.
<profile name="meta_inbound">
<gateways>
<gateway name="meta_whatsapp">
<param name="username" value="$${meta_sip_username}"/>
<param name="password" value="$${meta_sip_password}"/>
<param name="realm" value="$${meta_sip_server}"/>
<param name="proxy" value="$${meta_sip_server}:$${meta_sip_port}"/>
<param name="register" value="false"/>
<param name="register-transport" value="tls"/>
<param name="caller-id-in-from" value="true"/>
</gateway>
</gateways>
<settings>
<param name="context" value="meta_context"/>
<param name="ext-sip-ip" value="$${external_ip}"/>
<param name="ext-rtp-ip" value="$${external_ip}"/>
<param name="tls-sip-port" value="5061"/>
<param name="tls-cert-dir" value="/tmp/meta-ssl"/>
<param name="tls-version" value="tlsv1.2"/>
<param name="inbound-codec-prefs" value="OPUS"/>
<param name="outbound-codec-prefs" value="OPUS"/>
<param name="rtp-secure-media" value="mandatory"/>
<param name="rtp-secure-media-inbound" value="true"/>
<param name="rtp-secure-media-outbound" value="true"/>
<param name="disable-transfer" value="true"/>
<param name="enable-timer" value="false"/>
<param name="inbound-late-negotiation" value="false"/>
<param name="sip-trace" value="no"/>
<param name="NDLB-force-rport" value="safe"/>
<param name="aggressive-nat-detection" value="true"/>
</settings>
</profile>
Key settings explained:
register=false: Meta uses SIP digest challenge per INVITE, not registration. meta_whatsapp showing NOREG in sofia status is correct and expected.
caller-id-in-from=true: reads the WhatsApp caller's number from Meta's INVITE From header as caller_id_number
inbound-codec-prefs=OPUS: Meta only offers Opus. No fallback exists.
disable-transfer=true + enable-timer=false: Meta does not support re-INVITEs. These prevent FreeSWITCH from sending re-INVITEs toward Meta.
rtp-secure-media=mandatory: SDES-SRTP required on all calls from Meta
freeswitch/conf/sip_profiles/cisco_outbound.xml
This profile faces Webex CC on port 5062.
<profile name="cisco_outbound">
<gateways>
<gateway name="cisco_webex">
<param name="username" value="$${cisco_trunk_username}"/>
<param name="password" value="$${cisco_trunk_password}"/>
<param name="realm" value="$${cisco_sip_host}"/>
<param name="from-user" value="$${cisco_trunk_line_port}"/>
<param name="from-domain" value="$${cisco_sip_host}"/>
<param name="contact-user" value="$${cisco_trunk_line_port}"/>
<param name="contact-params" value="tgrp=$${cisco_trunk_otg};trunk-context=$${cisco_sip_host}"/>
<param name="proxy" value="$${cisco_sip_host}"/>
<param name="register-proxy" value="$${cisco_outbound_proxy}"/>
<param name="outbound-proxy" value="$${cisco_outbound_proxy}"/>
<param name="register" value="true"/>
<param name="register-transport" value="tls"/>
<param name="expire-seconds" value="300"/>
<param name="retry-seconds" value="30"/>
<param name="ping" value="25"/>
<param name="ping-min" value="1"/>
<param name="ping-max" value="3"/>
<param name="caller-id-in-from" value="false"/>
</gateway>
</gateways>
<settings>
<param name="context" value="cisco_context"/>
<param name="ext-sip-ip" value="$${external_ip}"/>
<param name="ext-rtp-ip" value="$${external_ip}"/>
<param name="tls-sip-port" value="$${cisco_tls_port}"/>
<param name="tls-cert-dir" value="/tmp/cisco-ssl"/>
<param name="tls-version" value="tlsv1.2"/>
<param name="inbound-codec-prefs" value="PCMU,PCMA"/>
<param name="outbound-codec-prefs" value="PCMU,PCMA"/>
<param name="rtp-secure-media" value="mandatory"/>
<param name="rtp-secure-media-outbound" value="true"/>
<param name="disable-transfer" value="false"/>
<param name="enable-timer" value="true"/>
<param name="inbound-late-negotiation" value="true"/>
<param name="sip-trace" value="no"/>
<param name="NDLB-force-rport" value="safe"/>
<param name="aggressive-nat-detection" value="true"/>
</settings>
</profile>
Key settings explained:
caller-id-in-from=false: the SIP From header must carry the trunk label (e.g. whatsapp_trk1862418010_LGU). Webex validates From against the registered trunk identity. If this is set to true and the caller's number appears in From, Webex returns 404 Not Found.
register=true: FreeSWITCH maintains a registration with Webex. Must show REGED.
disable-transfer=false + enable-timer=true: Webex supports full SIP including re-INVITEs. FreeSWITCH handles any Webex re-INVITEs on the B-leg without propagating them to Meta.
freeswitch/conf/dialplan/meta_to_cisco.xml
Every inbound call from Meta runs through this dialplan.
<extension name="meta_to_cisco_route">
<condition field="destination_number" expression="^(.+)$">
<action application="log" data="NOTICE ====== INBOUND CALL FROM WHATSAPP ======"/>
<action application="log" data="NOTICE Caller: ${caller_id_number} (${caller_id_name})"/>
<action application="log" data="NOTICE Destination: ${destination_number}"/>
<action application="log" data="NOTICE SIP Call-ID: ${sip_call_id}"/>
<action application="export" data="nolocal:absolute_codec_string=PCMU,PCMA"/>
<action application="export" data="nolocal:rtp_secure_media=mandatory"/>
<action application="set" data="bypass_media=false"/>
<action application="set" data="sip_renegotiate_codec_on_reinvite=false"/>
<action application="export" data="nolocal:sip_h_P-Asserted-Identity=<sip:${caller_id_number}@$${cisco_sip_host}>"/>
<action application="export" data="nolocal:sip_h_Remote-Party-ID=<sip:${caller_id_number}@$${cisco_sip_host}>;party=calling;screen=yes;privacy=off"/>
<action application="set" data="sip_h_X-WhatsApp-From=${caller_id_number}"/>
<action application="set" data="sip_h_X-WhatsApp-Display-Name=${caller_id_name}"/>
<action application="set" data="sip_h_X-WhatsApp-Business-Number=${destination_number}"/>
<action application="set" data="sip_h_X-WhatsApp-Call-Type=inbound"/>
<action application="set" data="webex_ep=$${webex_entry_point_number}"/>
<action application="answer"/>
<action application="playback" data="silence_stream://500"/>
<action application="log" data="NOTICE Bridging to Webex: sip:${webex_ep}@$${cisco_sip_host};tgrp=$${cisco_trunk_otg}"/>
<action application="bridge"
data="sofia/gateway/cisco_webex/sip:${webex_ep}@$${cisco_sip_host};tgrp=$${cisco_trunk_otg};trunk-context=$${cisco_sip_host}"/>
<action application="log" data="ERR Webex bridge failed: ${DIALSTATUS} - ${hangup_cause}"/>
<action application="hangup" data="NORMAL_TEMPORARY_FAILURE"/>
</condition>
</extension>
Key behaviors explained:
answer before bridge: FreeSWITCH answers the Meta leg first (sends 200 OK, establishes SRTP with Meta), plays 500ms of active silence, then bridges to Webex. Active silence fixed the cold first-call stall where passive sleep(500) never advanced to the Webex bridge.
bypass_media=false: required for Opus↔PCMU transcoding. If set to true, FreeSWITCH passes media through without touching it — no transcoding.
sip_renegotiate_codec_on_reinvite=false: if Webex sends a re-INVITE to change codec, FreeSWITCH handles it on the Webex leg only and does not propagate a re-INVITE toward Meta.
tgrp and trunk-context in bridge: required in the Request-URI. Webex uses these to route the call to the correct CC tenant and entry point.
Part 8: Deploy
git clone https://github.com/YOUR_ORG/workflow_whatsapp_gateway.git
cd workflow_whatsapp_gateway
cp .env.example .env
docker compose up -d --build
First build: 20-30 minutes. FreeSWITCH is compiled from source inside Docker. This is expected and only happens once — subsequent builds use the cached source and are much faster.
For every config change after initial deployment:
git add -A && git commit -m "describe change" && git push
git pull && docker compose up -d --build
Never use fs_cli -x "reloadxml". The config files are baked into the Docker image at build time. Only a rebuild picks up changes.
Part 9: Verify in This Exact Order
Step 1 — Trunk registration
docker exec sip-gateway-freeswitch fs_cli -x "sofia status"
cisco_webex must show REGED
meta_whatsapp shows NOREG — correct. Meta uses digest challenge per INVITE, not registration.
If cisco_webex is not REGED: wrong credentials in vars.xml, TCP 5062 not open in security group, or trunk password was regenerated in Control Hub.
Step 2 — TTS / play-message call first
Set the Webex CC flow to play a simple recorded message only. Make a WhatsApp call to the Meta Business number. The caller should hear the message.
This confirms: Meta SIP reaching gateway ✓, FreeSWITCH transcoding ✓, Webex bridge ✓, audio path both directions ✓.
If this fails: issue is in FreeSWITCH config or AWS networking.
If this works: move to AI agent.
Step 3 — AI agent call
Switch Webex CC flow to AI agent. Call in. Hear the greeting.
If TTS worked but AI agent fails: issue is in Webex CC CCAI configuration — not FreeSWITCH. Check Channel type is Inbound Telephony, correct flow is assigned, and webex_entry_point_number in vars.xml is the Entry Point DID (not the Meta WhatsApp Business number).
Debug logging when needed
docker exec sip-gateway-freeswitch fs_cli -x "sofia global siptrace on"
docker logs sip-gateway-freeswitch -f
docker exec sip-gateway-freeswitch fs_cli -x "sofia global siptrace off"
Part 10: Failure Mode Diagnosis
| Symptom | Cause | Fix |
|---|
| AI agent fails ~1 second, TTS works | webex_entry_point_number is set to the Meta WhatsApp Business number | Get an available DID from Control Hub → PSTN & Routing → Numbers (empty Assigned-to). Assign to Inbound Telephony CC Channel. Set as webex_entry_point_number in vars.xml. Rebuild. |
| Calls connect, complete silence | UDP 10000-20000 blocked in AWS security group | Add inbound rule: UDP 10000-20000 from 0.0.0.0/0 |
| Calls drop at ~20 seconds, no audio | DTLS configured instead of SDES | Re-run Meta Graph API with "srtp_key_exchange_protocol": "SDES" |
| 404 Not Found from Webex immediately | caller-id-in-from=true on cisco_webex gateway | Keep caller-id-in-from=false in cisco_outbound.xml |
| Meta INVITEs land on wrong profile | Port 5062 set in Meta Graph API instead of 5061 | Re-run Meta API call with "port": 5061 |
| cisco_webex shows NOREG | Wrong credentials or password regenerated in Control Hub | Control Hub → trunk → Retrieve Username and Reset Password → copy both → update vars.xml → rebuild |
| One-way or no audio | Docker bridge networking active | Confirm network_mode: host in docker-compose.yml for both services |
| AI agent greeting never plays or cold first call answers but never bridges | Missing answer plus active silence before bridge, or old passive sleep stall | Confirm dialplan has answer then playback data="silence_stream://500" before bridge |
customer_phone shows trunk label in CC flow | Dual Identity Support OFF on Webex trunk | Control Hub → trunk details → enable Dual Identity Support |
| Password stopped working | "Retrieve Username and Reset Password" was clicked | Click again, copy new credentials, update vars.xml, rebuild immediately |
Quick Reference
docker exec sip-gateway-freeswitch fs_cli -x "sofia status"
docker exec sip-gateway-freeswitch fs_cli -x "show calls"
docker logs sip-gateway-freeswitch -f
docker logs sip-gateway-freeswitch -f --since=1s 2>&1 | tee /tmp/call.log
git pull && docker compose up -d --build
docker exec sip-gateway-freeswitch fs_cli -x "sofia global siptrace on"
docker exec sip-gateway-freeswitch fs_cli -x "sofia global siptrace off"
| File | Edit When |
|---|
freeswitch/conf/vars.xml | Every deployment |
.env | Every deployment |
freeswitch/conf/dialplan/meta_to_cisco.xml | Only if changing call behavior |
freeswitch/conf/sip_profiles/meta_inbound.xml | Rarely |
freeswitch/conf/sip_profiles/cisco_outbound.xml | Rarely |
freeswitch/Dockerfile | Never |
docker-compose.yml | Never |