🏢 Part 8: Enterprise-Grade Distributed Deployment on Debian 13
Welcome to the eighth and final installment of our "Debian 13 Clustering & Distribution" series. In the previous articles, we packaged FreeSWITCH, Kamailio, and RTPEngine, and explored individual high-availability storage and database clustering configurations. In this final guide, we will unify these concepts into a production-ready, multi-server enterprise environment. We will walk through setting up a complete distributed topology on Debian 13 (Trixie). We will configure a replicated PostgreSQL 17 cluster, a high-availability GlusterFS storage network, and local HAProxy proxy configurations on application nodes for transparent database routing. We will also install our application APIs and frontend portals, deploy dedicated FreeSWITCH telephony nodes connecting via ODBC and mounting shared media files, detail credentials distribution, and establish troubleshooting and validation checks for cross-service connectivity.🏗️ Architecture Overview
In a distributed deployment, each component is decoupled and assigned to dedicated servers to ensure high availability, redundancy, and maximum horizontal scalability.
🖥️ Server Roles & Requirements
To set up a production-ready lab, we allocate dedicated servers with the following configurations:
| Role | Hostname | Example IP | Target Package | Minimum Spec |
|---|---|---|---|---|
| DB Primary | db-primary | 192.168.10.34 | softswitch-db | 4 vCPU, 16GB RAM, SSD |
| DB Replica 1 | db-replica1 | 192.168.10.35 | PostgreSQL 17 (Manual) | 4 vCPU, 16GB RAM, SSD |
| DB Replica 2 | db-replica2 | 192.168.10.36 | PostgreSQL 17 (Manual) | 4 vCPU, 16GB RAM, SSD |
| GlusterFS 1 | fs01 | 192.168.10.37 | glusterfs-server | 2 vCPU, 4GB RAM, Storage |
| GlusterFS 2 | fs02 | 192.168.10.38 | glusterfs-server | 2 vCPU, 4GB RAM, Storage |
| GlusterFS 3 | fs03 | 192.168.10.39 | glusterfs-server | 2 vCPU, 4GB RAM, Storage |
| Admin Server | admin | 192.168.10.40 | softswitch-admin, softswitch-api | 2 vCPU, 4GB RAM, SSD |
| Portal Server | portal | 192.168.10.41 | softswitch-portal | 2 vCPU, 2GB RAM, SSD |
| Telephony 1 | fs-01 | 192.168.10.30 | softswitch-telephony | 4 vCPU, 8GB RAM, SSD |
🛠️ Step-by-Step Deployment Guide
Phase 0: Install PostgreSQL 17 on Database Servers
Execute these tasks on all three database nodes (192.168.10.34, 192.168.10.35, and 192.168.10.36) to build the database engine base before configuring the cluster layers.
Do not install the Ring2All package repositories on the database replica servers. They only require PostgreSQL 17. The repository configuration and softswitch-db schemas should be registered solely on the DB Primary node.
0.1 Install PostgreSQL 17 Base
PostgreSQL 17 is available natively in the Debian 13 (Trixie) main repository:
0.2 Verify Cluster Directories
If pg_lsclusters prints an "Invalid data directory" error, append the directory path to the config file manually:
Verify service execution:
Phase 1: Database Cluster Setup (DB Primary)
Log in to the DB Primary server (192.168.10.34) to initialize the database configurations and schemas.
1.1 Register Repository and Install Database Package
Verify the generated DB credentials. Note down the password:
1.2 Configure PostgreSQL for Streaming Replication
Replace /etc/postgresql/17/main/postgresql.conf on the Primary server with the following settings:
1.3 Configure Client and Replication Authentication
Add the network access blocks to the end of /etc/postgresql/17/main/pg_hba.conf:
1.4 Create Replication User
Log in to PostgreSQL CLI on the Primary and create the replication user:
1.5 Restart PostgreSQL Primary
Phase 2: Configure Database Replica Nodes
Run these steps on the DB Replicas (192.168.10.35 and 192.168.10.36).
The performance configuration variables (shared_buffers, max_connections, etc.) in postgresql.conf on the Replicas must be equal to or higher than those on the Primary. Otherwise, replication will fail to initialize.
2.1 Write Configuration
Deploy the replication configuration file:
2.2 Rebuild Data Directory
Stop the local database service and wipe the default database file system:
2.3 Bootstrap Directory from Primary
Sync the database files from the Primary database node using pg_basebackup:
2.4 Set Directory Owner Permissions
Because pg_basebackup runs as root, update permissions to the postgres user:
2.5 Confirm Replication Link
Check if the server successfully started in recovery/replica mode:
Check the active replica streams on the Primary database node (192.168.10.34):
streaming state.
Phase 3: GlusterFS Shared Storage Cluster Setup
GlusterFS provides a distributed file system so all client servers can access recordings, uploads, and media folders concurrently.
3.1 Install GlusterFS Server on Storage Nodes
Run these commands on the three storage nodes (192.168.10.37, 192.168.10.38, and 192.168.10.39):
3.2 Update Network Hosts Resolutions
Add name resolutions on all three storage nodes:
3.3 Peer Cluster Probe (Only from fs01)
Establish the trusted storage pool by probing peers from fs01 (192.168.10.37):
3.4 Create Data Brick Directories
Create brick paths on all three storage nodes:
3.5 Create Replicated Volumes (Only from fs01)
Configure three-way replication volumes to ensure data remains online if a storage node fails:
Phase 4: Local HAProxy Configurations on Client Nodes
To handle database primary-replica routing transparently, we deploy HAProxy locally on every application and telephony node (e.g., Admin API, Telephony servers).
All local applications configure their database connection string to point to 127.0.0.1. Local HAProxy routes write requests on port 5000 to the Primary database node, and load balances read requests on port 5001 across the standby replicas.
Write the configuration into /etc/haproxy/haproxy.cfg:
Validate and restart the HAProxy service:
Phase 5: Admin Server Setup
Log in to the Admin Server (192.168.10.40).
5.1 System Pre-requisites and Repositories
Configure repositories as shown in Phase 1. Install prerequisites:
5.2 Configure HAProxy
Configure a local HAProxy proxy on this node following Phase 4. Verify that port 5000 is listening locally:
5.3 Copy Database Credentials
Create the config path and copy the /etc/softswitch/db-credentials file from the DB Primary node:
5.4 Install API Packages
Install the REST API and telemetry modules. The post-installation script detects local HAProxy port 5000 and automatically links the configurations:
Install packages dependencies for the monitoring service:
5.5 Mount Shared Storage Volumes
Install the client tools and mount the shared storage uploads directory:
5.6 Install Frontend Admin Dashboard
Phase 6: Portal & Switchboard Frontends Setup
You can deploy the Portal and Switchboard frontends on the same Admin server (using virtual directories under /portal and /switchboard) or split them onto separate hosts.
Option A: Deployment on the Admin Server
The packages register static directories inside /var/www/softswitch/ and hook into the Nginx configuration block automatically.
Option B: Dedicated Servers (e.g. Portal on 192.168.10.41)
Add Nginx and repository settings on the target server, then install the package:
Create a proxy configuration at /etc/nginx/sites-available/softswitch-portal to forward API requests to the Admin API:
Link and activate the virtual host block:
Phase 7: Telephony Server Setup (FreeSWITCH Client Node)
Log in to the Telephony Server (192.168.10.30).
7.1 Register Repositories and Install Base Dependencies
7.2 Install local HAProxy Proxy
Follow Phase 4 to install and configure local HAProxy routing on the telephony node.
7.3 Fetch DB Credentials File
Copy the credentials from the DB Primary node:
7.4 Mount Shared Storage Volumes
Mount the recordings and music volumes:
7.5 Install Telephony Modules
Install the custom softswitch-telephony configurations. The post-installation script will detect the local database proxy on port 5000 and write matching /etc/odbc.ini profiles automatically:
7.6 Telephony Domain Aliasing
If the internal SIP profile fails to start or report domain errors, configure a domain IP alias using SQL over the database proxy:
7.7 Map Telephony node to the Admin Monitoring API
Configure the telemetry API on the Admin server (192.168.10.40) to hook into this FreeSWITCH node ESL socket:
Update parameters to match the telephony server IP and default ClueCon secret:
Restart the service to initialize connections:
🔑 Secure Credentials Distribution
To distribute generated keys securely across the cluster network, run this wrapper helper script from the DB Primary node:
🔍 Validation Checklist
Review this checklist to ensure all distributed platform modules are connected:
1. Database Clustering
- [ ] Database replication shows a delay close to zero.
- [ ] Read requests are distributed across all three replication nodes via port 5001.
- [ ] Write requests are successfully routed to the Primary database node via port 5000.
2. Storage Clustering
- [ ] GlusterFS volumes report healthy and synchronized brick status (
gluster volume status). - [ ] Files written to
/var/lib/freeswitch/recordingssynchronize to all storage bricks.
3. Telephony Connectivity
- [ ] FreeSWITCH successfully connects to database schemas via ODBC.
- [ ] The
fs_cli -x "sofia status"command reports the internal and external profiles as RUNNING. - [ ] SIP devices can register and route calls using any telephony node IP.
📈 Capacity & Scaling Guidelines
Refer to this guide to plan your cluster deployment architecture:
| Concurrent Calls | Telephony Nodes | Database Configuration | Storage Type |
|---|---|---|---|
| < 100 | 1 | Single Local DB | Local Filesystem |
| 100–500 | 2 | Single Dedicated DB | Replicated GlusterFS (2 Nodes) |
| 500–1,000 | 3 | Replicated Primary + Replica | Replicated GlusterFS (3 Nodes) |
| 1,000–5,000 | 4–8 | Patroni Cluster (3+ Nodes) | Distributed-Replicated GlusterFS |
| > 5,000 | 8+ | High-Availability Cluster | Dedicated Storage Array / SAN |
🔍 Troubleshooting
1. Database connection is refused from clients
- Cause: The
/etc/postgresql/17/main/pg_hba.conffile on the target database nodes is missing client IP permissions, or local firewalls are blocking port5432. - Fix: Verify client subnet matching:
Run a TCP socket check from the client to the database node:
2. FreeSWITCH logs "CORE DATABASE INITIALIZATION FAILURE"
- Cause: The core system-level DSN connection is misaligned in
/etc/freeswitch/autoload_configs/switch.conf.xml. - Fix: Check
core-db-dsn. If the parameters are pointing directly to the database IP or port 5432, change the endpoint to the local HAProxy write interface:
Restart FreeSWITCH to reinitialize the SQL engine:
3. Web portal returns "502 Bad Gateway" on dashboard widgets
- Cause: The
softswitch-monitoring-apipackage was not installed or lacks required npm library dependencies. - Fix: Verify systemd status:
If dependencies are missing, run a manual npm build step:
This concludes our 8-part Debian 13 Clustering and Distribution series. You now have a complete, production-ready, enterprise-grade softswitch platform deployed on Debian 13.