Skip to content

📞 Part 2: Compiling and Packaging Telephony Server Engine on Debian 13 (Trixie)

12 min readUpdated: Sep 26, 2026
View as Markdown

Welcome to the second installment of our “Debian 13 Packaging & Distribution” series. In the previous post, we successfully built and secured our custom Debian APT repository server. In this guide, we will focus on compiling the core communications engine, Telephony Server (v1.11.1), along with its custom dependencies (SpanDSP, Sofia-SIP, libks2, signalwire-c, and libbroadvoice) from source. We will also address complex VM and clock-skew compilation traps, generate modular .deb packages, and publish them to our central repository.


🛠️ Phase 1: Setting Up the Build Environment

Section titled “🛠️ Phase 1: Setting Up the Build Environment”

Debian 13 (Trixie) utilizes modern compiler toolchains. To prepare your build node (which can be a dedicated VM or container running Debian 13), install the core development utilities.

Terminal window
apt-get update
apt-get install -y \
sudo git build-essential devscripts dpkg-dev equivs fakeroot \
autoconf automake libtool libtool-bin cmake pkg-config \
wget curl unzip python-is-python3 python3-all-dev \
erlang-dev libtpl-dev libgdbm-dev libdb-dev \
python3-setuptools docbook-xsl xsltproc \
libglib2.0-dev graphviz dh-make dh-python

1.2 Install Telephony Server Compilation Prerequisites

Section titled “1.2 Install Telephony Server Compilation Prerequisites”

Telephony Server relies on system libraries for features like SSL, database connectivity, and codecs. Run the following command to install the required header files:

Terminal window
apt-get install -y \
uuid-dev zlib1g-dev libjpeg-dev libsqlite3-dev libcurl4-openssl-dev \
libpcre2-dev libspeex-dev libspeexdsp-dev libldns-dev libedit-dev \
libtiff5-dev yasm libopus-dev libsndfile1-dev libavformat-dev \
libswscale-dev liblua5.2-dev liblua5.2-0 libpq-dev unixodbc-dev \
libxml2-dev libpq5 sngrep libswresample-dev bison doxygen \
libjansson-dev libopencv-dev libhiredis-dev libmemcached-dev \
libsphinxbase-dev libpocketsphinx-dev libopencore-amrnb-dev \
libmariadb-dev libperl-dev libgdbm-compat-dev librabbitmq-dev \
libsnmp-dev libmagickcore-dev libopusfile-dev libmp3lame-dev \
libshout3-dev libvlc-dev default-jdk mono-mcs libasound2-dev \
libcodec2-dev python-dev-is-python3

[!NOTE] PCRE Library Warning: Debian 13 completely removes libpcre3-dev (PCRE 8.x, which has reached End-of-Life). We use the modern replacement, libpcre2-dev, which Telephony Server supports natively.


📦 Phase 2: Building Telephony Dependencies

Section titled “📦 Phase 2: Building Telephony Dependencies”

Several libraries required by Telephony Server are either outdated in Debian’s official repository or require specific patches for stability. We compile them first, generate their .deb files, and install them so they are recognized during the main Telephony Server configuration phase.

SpanDSP handles critical telephony tasks such as T.38 faxing, tone detection, and classic modems.

Terminal window
cd /usr/src
git clone https://github.com/freeswitch/spandsp.git
cd spandsp
./bootstrap.sh
./configure
fakeroot debian/rules clean
dpkg-buildpackage -us -uc -b
# Isolate packages
mkdir -p /usr/src/freeswitch/deb
mv /usr/src/libspandsp*.deb /usr/src/freeswitch/deb/
# Install dependencies locally to build Telephony Server
cd /usr/src/freeswitch/deb
apt install -y ./libspandsp4_*.deb ./libspandsp4-dev_*.deb
apt-get install -f -y

This SignalWire communication library requires a custom Debian packaging structure.

Terminal window
cd /usr/src
git clone https://github.com/signalwire/libks.git
cd libks
mkdir -p debian

Create the required packaging files in the debian/ directory directly:

Defines the source and binary packages, their metadata, build-time dependencies, and runtime dependencies.

Terminal window
cat <<'EOF' > debian/control
Source: libks
Section: libs
Priority: optional
Maintainer: [YOUR_FULL_NAME] <[EMAIL_ADDRESS]>
Build-Depends: debhelper-compat (= 13), cmake, libpcre2-dev, uuid-dev
Standards-Version: 4.6.2
Homepage: https://github.com/signalwire/libks
Package: libks2
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: SignalWire libks library
A library for communication protocols developed by SignalWire.
Package: libks2-dev
Architecture: any
Depends: libks2 (= ${binary:Version}), ${misc:Depends}
Description: Development files for libks
Development headers and libraries for libks.
EOF

The makefile containing rules that dictate how the package is configured, built, and installed into temporary directories.

cat <<'EOF' > debian/rules
#!/usr/bin/make -f
%:
dh $@
override_dh_auto_configure:
cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release .
override_dh_auto_install:
dh_auto_install --destdir=debian/tmp
override_dh_auto_clean:
dh_clean
override_dh_installdocs:
dh_installdocs
dh_installdocs -plibks2-dev --link-doc=libks2
EOF

Make the script executable:

Terminal window
chmod +x debian/rules

Maintains the release history, package versioning, and change list.

Terminal window
cat <<'EOF' > debian/changelog
libks (2.0-7) unstable; urgency=medium
* Initial packaging for Debian 13.
-- [YOUR_FULL_NAME] <[EMAIL_ADDRESS]> Mon, 08 Sep 2025 20:30:00 +0000
EOF

Documents the license and copyright information for the package.

Terminal window
cat <<'EOF' > debian/copyright
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Files: *
Copyright: 2025 SignalWire, Inc.
License: MPL-1.1
EOF

2.2.5 Library Install File (debian/libks2.install)

Section titled “2.2.5 Library Install File (debian/libks2.install)”

Specifies which built files (libraries) go into the runtime binary package (libks2).

Terminal window
cat <<'EOF' > debian/libks2.install
usr/lib/libks2.so*
EOF

2.2.6 Development Install File (debian/libks2-dev.install)

Section titled “2.2.6 Development Install File (debian/libks2-dev.install)”

Specifies development assets (header files and pkg-config manifests) that go into the development package.

Terminal window
cat <<'EOF' > debian/libks2-dev.install
usr/include/libks2/*
usr/lib/pkgconfig/libks2.pc
EOF

2.2.7 Unpackaged Files List (debian/not-installed)

Section titled “2.2.7 Unpackaged Files List (debian/not-installed)”

Tells the build system to ignore generated files that are intentionally not packaged (such as the default changelog and copyright files).

Terminal window
cat <<'EOF' > debian/not-installed
usr/share/doc/libks2/changelog.Debian.gz
usr/share/doc/libks2/copyright
EOF

Now, clean, build, and install the package:

Terminal window
# Clean potential CMake residuals from manual builds
rm -rf CMakeCache.txt CMakeFiles/ cmake_install.cmake Makefile obj-*
fakeroot debian/rules clean
DEB_BUILD_OPTIONS="nocheck" dpkg-buildpackage -us -uc -b
mv /usr/src/libks2*.deb /usr/src/freeswitch/deb/
cd /usr/src/freeswitch/deb
dpkg -i libks2_*.deb libks2-dev_*.deb
apt-get install -f -y

Sofia-SIP is the underlying SIP user-agent library used by Telephony Server’s endpoint module mod_sofia.

[!IMPORTANT] Preventing Collisions with Official Debian Repository Packages: The official Debian repositories distribute standard (unpatched) versions of Sofia-SIP (libsofia-sip-ua0 and libsofia-sip-ua-dev). To prevent routine system updates (apt upgrade) from overwriting our custom patched Sofia-SIP packages, we rename all Sofia-SIP binary packages to use the prefix freeswitch-sofia-sip instead of libsofia-sip. We declare versioned Provides, Conflicts, and Replaces directives pointing to the official Debian package names in debian/control so that Telephony Server’s compilation and runtime dependencies are fully satisfied without conflicts.

Terminal window
cd /usr/src
git clone https://github.com/freeswitch/sofia-sip.git
cd sofia-sip
./bootstrap.sh
./configure
# Rename source and binary packages in debian/control and add versioned Provides/Conflicts/Replaces
python3 -c "
import re, os
content = open('debian/control').read()
content = content.replace('libsofia-sip', 'freeswitch-sofia-sip')
content = re.sub(r'(?<!freeswitch-)sofia-sip', 'freeswitch-sofia-sip', content)
packages = {
'freeswitch-sofia-sip-bin': 'sofia-sip-bin',
'freeswitch-sofia-sip-ua0': 'libsofia-sip-ua0',
'freeswitch-sofia-sip-ua-dev': 'libsofia-sip-ua-dev',
'freeswitch-sofia-sip-ua-glib3': 'libsofia-sip-ua-glib3',
'freeswitch-sofia-sip-ua-glib-dev': 'libsofia-sip-ua-glib-dev',
}
for pkg, orig in packages.items():
pattern = rf'(Package:\s*{pkg}\s*\nArchitecture:\s*any\s*\n)'
replacement = rf'\1Provides: {orig} (= \${{binary:Version}})\nConflicts: {orig}\nReplaces: {orig}\n'
content = re.sub(pattern, replacement, content)
open('debian/control', 'w').write(content)
for f in os.listdir('debian'):
if 'sofia-sip' in f and not f.startswith('freeswitch-'):
if f.startswith('libsofia-sip'):
new_f = 'freeswitch-sofia-sip' + f[len('libsofia-sip'):]
elif f.startswith('sofia-sip'):
new_f = 'freeswitch-sofia-sip' + f[len('sofia-sip'):]
else:
new_f = f
os.rename(os.path.join('debian', f), os.path.join('debian', new_f))
"
# Update source package name in debian/changelog
sed -i 's/^sofia-sip/freeswitch-sofia-sip/g' debian/changelog
# Dynamically extract current upstream version from debian/changelog (e.g., 1.13.18)
CURRENT_VER=$(dpkg-parsechangelog -S Version | sed 's/-.*//')
# Add a custom changelog entry with the +softswitch version suffix
dch -b -v "${CURRENT_VER}-0+softswitch" "Custom compile with versioned Provides"
# Clean packaging workspace and compile unsigned binary-only Debian packages
fakeroot debian/rules clean
dpkg-buildpackage -us -uc -b
# Isolate generated packages into the staging directory
mkdir -p /usr/src/freeswitch/deb
mv /usr/src/freeswitch-sofia-sip*.deb /usr/src/freeswitch/deb/
# Install custom Sofia-SIP packages locally so Telephony Server can link against them during compilation
cd /usr/src/freeswitch/deb
apt install -y ./freeswitch-sofia-sip-ua0_*.deb ./freeswitch-sofia-sip-ua-dev_*.deb ./freeswitch-sofia-sip-bin_*.deb
apt-get install -f -y

This codec library handles BroadVoice 16/32-bit audio profiles.

Terminal window
cd /usr/src
git clone https://github.com/freeswitch/libbroadvoice.git
cd libbroadvoice
./autogen.sh
./configure
fakeroot debian/rules clean
dpkg-buildpackage -us -uc -b
mv /usr/src/libbroadvoice*.deb /usr/src/freeswitch/deb/
cd /usr/src/freeswitch/deb
dpkg -i libbroadvoice1_*.deb libbroadvoice-dev_*.deb

Create the SignalWire C API library.

Terminal window
cd /usr/src
git clone https://github.com/signalwire/signalwire-c.git
cd signalwire-c
mkdir -p debian

Create the required packaging files in the debian/ directory directly:

Defines the source and binary packages, their metadata, build-time dependencies, and runtime dependencies.

Terminal window
cat <<'EOF' > debian/control
Source: signalwire-c
Section: libs
Priority: optional
Maintainer: [YOUR_FULL_NAME] <[EMAIL_ADDRESS]>
Build-Depends: debhelper-compat (= 13), cmake, libpcre2-dev, uuid-dev, libssl-dev, libjansson-dev
Standards-Version: 4.6.2
Homepage: https://github.com/signalwire/signalwire-c
Package: signalwire-client-c2
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libks2
Description: SignalWire C client library (version 2)
Package: signalwire-client-c2-dev
Architecture: any
Depends: signalwire-client-c2 (= ${binary:Version}), ${misc:Depends}, libks2-dev
Description: Development files for SignalWire C client library (version 2)
EOF

The makefile containing rules that dictate how the package is configured, built, and installed into temporary directories.

cat <<'EOF' > debian/rules
#!/usr/bin/make -f
export DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
%:
dh $@
override_dh_auto_configure:
cmake -DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=ON \
-DINSTALL_PKGCONFIG_DIR=/usr/lib/$(DEB_HOST_MULTIARCH)/pkgconfig .
override_dh_auto_install:
dh_auto_install --destdir=debian/tmp
mkdir -p debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH)/pkgconfig
mv debian/tmp/usr/lib/pkgconfig/signalwire_client2.pc debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH)/pkgconfig/
rmdir debian/tmp/usr/lib/pkgconfig
override_dh_auto_test:
: # Skip tests
override_dh_auto_clean:
dh_clean
override_dh_installdocs:
dh_installdocs
dh_installdocs -psignalwire-client-c2-dev --link-doc=signalwire-client-c2
EOF

Make the script executable:

Terminal window
chmod +x debian/rules

Maintains the release history, package versioning, and change list.

Terminal window
cat <<'EOF' > debian/changelog
signalwire-c (1.0-13) unstable; urgency=medium
* Initial package packaging for Debian 13.
-- [YOUR_FULL_NAME] <[EMAIL_ADDRESS]> Mon, 08 Sep 2025 22:00:00 +0000
EOF

2.5.4 Install File (debian/signalwire-client-c2.install)

Section titled “2.5.4 Install File (debian/signalwire-client-c2.install)”

Specifies which built files (libraries) go into the runtime binary package (signalwire-client-c2).

Terminal window
cat <<'EOF' > debian/signalwire-client-c2.install
usr/lib/libsignalwire_client2.so*
EOF

2.5.5 Development Install File (debian/signalwire-client-c2-dev.install)

Section titled “2.5.5 Development Install File (debian/signalwire-client-c2-dev.install)”

Specifies development assets (header files and pkg-config manifests) that go into the development package.

Terminal window
cat <<'EOF' > debian/signalwire-client-c2-dev.install
usr/include/signalwire-client-c2/*
usr/lib/*/pkgconfig/signalwire_client2.pc
EOF

2.5.6 Unpackaged Files List (debian/not-installed)

Section titled “2.5.6 Unpackaged Files List (debian/not-installed)”

Tells the build system to ignore generated files that are intentionally not packaged (such as the default changelog and copyright files).

Terminal window
cat <<'EOF' > debian/not-installed
usr/share/doc/signalwire-client-c2/changelog.Debian.gz
usr/share/doc/signalwire-client-c2/copyright
EOF

Build and install:

Terminal window
fakeroot debian/rules clean
dpkg-buildpackage -us -uc -b
mv /usr/src/signalwire-client-c2*.deb /usr/src/freeswitch/deb/
cd /usr/src/freeswitch/deb
dpkg -i signalwire-client-c2_*.deb signalwire-client-c2-dev_*.deb
apt-get install -f -y

⚙️ Phase 3: Compiling & Packaging Telephony Server

Section titled “⚙️ Phase 3: Compiling & Packaging Telephony Server”

Now that our compilation node is loaded with all custom dependencies, we clone Telephony Server and structure our Debian builds.

We will dynamically fetch and clone the latest stable Telephony Server release tag (or you may target a specific release like v1.11.1):

Terminal window
cd /usr/src
# Dynamically resolve the latest release tag (e.g., v1.11.1)
FS_TAG=$(git ls-remote --tags --sort="v:refname" https://github.com/signalwire/freeswitch.git | grep -o 'refs/tags/v[0-9].*' | cut -d/ -f3 | grep -v '\^{}' | tail -n1)
# Clone the latest stable release
git clone -b "${FS_TAG}" --depth 1 https://github.com/signalwire/freeswitch.git /usr/src/freeswitch/src
cd /usr/src/freeswitch/src
./bootstrap.sh -j
# Prevent file system timestamp skew loop
find . -type f -exec touch {} +
./configure \
--enable-core-odbc-support \
--enable-core-pgsql-support \
--enable-pcre2 \
--prefix=/usr \
--sysconfdir=/etc \
--localstatedir=/var \
--disable-maintainer-mode \
--disable-dependency-tracking
  • --enable-core-odbc-support & --enable-core-pgsql-support: Compiles native database connectivity (ODBC & direct PostgreSQL) directly into Telephony Server’s core library (libfreeswitch), enabling channel state persistence, multi-tenant directory lookups, and real-time CDR logging.
  • --enable-pcre2: Mandates the use of modern Perl-Compatible Regular Expressions (PCRE2). This is strictly required for Debian 13 (Trixie), where legacy libpcre3 has been completely deprecated.
  • --prefix=/usr, --sysconfdir=/etc, --localstatedir=/var: Conforms Telephony Server directory paths to standard Debian Filesystem Hierarchy Standard (FHS) conventions (/usr/bin, /etc/freeswitch, /var/log/freeswitch, /var/lib/freeswitch).
  • --disable-maintainer-mode & --disable-dependency-tracking: Prevents Autotools from triggering automatic and infinite Makefile regeneration loops due to container/VM filesystem timestamp skew, while significantly reducing overall build time.

3.2 Add Custom Workarounds for Debian 13 Packaging

Section titled “3.2 Add Custom Workarounds for Debian 13 Packaging”

Before launching dpkg-buildpackage, we must bypass several known packaging issues:

  1. Incompatible Modules: Exclude legacy features like V8/Javascript and obsolete audio codecs (silk, ilbc, flite) that are not compatible with Debian 13 build environments.
  2. dh_auto_clean Recursion Loop: Autotools comparisons can trigger an infinite build cleaner recursion loop. We override this loop as a no-op.
  3. Parallel Race Condition: Generating modules.inc under concurrent build jobs (e.g., -j8) results in race conditions. We force sequential module packaging.

Run these adjustments:

Terminal window
cd /usr/src/freeswitch/src/debian
# Exclude incompatible modules from packaging bootstrap
sed -i '/xml_int\/mod_xml_ldap/a\ languages/mod_v8\n languages/mod_basic\n asr_tts/mod_flite\n codecs/mod_ilbc\n codecs/mod_silk\n languages/mod_managed' bootstrap.sh
# Re-run bootstrap to regenerate control and rules definitions
./bootstrap.sh -c trixie
# Prevent auto clean recursive loops in rules
echo "" >> rules
echo "override_dh_auto_clean:" >> rules
printf "\t:\n" >> rules
# Clean up missing dependencies in control metadata
sed -i '/freeswitch-meta-codecs (= ${binary:Version}),/d' control
sed -i '/freeswitch-music,/d' control
sed -i '/freeswitch-sounds,/d' control
sed -i '/freeswitch-mod-flite (= ${binary:Version}),/d' control

Update debian/changelog dynamically with the cloned version metadata:

Terminal window
# Dynamically extract version from configure.ac (or fallback to FS_TAG)
FS_VER=$(sed -n 's/.*AC_INIT(\[freeswitch\],[ ]*\[\([^]]*\)\].*/\1/p' ../configure.ac)
FS_VER=${FS_VER:-${FS_TAG#v}}
cat > changelog <<EOF
freeswitch (${FS_VER}-1) unstable; urgency=medium
* Repackage Telephony Server ${FS_VER} for Debian 13.
* Disable incompatible audio modules and configure make workarounds.
-- [YOUR_FULL_NAME] <[EMAIL_ADDRESS]> $(date -R)
EOF

Synchronize all file timestamps to prevent GNU Make from triggering file skew regenerations, then run the sequential build command:

Terminal window
cd /usr/src/freeswitch/src
find . -type f -exec touch {} +
# Clean out temporary debug assets
fakeroot debian/rules clean
rm -rf debian/python-esl-dbg debian/libfreeswitch1-dbg
# Execute sequential packaging
DEB_BUILD_OPTIONS="parallel=1" dpkg-buildpackage -us -uc -b -d

Once compilation completes, move all created .deb files into the local directory /usr/src/freeswitch/deb/:

Terminal window
mkdir -p /usr/src/freeswitch/deb
mv /usr/src/freeswitch/*.deb /usr/src/freeswitch/deb/ 2>/dev/null || true
mv /usr/src/freeswitch/libfreeswitch*.deb /usr/src/freeswitch/deb/ 2>/dev/null || true
mv /usr/src/freeswitch/libesl*.deb /usr/src/freeswitch/deb/ 2>/dev/null || true
mv /usr/src/freeswitch/python-esl*.deb /usr/src/freeswitch/deb/ 2>/dev/null || true

🌐 Phase 4: Publishing to the APT Repository Server

Section titled “🌐 Phase 4: Publishing to the APT Repository Server”

Now that our packages are compiled and isolated locally in /usr/src/freeswitch/deb/, we upload them to our repository server (IP: <YOUR_REPO_IP>, configured in Part 1).

Section titled “4.1 Setup SSH Key Authentication (Optional but Recommended)”

To upload packages without entering the remote server password every time, configure SSH key-based authentication from your build node to the repository server:

  1. Generate SSH Key on your build node (if you do not have one):

    Terminal window
    ssh-keygen -t rsa -b 4096 -C "build-node"
    # Press Enter to accept defaults (do not set a passphrase for automation)
  2. Copy the public key to the repository server:

    Terminal window
    ssh-copy-id -i ~/.ssh/id_rsa.pub root@<YOUR_REPO_IP>
    # Alternatively, using cat:
    # cat ~/.ssh/id_rsa.pub | ssh root@<YOUR_REPO_IP> "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys"
  3. Verify passwordless access:

    Terminal window
    ssh root@<YOUR_REPO_IP> "echo 'SSH Connection Successful!'"

From your build node, secure copy the packages directly to the repository upload directory:

Terminal window
scp /usr/src/freeswitch/deb/*.deb root@<YOUR_REPO_IP>:/usr/src/

Log into your repository server over SSH, organize the files into their target component directories, and rebuild the repository signatures:

Terminal window
ssh root@<YOUR_REPO_IP>
# Sort packages into pool components (base, extras, devel, etc.)
CopyPackagesToRepo
# Rebuild package indexes and sign Release signatures
BuildRepoRing2All

Once completed, the packages are immediately ready for secure deployment.


Our repository server now serves Telephony core engines and custom dependencies over HTTPS. In Part 3: Compiling and Packaging Kamailio on Debian 13, we will complete our setup by packaging the high-performance SIP router Kamailio (v6.1), publishing it, and executing our end-to-end client installation.