FreeSWITCH Installation

Add ARP filter because we have two NICs:

echo "net.ipv4.conf.all.arp_filter = 1" >> /etc/sysctl.conf

Download the installer:

mkdir -p /usr/src/djangopbx-install
cd /usr/src/djangopbx-install
wget https://codeberg.org/djangopbx/djangopbx-install.sh/raw/branch/main/install.sh
nano install.sh

Make the following changes to the configuration section:

# Scaling and Clustering Options
freeswitch_core_in_postgres="no"
use_rabbitmq_broker="no"
install_rabbitmq_local="no"
install_postgresql_local="no"
install_freeswitch_local="yes"
install_djangopbx_local="no"
install_remote_event_receiver="yes"

It is not required but, for reference, you can add the RabbitMQ password for the AMQP Broker installer output. Change:

rabbitmq_password=random, edit "random" to read the correct value.

Run the installer:

chmod +x install.sh
./install.sh

If the installer completed successfully, we now we need to edit the configuration files in /home/django-pbx/freeswitch/autoload_configs.

  1. amqp.conf.xml

    <connection name=”primary”> for both producers and commands: edit hostname, user and password. For more details, please see the configuring mod_amqp section below.

  2. httapi.conf.xml

    <param name=”gatewau-url”>: edit url in all sections

  3. xml_curl.conf.xml

    edit gateway-url in all sections to point to the private LAN IP of your DjangoPBX

  4. lua.conf.xml

    comment out the hook scripts for registration and callcenter events, these will now be handled by AMQP.

Edit /etc/nftables.conf and add in your DjangoPBX and Filestore IP addresses to the ipv4_white_list or, alternatively, whitelist the whole private subnet e.g. 172.20.20.0/23

Now reboot. Comment out or disable the crontab for the django-pbx user.

Configuring mod_amqp

All of the FreeSWITCH configuration can be managed from within the DjangoPBX application. However, for the initial setup, there is somewhat of a “chicken and egg” situation whereby DjangoPBX will control the configuration of the FreeSWITCHes but not until the FreeSWITCHes have been configured correctly in the first place! Configuring mod_amqp is an important step in this process.

Once DjangoPBX is configured correctly for cluster working, it can write out files like a new vars.xml and/or modules.conf.xml to all the connected FreeSWITCHes, but until the whole cluster configuration is complete, vars.xml and modules.conf.xml will need to be configured manually.

You should make sure mod_amqp is enabled in the /home/django-pbx/freewitch/autoload_configs/modules.conf.xml file:

<!-- Event Handlers -->
<load module="mod_event_socket"/>
<load module="mod_amqp"/>

At the end of this section there is a typical amqp.conf.xml as an example that can be viewed for reference. The <connections> sections have both hostname and password items that need to be edited. The hostname is either the hostname or IP of your RabbitMQ server and the password is the RabbitMQ password generated by the amqp-broker-standalone-install.sh install script. If the configuration variable $rabbitmq_password in the amqp-broker-standalone-install.sh install script is set to random, the installer will generate a password. Any passwords both generated or specified are written to /root/djangopbx-passwords.txt.

Below is an example /home/django-pbx/freeswitch/autoload_configs/amqp.conf.xml for a test cluster, note - 172.20.20.102 is the private LAN IP address of the amqp message broker (RabbitMq):

<configuration name="amqp.conf" description="mod_amqp">
 <producers>
   <profile name="default">
     <connections>
   <connection name="primary">
     <param name="hostname" value="172.20.20.102"/>
     <param name="virtualhost" value="/"/>
     <param name="username" value="djangopbx"/>
     <param name="password" value="xxxxxxxxxxxxxxxxxxxx"/>
     <param name="port" value="5672"/>
     <param name="heartbeat" value="0"/>
   </connection>
   <!-- <connection name="secondary">
     <param name="hostname" value="localhost"/>
     <param name="virtualhost" value="/"/>
     <param name="username" value="djangopbx"/>
     <param name="password" value="djangopbx-insecure"/>
     <param name="port" value="5672"/>
     <param name="heartbeat" value="0"/>
   </connection> -->
     </connections>
     <params>
   <param name="exchange-name" value="TAP.Events"/>
   <param name="exchange-type" value="topic"/>
   <param name="circuit_breaker_ms" value="10000"/>
   <param name="reconnect_interval_ms" value="1000"/>
   <param name="send_queue_size" value="5000"/>
   <param name="enable_fallback_format_fields" value="1"/>

   <!-- The routing key is made from the format string, using the header values in the event specified in the format_fields.-->
   <!-- Fields that are prefixed with a # are treated as literals rather than doing a header lookup -->
   <param name="format_fields" value="#FreeSWITCH,FreeSWITCH-Hostname,Event-Name,Event-Subclass,Unique-ID"/>

   <!-- If enable_fallback_format_fields is enabled, then you can | separate event headers, and if the first does not exist
        then the system will check additional configured header values.
   -->
   <!-- <param name="format_fields" value="#FreeSWITCH,FreeSWITCH-Hostname|#Unknown,Event-Name,Event-Subclass,Unique-ID"/> -->

   <!-- <param name="event_filter" value="SWITCH_EVENT_ALL"/> -->
   <param name="event_filter" value="CUSTOM,CHANNEL_HANGUP_COMPLETE,CHANNEL_CALLSTATE,RECORD_STOP,CHANNEL_HOLD,CHANNEL_UNHOLD,DTMF"/>
     </params>
   </profile>
 </producers>
 <commands>
   <profile name="default">
     <connections>
   <connection name="primary">
     <param name="hostname" value="172.20.20.102"/>
     <param name="virtualhost" value="/"/>
     <param name="username" value="djangopbx"/>
     <param name="password" value="xxxxxxxxxxxxxxxxxxxx"/>
     <param name="port" value="5672"/>
     <param name="heartbeat" value="0"/>
   </connection>
     </connections>
     <params>
   <param name="exchange-name" value="TAP.Commands"/>
   <param name="binding_key" value="$${hostname}_command"/>
   <param name="reconnect_interval_ms" value="1000"/>
   <param name="queue-passive" value="false"/>
   <param name="queue-durable" value="false"/>
   <param name="queue-exclusive" value="false"/>
   <param name="queue-auto-delete" value="true"/>
   <param name="queue-name" value="$${hostname}_command"/>
     </params>
   </profile>
 </commands>
 <!---  <logging>
   <profile name="default">
     <connections>
   <connection name="primary">
     <param name="hostname" value="localhost"/>
     <param name="virtualhost" value="/"/>
     <param name="username" value="djangopbx"/>
     <param name="password" value="djangopbx-insecure"/>
     <param name="port" value="5672"/>
     <param name="heartbeat" value="0"/>
   </connection>
     </connections>
     <params>
   <param name="exchange-name" value="TAP.Logging"/>
   <param name="send_queue_size" value="5000"/>
   <param name="reconnect_interval_ms" value="1000"/>
   <param name="log-levels" value="warning,err,crit,alert"/>
     </params>
   </profile>
 </logging> -->
</configuration>