Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/signalwire/freeswitch/llms.txt

Use this file to discover all available pages before exploring further.

A FreeSWITCH instance exposed to the public internet is a high-value target. Unprotected SIP ports are continuously scanned for open registrations that can be exploited for toll fraud — where attackers generate thousands of dollars of calls within minutes using compromised credentials. Before putting a FreeSWITCH system into production, you should address every layer of the security model: network-level IP filtering, transport encryption, application authentication, media encryption, and operating system permissions.

Access Control Lists (ACLs)

ACLs are the first line of defense. FreeSWITCH’s mod_acl lets you define named IP-address lists and then reference those lists in SIP profile configurations to restrict which hosts can send SIP traffic or register endpoints.

Configuring ACLs

ACL lists are defined in conf/autoload_configs/acl.conf.xml:
<configuration name="acl.conf" description="Network Lists">
  <network-lists>
    <!--
      These ACL lists are created automatically at startup:
        rfc1918.auto  - All RFC 1918 private address space
        nat.auto      - RFC 1918 space excluding your local LAN
        localnet.auto - Your local LAN subnet
        loopback.auto - 127.0.0.0/8
    -->

    <!-- Allow the whole LAN, but deny one specific host -->
    <list name="lan" default="allow">
      <node type="deny"  cidr="192.168.42.0/24"/>
      <node type="allow" cidr="192.168.42.42/32"/>
    </list>

    <!-- Allow directory users who have a cidr= attribute set,
         as if they had authenticated with digest credentials -->
    <list name="domains" default="deny">
      <node type="allow" domain="$${domain}"/>
      <!-- <node type="allow" cidr="192.168.0.0/24"/> -->
    </list>

  </network-lists>
</configuration>

Applying ACLs to SIP Profiles

After defining an ACL list, reference it inside your Sofia SIP profile XML (conf/sip_profiles/internal.xml or external.xml) using the apply-inbound-acl and apply-register-acl parameters:
<!-- Only allow SIP INVITE from trusted networks -->
<param name="apply-inbound-acl" value="lan"/>

<!-- Only allow REGISTER from the domains ACL -->
<param name="apply-register-acl" value="domains"/>
Leaving SIP port 5060 open to the public internet without ACL protection is one of the most common vectors for VoIP toll fraud. Attackers run automated scanners that attempt SIP REGISTER with common username/password combinations. Even a short window of exposure can result in thousands of dollars of fraudulent calls. Always restrict registration to trusted IP ranges.

ESL Security

The Event Socket Layer (ESL) provides full programmatic control over FreeSWITCH, including the ability to originate calls, intercept media, and reload configuration. Its security must be treated with the same care as a root SSH session.

Default Configuration

The default conf/autoload_configs/event_socket.conf.xml ships with a well-known password and listens on all interfaces:
<configuration name="event_socket.conf" description="Socket Client">
  <settings>
    <param name="nat-map"      value="false"/>
    <param name="listen-ip"    value="::"/>
    <param name="listen-port"  value="8021"/>
    <param name="password"     value="ClueCon"/>
    <!-- Restrict to loopback only: -->
    <!--<param name="apply-inbound-acl" value="loopback.auto"/>-->
    <!--<param name="stop-on-bind-error" value="true"/>-->
  </settings>
</configuration>

Hardening ESL

Apply all three of the following changes before exposing a system to any untrusted network:
1

Change the default password

Replace ClueCon with a strong, unique password of at least 24 random characters.
<param name="password" value="YourStrongRandomPasswordHere"/>
2

Bind to loopback only

Change listen-ip from :: (all interfaces) to 127.0.0.1 so ESL is not reachable from the network at all.
<param name="listen-ip" value="127.0.0.1"/>
3

Apply an inbound ACL

Uncomment apply-inbound-acl and reference the loopback.auto list (or a custom list of trusted management hosts) as an additional guard.
<param name="apply-inbound-acl" value="loopback.auto"/>

SIP TLS

SIP signaling travels over UDP or TCP in plaintext by default, making it possible for an attacker on the network path to intercept credentials, read dial plans, or inject fraudulent SIP messages. Enabling TLS on a Sofia SIP profile encrypts signaling between FreeSWITCH and endpoints.

Enabling TLS in a SIP Profile

Add the following parameters to your SIP profile XML (e.g., conf/sip_profiles/internal.xml):
<!-- Enable TLS transport -->
<param name="tls"          value="true"/>
<param name="tls-only"     value="false"/>  <!-- set true to disable plain UDP/TCP -->
<param name="tls-bind-params" value="transport=tls"/>
<param name="tls-sip-port"    value="5061"/>

<!-- Directory containing the PEM certificate files -->
<param name="tls-cert-dir"   value="$${certs_dir}"/>

<!-- Minimum TLS version: tlsv1, tlsv1.1, tlsv1.2 -->
<param name="tls-version"    value="tlsv1.2"/>

Generating Certificates with gentls_cert

FreeSWITCH ships a shell script (scripts/gentls_cert) that creates a self-signed CA and server certificate suitable for TLS SIP and WSS (WebSocket Secure).
# Step 1: Create the Certificate Authority
gentls_cert setup

# Step 2: Generate a server certificate signed by your new CA
# Replace 'yourdomain.example.com' with your actual hostname or IP
gentls_cert create -cn yourdomain.example.com -alt DNS:yourdomain.example.com -out agent.pem

# Step 3: Verify the output files in the certs directory
ls /usr/local/freeswitch/certs/
# CA/cacert.pem   CA/cakey.pem   agent.pem   cafile.pem
The resulting files are:
FilePurpose
CA/cacert.pemCA certificate (distribute to endpoints that need to trust the server).
agent.pemCombined server certificate + private key (used by FreeSWITCH).
cafile.pemCopy of the CA cert for Sofia’s tls-cafile parameter.

Enabling TLS in vars.xml

You can also enable TLS globally by setting pre-processor variables in conf/vars.xml:
<X-PRE-PROCESS cmd="set" data="internal_ssl_enable=true"/>
<X-PRE-PROCESS cmd="set" data="external_ssl_enable=true"/>

Testing the TLS Connection

openssl s_client -connect yourdomain.example.com:5061

SRTP

TLS encrypts SIP signaling, but the media stream (RTP audio) remains in plaintext unless you also enable SRTP. SRTP negotiation is handled automatically during SDP offer/answer when configured on the SIP profile.

Enabling SRTP

Add rtp-secure-media to your SIP profile:
<!-- Require SRTP for all calls on this profile -->
<param name="rtp-secure-media" value="true"/>

<!-- Or offer SRTP but allow fallback to plain RTP -->
<param name="rtp-secure-media" value="optional"/>

<!-- Require SRTP, and use the SDES key exchange method -->
<param name="rtp-secure-media" value="mandatory"/>
Avoid storing SRTP encryption keys in CDRs or channel variables. The switch.conf.xml parameter rtp-retain-crypto-keys defaults to false — leave it that way. Enabling it exposes call media to anyone with CDR read access.

Running as Non-Root

FreeSWITCH does not need to run as root for normal operation. Running as a dedicated, unprivileged system user limits the blast radius if the process is ever compromised.

Creating a Dedicated User

# Create a system user and group with no login shell
adduser --system --group --no-create-home --shell /usr/sbin/nologin freeswitch

# Assign ownership of FreeSWITCH directories
chown -R freeswitch:freeswitch /etc/freeswitch
chown -R freeswitch:freeswitch /var/lib/freeswitch
chown -R freeswitch:freeswitch /var/log/freeswitch
chown -R freeswitch:freeswitch /var/run/freeswitch
chown -R freeswitch:freeswitch /usr/local/freeswitch

Starting FreeSWITCH as the Dedicated User

Use the -u and -g flags to drop privileges immediately after startup:
freeswitch -ncwait -u freeswitch -g freeswitch
If you also want core dumps when running as a non-root user, you may need to adjust the kernel’s suid dump behavior:
sysctl -w fs.suid_dumpable=1

Firewall Recommendations

A well-configured host firewall is essential for any production deployment. The following ports should be considered:
PortProtocolDirectionPurpose
5060UDP/TCPInboundSIP signaling (restrict with ACLs or whitelist)
5061TCPInboundSIP over TLS
5080UDP/TCPInboundOutbound SIP profile (carrier traffic)
8021TCPInboundEvent Socket Layer — never expose publicly
16384–32768UDPInbound/OutboundRTP media streams
# Example iptables rules (adjust interface and IP ranges for your environment)

# Allow SIP only from trusted CIDR ranges
iptables -A INPUT -p udp --dport 5060 -s 192.168.0.0/16 -j ACCEPT
iptables -A INPUT -p udp --dport 5060 -j DROP

# Allow TLS SIP
iptables -A INPUT -p tcp --dport 5061 -j ACCEPT

# Block ESL from everything except loopback
iptables -A INPUT -p tcp --dport 8021 -s 127.0.0.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 8021 -j DROP

# Allow RTP media
iptables -A INPUT -p udp --dport 16384:32768 -j ACCEPT

Fail2Ban Integration

mod_fail2ban (or alternatively the standalone fail2ban daemon reading FreeSWITCH logs) can automatically ban IP addresses that make repeated failed authentication attempts — a common pattern in SIP brute-force attacks targeting registration credentials.

fail2ban Filter for FreeSWITCH Log Files

Create /etc/fail2ban/filter.d/freeswitch.conf:
[Definition]
failregex = \[WARNING\] sofia_reg.c:\d+ SIP auth failure \(REGISTER\) on sofia profile \'[^']+\' for \[.*\] from ip <HOST>
            \[WARNING\] sofia_reg.c:\d+ SIP auth failure \(INVITE\) on sofia profile \'[^']+\' for \[.*\] from ip <HOST>
ignoreregex =
Create /etc/fail2ban/jail.d/freeswitch.conf:
[freeswitch]
enabled  = true
port     = 5060,5061,5080
protocol = udp
filter   = freeswitch
logpath  = /var/log/freeswitch/freeswitch.log
maxretry = 5
findtime = 60
bantime  = 3600
After editing, reload fail2ban:
systemctl reload fail2ban
fail2ban-client status freeswitch

Build docs developers (and LLMs) love