FreeSWITCH VoIP Server Installation

FreeSWITCH is a powerful open-source VoIP and real-time communication platform that supports SIP, WebRTC, and conferencing at scale. This guide covers installing FreeSWITCH on Linux, configuring SIP dial plans, enabling WebRTC support, setting up conference bridges, and scripting call logic with Lua.

Prerequisites

  • Ubuntu 20.04/22.04 or Debian 11/12
  • Minimum 1 GB RAM (2 GB recommended for production)
  • Root or sudo access
  • Open ports: 5060/UDP+TCP (SIP), 5061/TCP (SIP TLS), 8021/TCP (ESL), 16384–32768/UDP (RTP)

Install FreeSWITCH from Packages

FreeSWITCH maintains official packages via SignalWire (the project's primary sponsor):

# Install dependencies
sudo apt update && sudo apt install -y gnupg2 wget lsb-release

# Add the SignalWire repository key
wget -O - https://freeswitch.signalwire.com/repo/deb/debian-release/freeswitch_archive_g0.pub | \
  sudo gpg --dearmor -o /usr/share/keyrings/freeswitch-archive-keyring.gpg

# Add the repository (Debian/Ubuntu)
echo "deb [signed-by=/usr/share/keyrings/freeswitch-archive-keyring.gpg] \
  https://freeswitch.signalwire.com/repo/deb/debian-release/ $(lsb_release -sc) main" | \
  sudo tee /etc/apt/sources.list.d/freeswitch.list

# Install FreeSWITCH
sudo apt update
sudo apt install -y freeswitch freeswitch-meta-all

# Enable and start
sudo systemctl enable freeswitch
sudo systemctl start freeswitch
sudo systemctl status freeswitch

Directory Structure and Configuration Overview

/etc/freeswitch/
├── freeswitch.xml          # Top-level config that includes everything
├── vars.xml                # Global variables (domain, passwords, etc.)
├── directory/              # User/device registrations
│   └── default/            # Default user directory
├── dialplan/               # Call routing rules
│   ├── default.xml         # Inbound/outbound routing
│   └── public.xml          # Public (unauthenticated) routes
├── sip_profiles/           # SIP listener profiles
│   ├── internal.xml        # Internal SIP profile (port 5060)
│   └── external.xml        # External/trunk SIP profile
└── autoload_configs/       # Module and feature configs
# Connect to FreeSWITCH CLI
sudo fs_cli -H 127.0.0.1 -P 8021 -p ClueCon

# Inside fs_cli - check running modules
module_exists mod_sofia
show registrations
sofia status

SIP Profile Configuration

Edit /etc/freeswitch/sip_profiles/internal.xml to configure your internal SIP profile:

<!-- /etc/freeswitch/sip_profiles/internal.xml -->
<profile name="internal">
  <settings>
    <param name="sip-ip" value="$${local_ip_v4}"/>
    <param name="sip-port" value="5060"/>
    <param name="rtp-ip" value="$${local_ip_v4}"/>
    <param name="ext-rtp-ip" value="$${external_rtp_ip}"/>
    <param name="ext-sip-ip" value="$${external_sip_ip}"/>
    <param name="auth-calls" value="true"/>
    <param name="apply-inbound-acl" value="domains"/>
    <param name="record-path" value="$${recordings_dir}"/>
    <param name="codec-prefs" value="OPUS,G722,PCMU,PCMA"/>
  </settings>
  <domains>
    <domain name="all" alias="true" parse="true"/>
  </domains>
</profile>
# Add a SIP user in directory
sudo tee /etc/freeswitch/directory/default/1001.xml > /dev/null <<'EOF'
<include>
  <user id="1001">
    <params>
      <param name="password" value="SecurePass123!"/>
      <param name="vm-password" value="1234"/>
    </params>
    <variables>
      <variable name="toll_allow" value="domestic,international,local"/>
      <variable name="accountcode" value="1001"/>
      <variable name="user_context" value="default"/>
      <variable name="effective_caller_id_name" value="Extension 1001"/>
      <variable name="effective_caller_id_number" value="1001"/>
    </variables>
  </user>
</include>
EOF

# Reload directory from fs_cli
sudo fs_cli -x "reloadxml"
sudo fs_cli -x "sofia reload"

Dial Plan Configuration

The dial plan routes calls based on pattern matching. Edit /etc/freeswitch/dialplan/default.xml:

<!-- Route internal extensions (1000-1199) -->
<extension name="local_extensions">
  <condition field="destination_number" expression="^(1[0-1][0-9]{2})$">
    <action application="set" data="ringback=${us-ring}"/>
    <action application="bridge" data="user/$1@${domain_name}"/>
  </condition>
</extension>

<!-- Route to conference room 3000 -->
<extension name="conference">
  <condition field="destination_number" expression="^3000$">
    <action application="answer"/>
    <action application="conference" data="main@default"/>
  </condition>
</extension>

<!-- Voicemail -->
<extension name="voicemail">
  <condition field="destination_number" expression="^(\*98)$">
    <action application="answer"/>
    <action application="voicemail" data="check default ${domain_name} ${caller_id_number}"/>
  </condition>
</extension>
# Apply dial plan changes
sudo fs_cli -x "reloadxml"

WebRTC Support

FreeSWITCH supports WebRTC via WSS (WebSocket Secure) and DTLS-SRTP:

# Generate TLS certificates
sudo mkdir -p /etc/freeswitch/tls
sudo openssl req -x509 -newkey rsa:4096 -keyout /etc/freeswitch/tls/privkey.pem \
  -out /etc/freeswitch/tls/cert.pem -days 365 -nodes \
  -subj "/CN=your-server.example.com"

# Set permissions
sudo chown -R freeswitch:freeswitch /etc/freeswitch/tls

Enable the WebRTC profile by editing /etc/freeswitch/sip_profiles/internal.xml:

<!-- Add WebSocket support to internal profile -->
<param name="wss-binding" value=":7443"/>
<param name="tls" value="true"/>
<param name="tls-cert-dir" value="/etc/freeswitch/tls"/>
<param name="tls-version" value="tlsv1.2,tlsv1.3"/>
<param name="enable-dtls" value="true"/>
<param name="enable-rtcp-mux" value="true"/>
# Enable mod_verto for WebRTC
sudo fs_cli -x "load mod_verto"

# Verify WebSocket is listening
ss -tlnp | grep 7443

Conference Bridge Setup

# Configure conference in /etc/freeswitch/autoload_configs/conference.conf.xml
sudo tee /etc/freeswitch/autoload_configs/conference.conf.xml > /dev/null <<'EOF'
<configuration name="conference.conf" description="Conference">
  <caller-controls>
    <group name="default">
      <control action="mute" digits="0"/>
      <control action="deaf mute" digits="*"/>
      <control action="energy up" digits="9"/>
      <control action="energy down" digits="8"/>
      <control action="vol talk up" digits="3"/>
      <control action="vol talk down" digits="1"/>
    </group>
  </caller-controls>
  <profiles>
    <profile name="default">
      <param name="rate" value="48000"/>
      <param name="interval" value="20"/>
      <param name="energy-level" value="100"/>
      <param name="caller-controls" value="default"/>
      <param name="moderator-controls" value="default"/>
      <param name="max-members" value="50"/>
      <param name="record-file-prefix" value="$${recordings_dir}/conf_"/>
    </profile>
  </profiles>
</configuration>
EOF

sudo fs_cli -x "reloadxml"

Lua Scripting for Call Logic

FreeSWITCH supports Lua for advanced call routing and IVR logic:

-- /etc/freeswitch/scripts/ivr_menu.lua
-- Simple IVR with time-of-day routing

session:answer()
session:sleep(500)

-- Get current hour (server time)
local hour = tonumber(os.date("%H"))

if hour >= 9 and hour < 18 then
    -- Business hours: route to sales
    session:execute("playback", "ivr/ivr-welcome_to_freeswitch.wav")
    session:execute("bridge", "user/1001@${domain_name}")
else
    -- After hours: send to voicemail
    session:execute("playback", "ivr/ivr-after_hours.wav")
    session:execute("voicemail", "default ${domain_name} 1001")
end

session:hangup()
<!-- Trigger the Lua script from the dial plan -->
<extension name="ivr_menu">
  <condition field="destination_number" expression="^5000$">
    <action application="lua" data="ivr_menu.lua"/>
  </condition>
</extension>

Troubleshooting

Sofia SIP profile not starting:

sudo fs_cli -x "sofia status"
# If profile shows "DOWN":
sudo fs_cli -x "sofia profile internal restart"
# Check logs for errors
sudo journalctl -u freeswitch -n 100

No audio / one-way audio:

# Check RTP port range is open
sudo ss -ulnp | grep -E "1638[0-9]|164[0-9]{2}"

# Verify external IP is set correctly in vars.xml
grep external_rtp_ip /etc/freeswitch/vars.xml

Registration failures:

# Enable verbose SIP logging temporarily
sudo fs_cli -x "sofia loglevel all 9"
# Attempt registration from client, then:
sudo fs_cli -x "sofia loglevel all 0"

WebRTC connection issues:

# Verify TLS cert is valid
openssl s_client -connect your-server.example.com:7443 2>&1 | head -20

# Check mod_verto is loaded
sudo fs_cli -x "module_exists mod_verto"

Conclusion

FreeSWITCH is now installed and configured for SIP telephony, WebRTC, and conferencing. The modular XML configuration system lets you build complex PBX features, custom IVRs with Lua, and high-availability deployments. For production systems, consider adding a SIP trunk provider for PSTN connectivity and enabling TLS/SRTP throughout for encrypted communications.