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:
- Rapid iteration: Broke something?
docker compose down -v
and rebuild - Isolation: Test different configurations without system contamination
- Reproducibility: Share exact setup via
docker-compose.yml
- Portability: Same config works on VPS, home lab, or even a laptop
- 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.