Building Your Own VoIP PBX: A Playground for IVR and Voice AI Experiments

Building Your Own VoIP PBX: A Playground for IVR and Voice AI Experiments

Why Build a VoIP Lab in 2025?

The goal isn’t to replace my mobile phone. It’s to have a playground for voice technologies that are increasingly relevant in modern applications: IVR systems, conversational AI, voice assistants, and telephony integrations.

I wanted to experiment with:

  • IVR systems (Interactive Voice Response) - those “press 1 for sales” menus
  • SIP protocol internals - understanding modern telephony at a deeper level
  • Conversational interfaces - prototyping voice-driven applications

Setting up a proper PBX gives you a real telephony environment to test these technologies. And with Docker, I can iterate quickly without worrying about breaking a production system (because this is the disposable test environment).

The Setup: Small VPS, Big Possibilities

My testing ground:

  • Small VPS: 4 vCores, 8GB RAM, 75GB storage
  • OS: Ubuntu 24.04 LTS
  • Stack: Docker Compose + FreePBX + MariaDB
  • OVH SIP Trunk: Unlimited calls to 40+ countries (fixed lines)
  • Total Cost: ~€10/month (€5 VPS + €5 OVH trunk)

The beauty of this setup? It’s completely portable. Once tested on the VPS, I can migrate the exact same Docker configuration to my home lab. Infrastructure as code isn’t just for Kubernetes clusters.

More importantly, this gives me a real SIP/RTP environment to experiment with voice technologies before integrating them into larger projects.

Docker: The Right Tool for VoIP Experimentation

I could have gone the traditional route - bare metal Asterisk installation with manual dependency management. But here’s why Docker made sense for a lab environment:

  1. Rapid iteration: Broke something? docker compose down -v and rebuild
  2. Isolation: Test different configurations without system contamination
  3. Reproducibility: Share exact setup via docker-compose.yml
  4. Portability: Same config works on VPS, home lab, or even a laptop
  5. Version control: Entire infrastructure in git

The only consideration? VoIP is latency-sensitive. Docker adds minimal overhead, but you need proper kernel parameters for RTP (Real-time Transport Protocol) traffic.

The Docker Compose Setup

Here’s the core - surprisingly simple for a full-featured PBX:

version: '3.8'

services:
  freepbx:
    image: tiredofit/freepbx:latest
    container_name: freepbx
    restart: unless-stopped
    network_mode: host
    
    environment:
      - DB_HOST=127.0.0.1
      - DB_USER=asterisk
      - DB_PASS=${DB_PASSWORD}
      - ADMIN_PASSWORD=${ADMIN_PASSWORD}
      - TZ=Europe/Brussels
      - RTP_START=10000
      - RTP_FINISH=20000
      - ENABLE_FAIL2BAN=TRUE
      
    volumes:
      - ./data/recordings:/var/spool/asterisk/monitor
      - ./data/backup:/data/backup
      - freepbx-data:/data
      
    cap_add:
      - NET_ADMIN
      - NET_RAW

  mariadb:
    image: mariadb:10.11
    container_name: freepbx-db
    restart: unless-stopped
    network_mode: host
    
    environment:
      - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
      - MYSQL_DATABASE=asterisk
      - MYSQL_USER=asterisk
      - MYSQL_PASSWORD=${DB_PASSWORD}

The .env file holds all passwords (single quotes handle special characters):

DB_ROOT_PASSWORD='YourSecurePassword123!'
DB_PASSWORD='AnotherSecurePassword456!'
ADMIN_PASSWORD='AdminPassword789!'
PUBLIC_IP='your.vps.ip.here'
HOSTNAME='your.domain.here'

The Devil in the Details: VoIP-Specific Tweaks

Kernel Parameters for RTP

VoIP audio uses RTP over UDP, which needs proper buffer sizing:

sudo tee -a /etc/sysctl.conf << EOF
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.udp_mem = 65536 131072 262144
EOF

sudo sysctl -p

Firewall Configuration

sudo ufw allow 5060/udp
sudo ufw allow 5061/tcp
sudo ufw allow 10000:20000/udp

Network Mode: Host vs Bridge

I’m using network_mode: host because SIP is notoriously NAT-unfriendly. The protocol embeds IP addresses in the payload, not just headers.

Initial Testing: Making It Ring

After docker compose up -d and a 10-minute initialization:

External IP Settings (Settings → Asterisk SIP Settings):

  • External Address: [Your public IP]
  • Local Networks: [Your home network range]
  • Rewrite Contact: Yes

Test Extensions:

  • Extension 1001: Cisco SPA504G desk phone
  • Extension 1002: iPhone via Zoiper softphone

First test call worked perfectly - clear audio, minimal latency.

Connecting to the Outside World

I added a SIP trunk for external connectivity:

Trunk Name: Provider
Username: [provider username]
Secret: [provider password]
SIP Server: [provider SIP server]
Registration: Send

Now the PBX can make and receive external calls, essential for testing real-world IVR scenarios.

What I Learned (The Hard Way)

1. Password Quoting in .env Files

# Breaks
DB_PASSWORD=My$ecure!Pass

# Works
DB_PASSWORD='My$ecure!Pass'

2. “Unauthorized” = Wrong Password Field

FreePBX has multiple password fields. For SIP clients, you need the “Secret” field, not “User Password.”

3. Patience During Initialization

FreePBX takes 10-15 minutes on first start. Watch docker compose logs -f and wait for “FreePBX is ready for connections.”

The Real Goal: A Voice Technology Playground

With the basic PBX working, I now have a platform to experiment with:

IVR Systems:

  • Build custom voice menus
  • Test different prompt strategies
  • Measure completion rates

Telephony APIs:

  • Experiment with Voice API
  • Test integration patterns
  • Build custom AGI scripts

Security Basics

  • Enable SIP over TLS
  • Use strong passwords (20+ characters)
  • Enable Fail2Ban
  • Restrict access by IP
  • Regular updates

Why This Matters

Voice interfaces are increasingly important:

  • Customer service automation
  • Accessibility features
  • IoT voice control

Having a lab for experimentation - without per-minute API costs - is invaluable.

The Unexpected Benefit

I started this to test voice technologies. I ended up learning:

  • Modern SIP/RTP protocols
  • NAT traversal techniques
  • VoIP codecs
  • Docker networking
  • Asterisk dialplan

For experimentation and learning? A FreePBX lab is incredibly valuable.

Resources

  • FreePBX Docker Image: tiredofit/freepbx
  • FreePBX Documentation: wiki.freepbx.org
  • Asterisk Documentation: docs.asterisk.org

Total setup time? About 3 hours. For a fully functional PBX ready for voice experiments? Not bad for an afternoon project.

Now, if you’ll excuse me, I have an IVR system to design.

About the Author
totophe's avatar

totophe

Creative Mind, Digital Development Strategist, and Web & Marketing Technologies Consultant in Brussels, Belgium