📞 Part 2: Compiling and Packaging FreeSWITCH on Debian 13 (Trixie)
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, FreeSWITCH (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
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.
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 FreeSWITCH Compilation Prerequisites
FreeSWITCH relies on system libraries for features like SSL, database connectivity, and codecs. Run the following command to install the required header files:
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 FreeSWITCH supports natively.
📦 Phase 2: Building Telephony Dependencies
Several libraries required by FreeSWITCH 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 FreeSWITCH configuration phase.
2.1 spandsp (v3.0)
SpanDSP handles critical telephony tasks such as T.38 faxing, tone detection, and classic modems.
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/libspandsp3*.deb /usr/src/freeswitch/deb/
# Install dependencies locally to build FreeSWITCH
cd /usr/src/freeswitch/deb
dpkg -i libspandsp3_*.deb libspandsp3-dev_*.deb
apt-get install -f -y
2.2 libks (v2.0)
This SignalWire communication library requires a custom Debian packaging structure.
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:
2.2.1 Control File (debian/control)
Defines the source and binary packages, their metadata, build-time dependencies, and runtime dependencies.
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
2.2.2 Rules File (debian/rules)
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:
2.2.3 Changelog File (debian/changelog)
Maintains the release history, package versioning, and change list.
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
2.2.4 Copyright File (debian/copyright)
Documents the license and copyright information for the package.
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)
Specifies which built files (libraries) go into the runtime binary package (libks2).
cat <<'EOF' > debian/libks2.install
usr/lib/libks2.so*
EOF
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.
cat <<'EOF' > debian/libks2-dev.install
usr/include/libks2/*
usr/lib/pkgconfig/libks2.pc
EOF
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).
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:
# 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
2.3 sofia-sip
Sofia-SIP is the underlying SIP user-agent library used by FreeSWITCH's endpoint module mod_sofia.
IMPORTANT
Preventing Collisions with Official Debian Repository Packages:
The official Debian 13 (Trixie) repositories distribute their own standard (unpatched) versions of Sofia-SIP (libsofia-sip-ua0 and libsofia-sip-ua-dev). To prevent a routine system update (apt upgrade) from overwriting our custom patched Sofia-SIP packages with the official Debian ones, we rename all Sofia-SIP binary packages to use the prefix freeswitch-sofia-sip instead of libsofia-sip. We also declare Provides, Conflicts, and Replaces directives pointing to the official Debian package names in debian/control so that FreeSWITCH's compilation and runtime dependencies are fully satisfied without conflicts.
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 Provides/Conflicts/Replaces
python3 -c "
import re
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}\nConflicts: {orig}\nReplaces: {orig}\n'
content = re.sub(pattern, replacement, content)
open('debian/control', 'w').write(content)
"
# Rename installation files in debian/ to match the new package names
python3 -c "
import os
for f in os.listdir('debian'):
if 'sofia-sip' in f:
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
# Add a custom changelog entry with the +softswitch version suffix
dch -v "1.13.17-0+softswitch" "Custom compile with nua_reload_tls patch and freeswitch-sofia package rename"
fakeroot debian/rules clean
dpkg-buildpackage -us -uc -b
# Move packages to /usr/src/freeswitch/deb
mv /usr/src/freeswitch-sofia-sip*.deb /usr/src/freeswitch/deb/
cd /usr/src/freeswitch/deb
dpkg -i freeswitch-sofia-sip-ua0_*.deb freeswitch-sofia-sip-ua-dev_*.deb freeswitch-sofia-sip-bin_*.deb
apt-get install -f -y
IMPORTANT
Package Renaming, Version Suffixing & Multi-Architecture Pitfalls
- Package Renaming (
freeswitch-sofia-sip): Since the official Debian repositories contain standard unpatched versions of libsofia-sip-ua0, we prefix our packages with freeswitch-sofia and build with version suffixing (+softswitch). This prevents apt from ever overwriting our library with official Debian repository updates, while our Provides, Conflicts, and Replaces directives ensure seamless dependency compatibility for FreeSWITCH's compilation and runtime requirements.
* Arch-Specific Repository Syncing: When deploying to production servers running different CPU architectures (e.g. some running arm64 and others running amd64), make sure you compile Sofia-SIP and other custom dependencies on both CPU architectures and publish them to your APT repository. If an architecture is missing from the repository, target servers of that architecture will fall back to the unpatched upstream Debian libraries, breaking SIP signaling.
2.4 libbroadvoice
This codec library handles BroadVoice 16/32-bit audio profiles.
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
2.5 signalwire-c
Create the SignalWire C API library.
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:
2.5.1 Control File (debian/control)
Defines the source and binary packages, their metadata, build-time dependencies, and runtime dependencies.
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
2.5.2 Rules File (debian/rules)
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:
2.5.3 Changelog File (debian/changelog)
Maintains the release history, package versioning, and change list.
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)
Specifies which built files (libraries) go into the runtime binary package (signalwire-client-c2).
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)
Specifies development assets (header files and pkg-config manifests) that go into the development package.
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)
Tells the build system to ignore generated files that are intentionally not packaged (such as the default changelog and copyright files).
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:
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 FreeSWITCH
Now that our compilation node is loaded with all custom dependencies, we clone FreeSWITCH and structure our Debian builds.
We will target the stable release branch v1.11.1:
cd /usr/src
git clone -b v1.11.1 --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
3.2 Add Custom Workarounds for Debian 13 Packaging
Before launching dpkg-buildpackage, we must bypass several known packaging issues:
- Incompatible Modules: Exclude legacy features like V8/Javascript and obsolete audio codecs (silk, ilbc, flite) that are not compatible with Debian 13 build environments.
dh_auto_clean Recursion Loop: Autotools comparisons can trigger an infinite build cleaner recursion loop. We override this loop as a no-op.
- 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:
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 with the new version metadata:
cat > changelog <<'EOF'
freeswitch (1.11.1-1) unstable; urgency=medium
* Repackage FreeSWITCH 1.11.1 for Debian 13.
* Disable incompatible audio modules and configure make workarounds.
-- [YOUR_FULL_NAME] <[EMAIL_ADDRESS]> Tue, 10 Sep 2025 20:30:00 +0000
EOF
3.3 Compile and Isolate
Synchronize all file timestamps to prevent GNU Make from triggering file skew regenerations, then run the sequential build command:
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/:
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
Now that our packages are compiled and isolated locally in /usr/src/freeswitch/deb/, we upload them to our repository server (IP: , configured in Part 1).
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:
- Generate SSH Key on your build node (if you do not have one):
ssh-keygen -t rsa -b 4096 -C "build-node"
# Press Enter to accept defaults (do not set a passphrase for automation)
- Copy the public key to the repository server:
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"
- Verify passwordless access:
ssh root@<YOUR_REPO_IP> "echo 'SSH Connection Successful!'"
4.2 Upload Packages
From your build node, secure copy the packages directly to the repository upload directory:
scp /usr/src/freeswitch/deb/*.deb root@76.13.102.153:/var/www/pbx-repo/ring2all/trixie/apt/pool/b/base/
scp /usr/src/freeswitch/deb/*.deb root@<YOUR_REPO_IP>:/var/www/pbx-repo/ring2all/trixie/apt/pool/b/base/
4.3 Sort and Sign on the Repo Server
Log into your repository server over SSH, organize the files into their target component directories, and rebuild the repository signatures:
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.
⏭️ What's Next?
Our repository server now serves FreeSWITCH 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.