Last updated: March 22, 2026

A proper VoIP setup replaces desk phones with software-based calling that works from any home office. This guide covers a self-hosted FreePBX deployment, softphone configuration, QoS tuning, and failover so remote workers maintain business call quality.

Architecture Overview

Internet
    
    
SIP Trunk Provider (Twilio/VoIP.ms/Bandwidth)
    
    
FreePBX Server (cloud VM or on-prem)
    
     Extension 101 → Linphone (desktop)
     Extension 102 → Zoiper (mobile)
     Extension 103 → Hardware IP phone

FreePBX Installation

Deploy on Ubuntu 22.04 (2 vCPU, 2GB RAM minimum):

Download FreePBX installer
wget https://github.com/FreePBX/sng_freepbx_debian_install/raw/master/sng_freepbx_debian_install.sh

Run installer (takes 20-30 minutes)
chmod +x sng_freepbx_debian_install.sh
sudo bash sng_freepbx_debian_install.sh

Verify Asterisk is running
sudo systemctl status asterisk
fwconsole sa

Firewall Rules

UFW rules for SIP and RTP
sudo ufw allow 5060/udp   # SIP signaling
sudo ufw allow 5061/tcp   # SIP TLS
sudo ufw allow 10000:20000/udp  # RTP audio ports
sudo ufw allow 80/tcp     # HTTP admin
sudo ufw allow 443/tcp    # HTTPS admin

Restrict admin access to your team's IPs
sudo ufw allow from 203.0.113.0/24 to any port 80
sudo ufw allow from 203.0.113.0/24 to any port 443
sudo ufw deny 80/tcp
sudo ufw deny 443/tcp

SIP Trunk Configuration

In FreePBX admin (Connectivity > Trunks):

Trunk settings for VoIP.ms (example)
[voipms-trunk]
type=friend
host=atlanta1.voip.ms
port=5060
username=your_account_number
secret=your_password
insecure=invite,port
qualify=yes
context=from-trunk
disallow=all
allow=ulaw,alaw,g722
dtmfmode=rfc2833
nat=force_rport,comedia

For Twilio SIP Trunking:

Configure via Twilio Console, then add trunk in FreePBX:
Trunk Type - SIP
Outbound CallerID - +15551234567
SIP Server - your-subdomain.pstn.twilio.com
Username - your_twilio_account_sid
Secret - your_twilio_auth_token

Extension Configuration

/etc/asterisk/sip_custom.conf
[101]
type=friend
host=dynamic
secret=str0ng-ext-password
username=101
callerid=Alice Smith <101>
context=from-internal
dtmfmode=rfc2833
nat=force_rport,comedia
qualify=yes
disallow=all
allow=ulaw,g722
transport=tls,udp
encryption=yes

[102]
type=friend
host=dynamic
secret=str0ng-ext-password-2
username=102
callerid=Bob Jones <102>
context=from-internal
dtmfmode=rfc2833
nat=force_rport,comedia
qualify=yes
disallow=all
allow=ulaw,g722

Linphone Softphone Setup

Install on Linux/Mac/Windows:

Ubuntu
sudo apt install linphone

macOS
brew install --cask linphone

Configure via CLI or settings file
cat ~/.linphonerc

Settings to configure in Linphone:

Preferences > SIP Accounts > Add Account

SIP Address - "sip:101@your-pbx.example.com"
SIP Password:      str0ng-ext-password
SIP Server - "your-pbx.example.com:5060"
Transport:         TLS (recommended)
STUN server - "stun.l.google.com:19302"
Enable ICE:        Yes
SRTP:              Mandatory

Zoiper Mobile Configuration

Account Type - SIP
Username - 102
Password - str0ng-ext-password-2
Domain - your-pbx.example.com
Port - 5061
Transport - TLS
SRTP - Required
STUN - stun.l.google.com

Router QoS Configuration

QoS prevents audio dropouts when bandwidth is shared. Access your router admin panel:

On pfSense/OPNsense - ALTQ/HFSC QoS
Traffic shaper > HFSC

Create a VoIP queue with:
- Priority: Highest
- Bandwidth guarantee: 128kbps per call (g.711)
- Match rule: UDP port 10000-20000 (RTP)
- Match rule: UDP port 5060 (SIP)

On Linux router/gateway using tc
Mark SIP/RTP packets
iptables -t mangle -A PREROUTING -p udp --dport 5060 -j DSCP --set-dscp-class EF
iptables -t mangle -A PREROUTING -p udp --dport 10000:20000 -j DSCP --set-dscp-class EF

Apply QoS with HTB
tc qdisc add dev eth0 root handle 1: htb default 30
tc class add dev eth0 parent 1: "classid 1:1 htb rate 100mbit"
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 5mbit ceil 10mbit prio 1  # VoIP
tc class add dev eth0 parent 1:1 classid 1:30 htb rate 90mbit ceil 100mbit prio 3 # Default
tc filter add dev eth0 parent 1: "protocol ip handle 0x2e fw classid 1:10"

Fail2ban for SIP Security

/etc/fail2ban/filter.d/asterisk.conf
[Definition]
failregex = NOTICE.* .*: Registration from '.*' failed for '<HOST>.*' - Wrong password
            NOTICE.* .*: Registration from '.*' failed for '<HOST>.*' - No matching peer
            NOTICE.* <HOST> failed to authenticate as '.*'$

ignoreregex =
/etc/fail2ban/jail.local
[asterisk]
enabled  = true
port     = 5060,5061
filter   = asterisk
logpath  = /var/log/asterisk/full
maxretry = 5
bantime  = 3600
findtime = 300
sudo systemctl restart fail2ban
sudo fail2ban-client status asterisk

Call Quality Testing

Test codec performance
asterisk -rx "sip show peers"

Check active calls
asterisk -rx "core show channels"

Monitor RTP quality
asterisk -rx "rtp set debug on"
asterisk -rx "rtp set debug off"

Network latency check for VoIP (must be <150ms for good quality)
ping -i 0.2 -c 50 your-pbx.example.com | tail -1
Target - avg < 80ms, max < 150ms

Hunt Groups and IVR

In FreePBX - Applications > Ring Groups
Ring Group Number - 600
Ring Strategy - ringall
Ring Time - 20 seconds
Extensions - 101-102-103
Destination if no answer - Voicemail

IVR via Applications > IVR
Press 1 -> Extension 101 (Sales)
Press 2 -> Extension 102 (Support)
Press 0 -> Ring Group 600 (General)

Monitoring and Uptime

Check Asterisk status
fwconsole sa

Restart if needed
sudo systemctl restart asterisk

Cron-based health check
Add to crontab -e
*/5 * * * * asterisk -rx "core show version" > /dev/null 2>&1 || systemctl restart asterisk

SIP trunk registration status
asterisk -rx "sip show registry"
Output - Host: atlanta1.voip.ms    State: Registered

Related Reading

Related Articles

Built by theluckystrike. More at zovo.one