Explore options for connecting local FreeSWITCH instance with external PBX provider to route calls to a SIP client connected to that same FreeSWITCH instance.

FreeSWITCH excels as a flexible B2BUA (Back-to-Back User Agent), SIP switch, and media handler. It can interconnect a local instance with an external PBX/VoIP provider (SIP trunk provider like Telnyx, Twilio, SignalWire, or another PBX system) while routing calls to SIP clients (phones/softphones) registered directly to the same FreeSWITCH instance.

The typical architecture uses two Sofia SIP profiles:

  • Internal — For local SIP clients (usually on LAN or localhost, context default or internal).
  • External — For the provider/peer (public-facing or via NAT/VPN, context public or custom like from-provider).

The SIP client registers as a user in the directory (e.g., conf/directory/default/1001.xml or dynamically). Inbound calls from the external side land in a dialplan context and bridge to the client via user/EXTENSION or sofia/internal/EXTENSION.

Option 1: SIP Trunk to a VoIP/SIP Trunk Provider (Most Common)

Connect FreeSWITCH to a carrier or hosted provider for PSTN access, DIDs, and outbound calling. The provider becomes the "external PBX provider."

Two authentication approaches (choose based on provider support and your network):

  • Registration-based (register="true"): FreeSWITCH sends periodic REGISTERs. Good for dynamic IPs or NAT on the FreeSWITCH side. Provider sends inbound calls to the registered Contact URI. Requires username/password from provider.⁠Developer.signalwire
  • IP Authentication (register="false"): No registration. Provider is configured with your FreeSWITCH public IP (or SIP URI). FreeSWITCH authenticates inbound by IP (via ACL). Simpler, less traffic; requires static public IP (or reliable port forwarding) and provider-side IP whitelisting. Often preferred for security and simplicity when possible.⁠Support.telnyx

Basic gateway configuration (create file in conf/sip_profiles/external/provider.xml):

Registration example (e.g., Wavix-style):

XML
<include>
  <gateway name="myprovider">
    <param name="username" value="YOUR_USERNAME"/>
    <param name="password" value="YOUR_PASSWORD"/>
    <param name="proxy" value="sip.myprovider.com"/>
    <param name="realm" value="sip.myprovider.com"/>
    <param name="register" value="true"/>
    <param name="context" value="public"/>  <!-- or custom inbound context -->
    <param name="ping" value="30"/>         <!-- keepalive -->
  </gateway>
</include>

IP-auth example (e.g., Telnyx-style):

XML
<include>
  <gateway name="myprovider">
    <param name="proxy" value="sip.myprovider.com"/>
    <param name="register" value="false"/>
    <param name="context" value="public"/>
    <!-- username/password often not needed or set to placeholders -->
  </gateway>
</include>

Include it via the external profile's gateways section (usually already done with <X-PRE-PROCESS cmd="include" data="external/*.xml"/>).

NAT handling (critical for most deployments): In vars.xml or the profile, set:

XML
<X-PRE-PROCESS cmd="set" data="external_sip_ip=your.public.ip.or.autonat"/>
<X-PRE-PROCESS cmd="set" data="external_rtp_ip=your.public.ip.or.autonat"/>

Or use autonat detection. Restart/reload after changes.

Dialplan routing examples (in conf/dialplan/public/ or a custom context file):

Inbound (from provider → route specific DID to your SIP client extension 1001):

XML
<extension name="inbound_did_1001">
  <condition field="destination_number" expression="^(YOUR_DID_HERE)$">
    <action application="set" data="effective_caller_id_number=${caller_id_number}"/>
    <action application="bridge" data="user/1001"/>  <!-- or sofia/internal/1001@$${domain} -->
  </condition>
</extension>

Outbound (from internal SIP client → provider):

XML
<extension name="outbound_via_provider">
  <condition field="destination_number" expression="^(\d{10,15})$">
    <action application="bridge" data="sofia/gateway/myprovider/$1"/>
  </condition>
</extension>

Always match your provider's expected number format (E.164 with/without +, etc.). Test with fs_cli -x "sofia status gateway myprovider" (look for REGED or UP state) and reloadxml.

Provider-specific notes: Many (Telnyx, Wavix, etc.) publish exact FreeSWITCH guides. Follow them for required headers (e.g., caller-id-in-from, PAI for caller ID presentation), codecs, or DTMF settings.⁠Docs.wavix

Option 2: Peer Trunk / Interconnect with Another PBX

Treat the external PBX (another FreeSWITCH, FreePBX/Asterisk, 3CX, etc.) exactly like a trunk provider. Useful for hybrid on-prem + cloud, multi-site, or migration scenarios.

  • Set up a gateway on the FreeSWITCH side pointing to the other PBX's IP/hostname (register=true if one side should register to the other; or false + IP ACL for trusted peers).
  • On the other PBX, configure a reciprocal trunk/gateway pointing back (or one-way if desired).
  • Use contexts and dialplan conditions to route specific number ranges, DIDs, or prefixes between systems (e.g., bridge to the peer gateway or locally to your SIP client).
  • On internal/LAN or via VPN: IP authentication (register="false") with ACLs is clean and common.
  • Example use case: FreeSWITCH handles media/transcoding/recording while the other PBX manages extensions/GUI; or route certain calls from external provider → FreeSWITCH → other PBX.

This works bidirectionally and can include failover or least-cost routing.

Option 3: VPN + Private SIP Peering (Recommended for Security)

Establish a VPN tunnel (WireGuard, OpenVPN, IPsec) between the local FreeSWITCH network and the external provider/PBX network.

  • Route SIP/RTP over the private tunnel (no public exposure).
  • Use IP-based authentication or simple credentials.
  • Treat the peer as a trusted internal gateway (often on a dedicated internal profile or context).
  • Benefits: Strong encryption at network layer, simpler ACLs/firewall rules, avoids many NAT/public SIP issues.
  • Ideal when both sides are under your control or the provider supports private interconnect.

Option 4: GUI-Managed Setup with FusionPBX (or Similar)

Install FusionPBX on top of FreeSWITCH for a web interface that dramatically simplifies:

  • Adding/editing gateways (with templates for many providers).
  • Inbound routes/destinations (map DIDs to extensions, ring groups, IVRs, time conditions, etc.).
  • Outbound routes, caller ID, recording, etc.
  • Multi-tenant or advanced features.

Many production deployments use this. Inbound routing becomes point-and-click (Destinations or Inbound Routes section) instead of manual XML.⁠Gotrunk

Other GUIs or commercial distributions exist but FusionPBX is the most popular open-source option tightly integrated with FreeSWITCH.

Essential Configuration & Best Practices (All Options)

  • Profiles & Security: Keep internal and external profiles separate. Enable TLS (tls transport, port 5061) + SRTP where the provider supports it. Use strong passwords or IP auth. Add provider IPs to ACLs (conf/acls.xml) for trusted access. Consider fail2ban or firewall rules limiting SIP sources.
  • Firewall/Ports: SIP signaling (UDP/TCP/TLS 5060/5061) + RTP media range (commonly 10000–20000 UDP). Restrict where possible.
  • Codecs & Media: Prefer compatible codecs (PCMU/PCMA often safest). FreeSWITCH can transcode but it uses CPU. Use absolute_codec_string variables per gateway if needed.
  • DTMF & Features: Standardize on RFC 2833 (out-of-band). Test caller ID (From/PAI headers), especially for outbound.
  • Testing & Monitoring:
    • fs_cli: sofia status, sofia status gateway NAME, reloadxml, reloadacl.
    • Tools: sngrep (excellent SIP trace), tcpdump/wireshark.
    • Check one-way audio, registration state, and exact DID variable (destination_number, sip_to_user, etc.—varies by provider).
  • High Availability/Scaling: Multiple gateways with failover, DNS SRV, mod_lcr for routing, or clustered FreeSWITCH setups.
  • Common Pitfalls: NAT misconfiguration (one-way audio), context mismatches, wrong DID variable in dialplan, firewall blocking RTP, provider expecting specific registration behavior or headers.

Routing Specifically to Your SIP Client

Once the call reaches FreeSWITCH (via any of the above options), routing to the registered SIP client is standard internal handling:

  • The client must be registered and online (check with sofia status profile internal or similar).
  • Use bridge user/EXTENSION (easiest) or sofia/internal/EXTENSION.
  • You can add IVR, ring groups, call screening, recording, or other logic in the dialplan before/after bridging.
  • FreeSWITCH manages the end-to-end SIP dialogs and media (with proper ext-ip settings for NAT).

Recommendations & Next Steps

  1. Identify your exact external provider/PBX and obtain their recommended FreeSWITCH (or generic SIP) configuration.
  2. Start simple: IP auth if possible + basic inbound DID route to one test extension.
  3. Harden security from day one (TLS where feasible, ACLs, minimal exposure).
  4. Use FusionPBX if you prefer GUI management over raw XML.
  5. Test thoroughly with sngrep and a softphone client.
  6. Communities/resources: FreeSWITCH documentation (developer.signalwire.com/freeswitch), mailing lists, Discord/forums, and provider support. Consider mod_xml_curl for dynamic/large-scale configs later.

This setup gives you full control: the external provider handles PSTN/cloud termination, FreeSWITCH acts as the intelligent switch/router/media handler, and your SIP client receives calls seamlessly. Many production systems run exactly this pattern (or with FusionPBX on top).

If you provide more details (specific provider, on-prem vs. cloud, NAT situation, desired features like recording/IVR, or whether it's bidirectional), I can give more targeted XML examples or troubleshooting steps.

58 sources
FreeSWITCH External SIP Trunk Setup | Shared Grok Conversation