📦 Part 1: Setting up a Custom APT Repository Server on Debian 13 (Trixie)
Welcome to the first installment of our “Debian 13 Packaging & Distribution” series. In this post, we will walk through the process of building your own secure, public-facing Debian APT repository server from scratch. You will learn how to configure Nginx to serve package indices, generate and use GPG keys to sign your metadata, write utility scripts to manage package sorting and deduplication, and distribute a bootstrap script to make client installation as simple as a single command.
🏗️ Why Build a Custom APT Repository?
Section titled “🏗️ Why Build a Custom APT Repository?”When distributing complex software like Telephony Server or Kamailio across multiple production servers, relying on manual file transfers or local compilation on every machine is error-prone and inefficient.
A custom APT repository provides:
- Dependency Management: APT automatically resolves and installs system prerequisites.
- Security: Cryptographically signed packages ensure that clients only install untampered code.
- Consistency: Ensure all production, staging, and development servers run the exact same versions.
- Convenience: Updates are as simple as running
apt-get update && apt-get upgrade.
🛠️ Step 1: Server Preparation & Web Server Installation
Section titled “🛠️ Step 1: Server Preparation & Web Server Installation”For this setup, we will use a server running Debian 13 (Trixie). Our repository will be hosted at repo.softswitchone.com.
1.1 Install System Utilities
Section titled “1.1 Install System Utilities”First, update the package list and install Nginx alongside the tools required to generate repository metadata and manage cryptographic keys:
apt-get updateapt-get install -y nginx apt-utils devscripts gnupg2 dpkg-dev gzip python3 certbot python3-certbot-nginxnginx: Serves the repository files over HTTP/HTTPS.apt-utils&dpkg-dev: Containsdpkg-scanpackagesto index package directories.gnupg2: Cryptographically signs repository indexes.
🌐 Step 2: Web Server Configuration (Nginx & HTTPS)
Section titled “🌐 Step 2: Web Server Configuration (Nginx & HTTPS)”APT repositories are served over simple HTTP/HTTPS directory structures. We will configure Nginx to serve our files and enable directory listing so APT can crawl the pool.
2.1 Create the Nginx Virtual Host
Section titled “2.1 Create the Nginx Virtual Host”Create a configuration file at /etc/nginx/sites-available/repo.softswitchone.com:
server { listen 80; server_name repo.softswitchone.com;
root /var/www/pbx-repo/ring2all/trixie;
access_log /var/log/nginx/repo_access.log; error_log /var/log/nginx/repo_error.log;
# Allow directory listing so clients can inspect package folders autoindex on;
# Serve the main repository files location /apt/ { alias /var/www/pbx-repo/ring2all/trixie/apt/; autoindex on; }
# Public location for client GPG keys location /apt/gpgkey/ { alias /var/www/pbx-repo/ring2all/trixie/apt/gpgkey/; }
# Deny access to hidden system files (.git, .htaccess, etc.) location ~ /\. { deny all; }}Enable the configuration and restart Nginx:
ln -sf /etc/nginx/sites-available/repo.softswitchone.com /etc/nginx/sites-enabled/nginx -tsystemctl restart nginx2.2 Secure the Server with Let’s Encrypt SSL
Section titled “2.2 Secure the Server with Let’s Encrypt SSL”Run Certbot to acquire and install an SSL certificate, automatically redirecting all HTTP traffic to HTTPS:
certbot --nginx -d repo.softswitchone.comConfiguring SSL Auto-Renewal
Section titled “Configuring SSL Auto-Renewal”Let’s Encrypt certificates are valid for 90 days. Set up a daily cron job to run the certbot renewal checks automatically:
echo "0 3 * * * root certbot renew --quiet --post-hook 'systemctl reload nginx'" > /etc/cron.d/certbot-renewchmod 644 /etc/cron.d/certbot-renew🔑 Step 3: Cryptographic Signing (GPG Key Setup)
Section titled “🔑 Step 3: Cryptographic Signing (GPG Key Setup)”Modern APT clients refuse to install packages from repositories that do not sign their index metadata with a trusted GPG key.
3.1 Generate the RSA Signing Key
Section titled “3.1 Generate the RSA Signing Key”Run the key generator on your repository server:
gpg --full-generate-keySelect the following configuration options when prompted:
- Key type: Select
1(RSA and RSA). - Keysize: Enter
4096bits. - Validity: Enter
0(key does not expire) and confirm withy. - Real name: Enter
Ring2All Repo. - Email address: Enter
[EMAIL_ADDRESS]. - Passphrase: Leave empty (press Enter twice) for automated, non-interactive index signing.
3.2 Find and Copy the Key ID
Section titled “3.2 Find and Copy the Key ID”List the keys in your keyring to retrieve the long key fingerprint:
gpg --list-keys --keyid-format longExample Output:
pub rsa4096/D899B67676A5D2D408C5E30EA4B1437798E981B7 2026-01-26 [SC] D899B67676A5D2D408C5E30EA4B1437798E981B7uid [ultimate] Ring2All Repo <[EMAIL_ADDRESS]>Identify the long key ID: D899B67676A5D2D408C5E30EA4B1437798E981B7.
3.3 Export the Public Key for Clients
Section titled “3.3 Export the Public Key for Clients”Clients will need your public GPG key to verify the repository signatures. Export it in ASCII-armored format and save it inside your web server root:
mkdir -p /var/www/pbx-repo/ring2all/trixie/apt/gpgkeygpg --armor --export D899B67676A5D2D408C5E30EA4B1437798E981B7 > /var/www/pbx-repo/ring2all/trixie/apt/gpgkey/ring2all.gpg📁 Step 4: Repository Structure & Automation Scripts
Section titled “📁 Step 4: Repository Structure & Automation Scripts”To keep the repository clean and maintainable, we partition packages into five functional Components:
| Component | Pool Path | Content Description |
|---|---|---|
| base | pool/b/base/ |
Telephony core, dependencies, and essential modules |
| core | pool/c/core/ |
Ring2All Softswitch packages (admin panel, APIs, etc.) |
| extras | pool/e/extras/ |
Auxiliary modules (Perl, Python, MariaDB backends, VLC) |
| devel | pool/d/devel/ |
Development headers (-dev) and debug symbols (-dbg) |
| audios | pool/a/audios/ |
Voice guides (Emma, Paloma) and music files |
Let’s configure the scripts that automate package sorting, deduplication, metadata indexing, and signing.
4.1 Script 1: /usr/sbin/ReleaseBuilderRing2All
Section titled “4.1 Script 1: /usr/sbin/ReleaseBuilderRing2All”This script parses the index metadata directories and outputs standard Debian release header hashes (MD5, SHA1, SHA256) of all underlying files.
Create /usr/sbin/ReleaseBuilderRing2All:
cat > /usr/sbin/ReleaseBuilderRing2All <<'EOF'#!/bin/bashset -e
while getopts o:l:s:d:c:a: flag; do case "${flag}" in o) ORIGIN=${OPTARG};; l) LABEL=${OPTARG};; s) SUITE=${OPTARG};; d) DESC=${OPTARG};; c) COMP=${OPTARG};; a) ARCH=${OPTARG};; esacdone
ORIGIN=${ORIGIN:-"Ring2All Repo"}LABEL=${LABEL:-Base}SUITE=${SUITE:-stable}DESC=${DESC:-"Ring2All packages"}COMP=${COMP:-main}ARCH=${ARCH:-"amd64 arm64 armhf all"}
do_hash() { HASH_NAME=$1 HASH_CMD=$2 echo "${HASH_NAME}:" for f in $(find -type f); do f=$(echo $f | cut -c3-) [ "$f" = "Release" ] && continue echo " $(${HASH_CMD} ${f} | cut -d' ' -f1) $(wc -c < $f) $f" done}
cat <<EOTOrigin: ${ORIGIN}Label: ${LABEL}Suite: ${SUITE}Codename: ${SUITE}Version: 1.0Architectures: ${ARCH}Components: ${COMP}Description: ${DESC}Date: $(date -Ru)EOTdo_hash "MD5Sum" "md5sum"do_hash "SHA1" "sha1sum"do_hash "SHA256" "sha256sum"EOF
chmod +x /usr/sbin/ReleaseBuilderRing2All4.2 Script 2: /usr/sbin/CleanPoolRepo
Section titled “4.2 Script 2: /usr/sbin/CleanPoolRepo”If we upload packages repeatedly (e.g., during active CI/CD iterations), older versions will accumulate and consume disk space. This Python script compares package version numbers using Debian’s native dpkg --compare-versions and safely purges old duplicates while keeping only the latest version.
Create /usr/sbin/CleanPoolRepo:
cat > /usr/sbin/CleanPoolRepo <<'EOF'#!/usr/bin/env python3import osimport subprocessimport sys
def get_pkg_info(deb_path): try: res = subprocess.run( ["dpkg-deb", "-f", deb_path, "Package", "Version", "Architecture"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True ) info = {} for line in res.stdout.strip().split('\n'): if ':' in line: k, v = line.split(':', 1) info[k.strip().lower()] = v.strip() return info.get("package"), info.get("version"), info.get("architecture") except Exception as e: print(f"Error reading {deb_path}: {e}", file=sys.stderr) return None, None, None
def compare_versions(v1, v2): res = subprocess.run(["dpkg", "--compare-versions", v1, "lt", v2]) return res.returncode == 0
def clean_pool(pool_dir): if not os.path.isdir(pool_dir): print(f"Directory {pool_dir} does not exist.") return
deb_files = [] for root, _, files in os.walk(pool_dir): for f in files: if f.endswith(".deb"): deb_files.append(os.path.join(root, f))
groups = {} for filepath in deb_files: pkg, ver, arch = get_pkg_info(filepath) if not pkg or not ver or not arch: continue key = (pkg, arch) if key not in groups: groups[key] = [] groups[key].append({"path": filepath, "version": ver})
for key, items in groups.items(): if len(items) <= 1: continue for i in range(len(items)): max_idx = i for j in range(i + 1, len(items)): if compare_versions(items[max_idx]["version"], items[j]["version"]): max_idx = j items[i], items[max_idx] = items[max_idx], items[i]
latest = items[0] for item in items[1:]: print(f"Removing older version: {item['path']} ({item['version']}) in favor of {latest['version']}") try: os.remove(item["path"]) except Exception as e: print(f"Error removing {item['path']}: {e}", file=sys.stderr)
if __name__ == "__main__": if len(sys.argv) < 2: print("Usage: CleanPoolRepo <pool_dir>") sys.exit(1) clean_pool(sys.argv[1])EOF
chmod +x /usr/sbin/CleanPoolRepo4.3 Script 3: /usr/sbin/BuildRepoRing2All
Section titled “4.3 Script 3: /usr/sbin/BuildRepoRing2All”This script links all pools, triggers the cleanup process, scans packages using dpkg-scanpackages, generates compressed metadata indexes (Packages.gz), builds the global Release files, and signs them cryptographically with GPG.
Create /usr/sbin/BuildRepoRing2All:
cat > /usr/sbin/BuildRepoRing2All <<'EOF'#!/bin/bashset -e
PROJECT_DIR=/var/www/pbx-repo/ring2all/trixie
# Detect GPG key matching the administrator's emailGPG_KEY=$(gpg --list-secret-keys --keyid-format long "[EMAIL_ADDRESS]" 2>/dev/null | grep -A 1 "^sec" | tail -n 1 | awk '{print $1}')if [ -z "$GPG_KEY" ]; then GPG_KEY=$(gpg --list-secret-keys --keyid-format long 2>/dev/null | grep -A 1 "^sec" | tail -n 1 | awk '{print $1}')fiGPG_KEY=${GPG_KEY:-"D899B67676A5D2D408C5E30EA4B1437798E981B7"}
echo "Creating directory structures..."mkdir -p ${PROJECT_DIR}/apt/{gpgkey,base,core,extras,devel,audios}mkdir -p ${PROJECT_DIR}/apt/pool/{a/audios,b/base,c/core,e/extras,d/devel}
for section in audios base core extras devel; do mkdir -p ${PROJECT_DIR}/apt/${section}/dists/stable/main/binary-{amd64,all,arm64,armhf} mkdir -p ${PROJECT_DIR}/apt/${section}/pooldone
# Map virtual symbolic links to resolve the centralized poolln -sf ${PROJECT_DIR}/apt/pool ${PROJECT_DIR}/apt/audios/pool 2>/dev/null || trueln -sf ${PROJECT_DIR}/apt/pool ${PROJECT_DIR}/apt/base/pool 2>/dev/null || trueln -sf ${PROJECT_DIR}/apt/pool ${PROJECT_DIR}/apt/core/pool 2>/dev/null || trueln -sf ${PROJECT_DIR}/apt/pool ${PROJECT_DIR}/apt/extras/pool 2>/dev/null || trueln -sf ${PROJECT_DIR}/apt/pool ${PROJECT_DIR}/apt/devel/pool 2>/dev/null || true
# Copy signing key and client bootstrap script to public web paths[ -f ~/ring2all.gpg ] && cp ~/ring2all.gpg ${PROJECT_DIR}/apt/gpgkey/ring2all.gpg[ -f ~/ring2all_setup_repo ] && cp ~/ring2all_setup_repo ${PROJECT_DIR}/apt/setup_repo
# Purge obsolete versionsif [ -x /usr/sbin/CleanPoolRepo ]; then echo "Purging old duplicate packages from pool..." /usr/sbin/CleanPoolRepo ${PROJECT_DIR}/apt/poolfi
# Rebuild package indexesecho "Generating Packages files..."cd ${PROJECT_DIR}/apt
for section in audios base core extras devel; do pool_letter="${section:0:1}" [ "$section" = "audios" ] && pool_letter="a" [ "$section" = "extras" ] && pool_letter="e"
for arch in amd64 all arm64 armhf; do dpkg-scanpackages --arch $arch pool/${pool_letter}/${section}/ /dev/null > ${section}/dists/stable/main/binary-${arch}/Packages 2>/dev/null || true gzip -9c ${section}/dists/stable/main/binary-${arch}/Packages > ${section}/dists/stable/main/binary-${arch}/Packages.gz 2>/dev/null || true donedone
# Create and cryptographically sign release metadataecho "Signing release index..."for section in audios base core extras devel; do cd ${PROJECT_DIR}/apt/${section}/dists/stable/ /usr/sbin/ReleaseBuilderRing2All -l ${section^} -d "Ring2All ${section^} packages" > Release rm -f Release.gpg InRelease
if gpg --list-keys "$GPG_KEY" >/dev/null 2>&1; then gpg -u "$GPG_KEY" -abs -o Release.gpg Release cat Release | gpg -u "$GPG_KEY" -abs --clearsign > InRelease else echo "⚠️ WARNING: GPG key $GPG_KEY not found. Skipping metadata signing." fidone
echo "✅ Repository rebuild complete!"EOF
chmod +x /usr/sbin/BuildRepoRing2All4.4 Script 4: /usr/sbin/CopyPackagesToRepo
Section titled “4.4 Script 4: /usr/sbin/CopyPackagesToRepo”This script acts as the entry-point gatekeeper, sorting incoming compiled Telephony Server .deb packages (e.g. core binaries, configuration packs, dynamic modules, and custom telephony dependencies) into their respective repository component directories.
Create /usr/sbin/CopyPackagesToRepo:
cat > /usr/sbin/CopyPackagesToRepo << 'EOF'#!/bin/bash# CopyPackagesToRepo - Sort uploaded packages into repository categories
POOL_DIR="/var/www/pbx-repo/ring2all/trixie/apt/pool"
# Detect source directory dynamicallySRC_DIR="/usr/src"if [ -d "/usr/src/freeswitch/deb" ] && ls /usr/src/freeswitch/deb/*.deb &>/dev/null; then SRC_DIR="/usr/src/freeswitch/deb"fi
echo "=============================================="echo " Moving packages to Ring2All Repository "echo "=============================================="echo "Source directory: $SRC_DIR"echo "Target pool directory: $POOL_DIR"
# Create directories if neededmkdir -p $POOL_DIR/{a/audios,b/base,c/core,d/devel,e/extras}
# ============================================================# BASE: Telephony Core + Dependencies + Essential Modules# ============================================================echo ""echo "=== BASE: Telephony Core ==="
# Core Telephony Servermv -v $SRC_DIR/freeswitch_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-all_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-systemd*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-timezones*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/libfreeswitch1_*.deb $POOL_DIR/b/base/ 2>/dev/null
# Meta packagesmv -v $SRC_DIR/freeswitch-meta-*.deb $POOL_DIR/b/base/ 2>/dev/null
# Configuration packagesmv -v $SRC_DIR/freeswitch-conf-*.deb $POOL_DIR/b/base/ 2>/dev/null
# Language packsmv -v $SRC_DIR/freeswitch-lang*.deb $POOL_DIR/b/base/ 2>/dev/null
# Dependencies (spandsp, libks2, sofia-sip, signalwire-c, broadvoice)mv -v $SRC_DIR/libspandsp*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/libks2_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/libbroadvoice1_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/signalwire-client-c2_*.deb $POOL_DIR/b/base/ 2>/dev/null
# Legacy Sofia-SIP packagesmv -v $SRC_DIR/libsofia-sip-ua0_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/libsofia-sip-ua-glib3_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/sofia-sip-bin_*.deb $POOL_DIR/b/base/ 2>/dev/null
# New renamed Sofia-SIP packagesmv -v $SRC_DIR/freeswitch-sofia-sip-ua0_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-sofia-sip-ua-glib3_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-sofia-sip-bin_*.deb $POOL_DIR/b/base/ 2>/dev/null
# Kamailio SBC packagesmv -v $SRC_DIR/sbc-kamailio_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/sbc-kamailio-*-modules_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/sbc-kamailio-nth_*.deb $POOL_DIR/b/base/ 2>/dev/null
# Essential endpoint modulesmv -v $SRC_DIR/freeswitch-mod-sofia_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-verto_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-rtc_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-loopback_*.deb $POOL_DIR/b/base/ 2>/dev/null
# Essential application modulesmv -v $SRC_DIR/freeswitch-mod-lua_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-commands_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-dptools_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-dialplan-xml_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-event-socket_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-console_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-logfile_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-syslog_*.deb $POOL_DIR/b/base/ 2>/dev/null
# Database modulesmv -v $SRC_DIR/freeswitch-mod-pgsql_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-cdr-pg-csv_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-odbc-cdr_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-db_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-hash_*.deb $POOL_DIR/b/base/ 2>/dev/null
# Essential codecsmv -v $SRC_DIR/freeswitch-mod-opus_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-spandsp_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-g729_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-codec2_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-amr_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-amrwb_*.deb $POOL_DIR/b/base/ 2>/dev/null
# Essential applicationsmv -v $SRC_DIR/freeswitch-mod-voicemail_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-voicemail-ivr_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-conference_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-fifo_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-callcenter_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-httapi_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-sndfile_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-tone-stream_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-local-stream_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-native-file_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-shout_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-sms_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-valet-parking_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-spy_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-directory_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-lcr_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-nibblebill_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-blacklist_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-cidlookup_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-curl_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-xml-curl_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-http-cache_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-fail2ban_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-expr_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-translate_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-distributor_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-easyroute_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-avmd_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-vmd_*.deb $POOL_DIR/b/base/ 2>/dev/null
# Say modules (essential for IVR)mv -v $SRC_DIR/freeswitch-mod-say-en_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-say-es_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-say-es-ar_*.deb $POOL_DIR/b/base/ 2>/dev/null
# CDR modulesmv -v $SRC_DIR/freeswitch-mod-cdr-csv_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-json-cdr_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-xml-cdr_*.deb $POOL_DIR/b/base/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-format-cdr_*.deb $POOL_DIR/b/base/ 2>/dev/null
# ============================================================# EXTRAS: Optional modules# ============================================================echo ""echo "=== EXTRAS: Optional Modules ==="
# Alternative language bindingsmv -v $SRC_DIR/freeswitch-mod-perl_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-python3_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-java_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-erlang-event_*.deb $POOL_DIR/e/extras/ 2>/dev/null
# Alternative dialplansmv -v $SRC_DIR/freeswitch-mod-dialplan-asterisk_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-dialplan-directory_*.deb $POOL_DIR/e/extras/ 2>/dev/null
# Alternative databasesmv -v $SRC_DIR/freeswitch-mod-mariadb_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-cdr-sqlite_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-cdr-mongodb_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-hiredis_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-memcache_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-redis_*.deb $POOL_DIR/e/extras/ 2>/dev/null
# Media modulesmv -v $SRC_DIR/freeswitch-mod-vlc_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-av_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-cv_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-imagick_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-png_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-video-filter_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-yuv_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-fsv_*.deb $POOL_DIR/e/extras/ 2>/dev/null
# Alternative endpointsmv -v $SRC_DIR/freeswitch-mod-rtmp_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-skinny_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-alsa_*.deb $POOL_DIR/e/extras/ 2>/dev/null
# Additional say modulesmv -v $SRC_DIR/freeswitch-mod-say-de_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-say-fr_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-say-pt_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-say-ru_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-say-it_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-say-nl_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-say-he_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-say-hr_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-say-hu_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-say-ja_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-say-pl_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-say-sv_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-say-th_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-say-zh_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-say-fa_*.deb $POOL_DIR/e/extras/ 2>/dev/null
# Additional codecsmv -v $SRC_DIR/freeswitch-mod-bv_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-g723-1_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-opusfile_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-b64_*.deb $POOL_DIR/e/extras/ 2>/dev/null
# Miscellaneousmv -v $SRC_DIR/freeswitch-mod-amqp_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-bert_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-enum_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-esf_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-esl_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-event-multicast_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-event-test_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-fsk_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-graylog2_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-ldap_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-pocketsphinx_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-posix-timer_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-prefix_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-random_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-shell-stream_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-signalwire_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-snapshot_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-snmp_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-test_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-timerfd_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-tts-commandline_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-xml-rpc_*.deb $POOL_DIR/e/extras/ 2>/dev/nullmv -v $SRC_DIR/freeswitch-mod-xml-scgi_*.deb $POOL_DIR/e/extras/ 2>/dev/null
# ============================================================# DEVEL: Development packages and debug symbols# ============================================================echo ""echo "=== DEVEL: Development Packages ==="
mv -v $SRC_DIR/*-dev_*.deb $POOL_DIR/d/devel/ 2>/dev/nullmv -v $SRC_DIR/*-dbg_*.deb $POOL_DIR/d/devel/ 2>/dev/nullmv -v $SRC_DIR/*-dbgsym_*.deb $POOL_DIR/d/devel/ 2>/dev/nullmv -v $SRC_DIR/*-doc_*.deb $POOL_DIR/d/devel/ 2>/dev/nullmv -v $SRC_DIR/python-esl*.deb $POOL_DIR/d/devel/ 2>/dev/nullmv -v $SRC_DIR/libesl-perl*.deb $POOL_DIR/d/devel/ 2>/dev/null
# ============================================================# CORE: Ring2All PBX, Ring2All SBC & Ring2All BSS Packages# ============================================================echo ""echo "=== CORE: Ring2All PBX, Ring2All SBC & Ring2All BSS Packages ==="
# Ring2All PBX Packagesmv -v $SRC_DIR/softswitch-admin_*.deb $POOL_DIR/c/core/ 2>/dev/nullmv -v $SRC_DIR/softswitch-db_*.deb $POOL_DIR/c/core/ 2>/dev/nullmv -v $SRC_DIR/softswitch-api_*.deb $POOL_DIR/c/core/ 2>/dev/nullmv -v $SRC_DIR/softswitch-monitoring-api_*.deb $POOL_DIR/c/core/ 2>/dev/nullmv -v $SRC_DIR/softswitch-billing-api_*.deb $POOL_DIR/c/core/ 2>/dev/nullmv -v $SRC_DIR/softswitch-portal_*.deb $POOL_DIR/c/core/ 2>/dev/nullmv -v $SRC_DIR/softswitch-switchboard_*.deb $POOL_DIR/c/core/ 2>/dev/nullmv -v $SRC_DIR/softswitch-telephony_*.deb $POOL_DIR/c/core/ 2>/dev/nullmv -v $SRC_DIR/softswitch-all_*.deb $POOL_DIR/c/core/ 2>/dev/null
# Ring2All SBC Packages (Modular Suite & Monolithic)mv -v $SRC_DIR/softswitch-sbc_*.deb $POOL_DIR/c/core/ 2>/dev/nullmv -v $SRC_DIR/softswitch-sbc-db_*.deb $POOL_DIR/c/core/ 2>/dev/nullmv -v $SRC_DIR/softswitch-sbc-api_*.deb $POOL_DIR/c/core/ 2>/dev/nullmv -v $SRC_DIR/softswitch-sbc-admin_*.deb $POOL_DIR/c/core/ 2>/dev/nullmv -v $SRC_DIR/softswitch-sbc-telephony_*.deb $POOL_DIR/c/core/ 2>/dev/nullmv -v $SRC_DIR/softswitch-sbc-all_*.deb $POOL_DIR/c/core/ 2>/dev/null
# Ring2All BSS Packages (Billing, OCS & Customer Store)mv -v $SRC_DIR/softswitch-bss-api_*.deb $POOL_DIR/c/core/ 2>/dev/nullmv -v $SRC_DIR/softswitch-bss-web_*.deb $POOL_DIR/c/core/ 2>/dev/nullmv -v $SRC_DIR/softswitch-bss-client_*.deb $POOL_DIR/c/core/ 2>/dev/nullmv -v $SRC_DIR/softswitch-bss-all_*.deb $POOL_DIR/c/core/ 2>/dev/null
# Legacy or generic audios in core (music)mv -v $SRC_DIR/softswitch-music_*.deb $POOL_DIR/c/core/ 2>/dev/null
# ============================================================# AUDIOS: Voice guides (populated by voiceguide builds)# ============================================================echo ""echo "=== AUDIOS: Voice Guides ==="
mv -v $SRC_DIR/softswitch-voiceguide-emma_*.deb $POOL_DIR/a/audios/ 2>/dev/nullmv -v $SRC_DIR/softswitch-voiceguide-paloma_*.deb $POOL_DIR/a/audios/ 2>/dev/null
# ============================================================# Count packages per component# ============================================================echo ""echo "=============================================="echo " Summary "echo "=============================================="echo "BASE: $(ls -1 $POOL_DIR/b/base/*.deb 2>/dev/null | wc -l) packages"echo "CORE: $(ls -1 $POOL_DIR/c/core/*.deb 2>/dev/null | wc -l) packages"echo "EXTRAS: $(ls -1 $POOL_DIR/e/extras/*.deb 2>/dev/null | wc -l) packages"echo "DEVEL: $(ls -1 $POOL_DIR/d/devel/*.deb 2>/dev/null | wc -l) packages"echo "AUDIOS: $(ls -1 $POOL_DIR/a/audios/*.deb 2>/dev/null | wc -l) packages"echo ""echo "✅ Done! Now run: BuildRepoRing2All"EOF
chmod +x /usr/sbin/CopyPackagesToRepo🚀 Step 5: Client Installation & Bootstrap Configuration
Section titled “🚀 Step 5: Client Installation & Bootstrap Configuration”On the repository server, we create a script ring2all_setup_repo to automate client registration. This script will download the signing GPG key, save it securely under /etc/apt/keyrings, and configure the custom repository list.
Create ~/ring2all_setup_repo:
cat > ~/ring2all_setup_repo << 'EOF'#!/bin/bashset -e
echo "Installing Ring2All repository keyring and source list..."
# Install basic dependencies if missingapt-get update && apt-get install -y wget curl gpg
# Create keyrings directorymkdir -p /etc/apt/keyrings
# Securely download and import public signing key# Securely download and import public signing keycurl -fsSL https://repo.softswitchone.com/apt/gpgkey/ring2all.gpg | gpg --dearmor -o /etc/apt/keyrings/ring2all.gpgchmod 644 /etc/apt/keyrings/ring2all.gpg
# Register the components source filecat > /etc/apt/sources.list.d/ring2all.list << 'SOURCES'deb [signed-by=/etc/apt/keyrings/ring2all.gpg] https://repo.softswitchone.com/apt/base stable maindeb [signed-by=/etc/apt/keyrings/ring2all.gpg] https://repo.softswitchone.com/apt/devel stable maindeb [signed-by=/etc/apt/keyrings/ring2all.gpg] https://repo.softswitchone.com/apt/extras stable maindeb [signed-by=/etc/apt/keyrings/ring2all.gpg] https://repo.softswitchone.com/apt/audios stable maindeb [signed-by=/etc/apt/keyrings/ring2all.gpg] https://repo.softswitchone.com/apt/core stable mainSOURCES
echo "✅ Ring2All repository configured successfully!"echo "Run 'apt-get update' to refresh the package cache."EOF
chmod +x ~/ring2all_setup_repoWhenever /usr/sbin/BuildRepoRing2All is executed, it automatically publishes this setup script to the Nginx web root.
🔍 Step 6: Client Verification
Section titled “🔍 Step 6: Client Verification”To register a fresh Debian 13 target client server and install packages from our repository, run:
# Bootstrap the clientwget -qO- https://repo.softswitchone.com/apt/setup_repo | bash
# Refresh APT cacheapt-get update
# Install from the new repositoryapt-get install -y freeswitch freeswitch-meta-all⏭️ What’s Next?
Section titled “⏭️ What’s Next?”Now that the distribution infrastructure is fully operational, we need packages to publish. In Part 2: Compiling and Packaging Telephony Server Engine on Debian 13, we will compile the Telephony Server communication engine from source, package it as .deb binaries, and publish them to our new repository.

