Asterisk Architecture Demystified: Build, Configure, and Scale Your PBX | Brav

Discover how to master Asterisk’s modular architecture, configure channels, dial plans, and APIs. Build a scalable PBX from scratch with step-by-step guidance.

Asterisk Architecture Demystified: Build, Configure, and Scale Your PBX

Published by Brav

Table of Contents

TL;DR

  • Asterisk is a modular, open-source PBX that can be built on any OS.
  • Core files live in /etc/asterisk; modules live in /usr/lib/asterisk/modules.
  • Control concurrent calls with maxcalls in asterisk.conf.
  • Load only the modules you need via modules.conf and configure channel drivers (SIP, PJSIP, DAHDI, Local).
  • Use ARI for real-time control, AGI for scripting, and AMI for monitoring – pick the right API for your use case.

Why this matters

I’ve spent years watching engineers stumble over the sheer number of configuration files that ship with Asterisk. The most common frustrations are:

  • Not knowing which modules to load, which can bloat memory and expose unused features.
  • Drowning in the wild variety of dialplan syntax, especially when trying to combine legacy SIP with modern PJSIP.
  • Seeing calls drop because I set the wrong maxcalls value, or because the system is overwhelmed with media streams.
  • Integrating analog lines (FXS/FXO) or digital T1/E1 cards feels like learning a new language.

All of these issues arise from a single source of truth: the architecture and configuration files. Mastering this architecture turns a noisy, unstable PBX into a lean, scalable platform that can be expanded with voicemail, IVR, and even WebRTC support.

Core concepts

Asterisk is built around three pillars: a core engine, loadable modules, and a dialplan.

  • The core engine (the asterisk binary) parses configuration, manages threads, and hosts the event loop.
  • Modules (in /usr/lib/asterisk/modules – see [Directory and File Structure (2025)]) provide applications, channel drivers, codecs, and back-ends.
  • The dialplan (stored in extensions.conf) is the glue that tells Asterisk what to do when a call enters or exits a channel.

Together they form a flexible, scriptable platform that can be turned into a traditional PBX, a media server, or a programmable API endpoint.

Modules and the module loader

Asterisk loads modules via modules.conf (see [Module Loader (2025)]). The default setting is autoload=yes, which scans the modules directory and loads everything it finds. This is convenient, but it also means that every module – even unused ones – consumes memory and, in some cases, listens on network ports. The best practice is to switch to autoload=no and then explicitly list the modules you need, e.g.:

; modules.conf
autoload=no
load => chan_sip.so
load => chan_pjsip.so
load => chan_dahdi.so
load => app_dial.so

Doing so gives you tighter control over resource usage and reduces the attack surface of your PBX. The modules directory itself lives at /usr/lib/asterisk/modules – this location is hard-coded in the core configuration ([Directory Structure (2025)]).

Channel drivers – SIP, PJSIP, DAHDI, and Local

Channels are the lifelines that connect Asterisk to the outside world. Each driver is a module that implements the core Asterisk channel interface.

Channel DriverUse CaseLimitation
chan_sipLegacy SIP devices, simple PBXLimited to SIP 2006, no WebRTC, slower
chan_pjsipModern SIP, WebRTC, advanced codecsRequires libnice, heavier, needs additional configuration
chan_dahdiAnalog/T1/E1 lines via DAHDI cardsHardware dependent, requires DAHDI drivers, not all platforms

The Local channel (chan_local) is a special driver that creates a fake call that stays entirely inside Asterisk. It is a powerful tool for invoking dialplan logic without creating an external media stream – the article on “Local Channels” explains this in depth (see [Channels (2025)]).

The dialplan – extensions.conf

The dialplan is a text file full of contexts (scopes) and extensions (rules). Each line looks like:

exten => 100,1,Dial(PJSIP/100)

The 1 is the priority, and Dial() is an application that hands control to the channel driver. Asterisk reads the dialplan during boot, but you can also reload it on the fly with dialplan reload. The dialplan can be split into multiple files (e.g. voicemail.conf, voicemail.conf) and included with #include. Because the dialplan is just plain text, version control becomes a natural way to track changes and rollback misconfigurations.

Media and local channels

Media flows over RTP, SIP, or other transport protocols. Asterisk’s media subsystem can transcode codecs on the fly, route streams through bridges, and even provide media server features like voicemail or IVR. When you dial a Local channel, Asterisk internally creates two channels – the “caller” and the “callee” – even though no external media ever leaves the server. This is why a single logical call in Asterisk often consumes two channel resources, a fact that directly impacts the maxcalls setting.

The key configuration files

  • asterisk.conf – global settings such as directories, log level, and maxcalls ([Asterisk — Core Configuration File (2025)]).
  • modules.conf – which modules to load ([Module Loader (2025)]).
  • pjsip.conf – endpoints, registries, and transports for modern SIP ([Channels (2025)]).
  • sip.conf – legacy SIP configuration (used only if you still need chan_sip).
  • extensions.conf – your dialplan.
  • agi-bin/ – AGI scripts.
  • sounds/ – audio files for IVR.

The maxcalls parameter in asterisk.conf controls the total number of active channels. Setting it too low will cause legitimate calls to be rejected; setting it too high can exhaust CPU or memory. The default is 255, but most deployments set it to a value that matches the hardware capacity (e.g. 200 for a small office, 1000+ for a data-center PBX) ([Asterisk — Core Configuration File (2025)]).

APIs – ARI, AGI, and AMI

Asterisk exposes three APIs that cater to different needs.

  • ARI (Asterisk REST Interface) is a modern, asynchronous API that gives you fine-grained control over channels, bridges, and media. The official docs describe its REST endpoints and WebSocket events ([ARI (2025)]). ARI is ideal when you want to build a custom application that can originate calls, play media, or route traffic dynamically.
  • AGI (Asterisk Gateway Interface) runs a script (Python, Perl, PHP, etc.) that is launched from the dialplan. AGI is synchronous – the dialplan waits until the script finishes. Because the script runs as a separate process, you can perform arbitrary logic such as querying a database or posting to Twitter. The AGI documentation lists a large number of libraries (Python’s pyst2, PHP’s PHPAGI, etc.) ([AGI (2025)]).
  • AMI (Asterisk Manager Interface) is a TCP socket that streams events and allows you to send commands to Asterisk in real time. AMI is perfect for monitoring, generating CDRs, or integrating with a CRM ([AMI (2025)]).

Choosing the right API depends on latency, event handling, and whether you need to execute external code. In practice, many deployments use a combination: AGI for heavy scripting, AMI for monitoring, and ARI for real-time control.

Scaling for high concurrent calls

The biggest bottleneck in a PBX is often the number of concurrent media streams. A single SIP call consumes at least one channel in the media subsystem and, because of the B2BUA model, usually two channels in total. This means that a 200-call load typically requires 400 channel objects plus associated memory.

To scale, you should:

  1. Tune maxcalls – set it to the maximum you expect to run simultaneously, but leave a safety margin.
  2. Use proper hardware – at least a quad-core CPU and 2 GB of RAM per 200 calls is a good rule of thumb.
  3. Leverage multiple Asterisk instances – use a load balancer (e.g., OpenSIP or a dedicated SBC) to distribute INVITEs across servers.
  4. Enable fast media routing – enable directmedia=yes in pjsip.conf if the endpoints support it, which removes the need for Asterisk to receive and resend RTP packets.
  5. Monitor memory and CPUcore show uptime and asterisk -rvv core show channels give you real-time insight into channel usage.

Because Asterisk is a pure-C engine, it scales linearly with CPU cores, so adding a few more cores can unlock hundreds of additional concurrent calls.

Bridging the physical and virtual worlds

  • Analog/FXS and FXO – The chan_dahdi driver can attach to hardware cards (e.g., Digium’s G200), load chan_dahdi, and define an endpoint in pjsip.conf that maps to the FXS/FXO line. In the Switchvox appliances (E510/E545) you can push up to 50 or 200 concurrent calls respectively ([Switchvox – E510 (2025)]); [Switchvox – E545 (2025)].
  • Digital T1/E1 – The same driver handles digital PRI, simply by selecting the right line card and configuring chan_dahdi.
  • OpenSIP integration – The “Realtime OpenSIP – Asterisk Integration” tutorial shows how to run OpenSIP and Asterisk side by side, using a shared MySQL database for real-time registration and call routing ([OpenSIP – Integration (2025)]).
  • Camellia – Camellia is an open-source load-balancer that can sit in front of Asterisk for traffic distribution. While it is primarily a generic load balancer, its SIP-aware mode can be used to balance SIP INVITEs to multiple Asterisk nodes, though you’ll need to verify the configuration in your environment ([Camellia – Unverified]).

How to apply it

Below is a practical walk-through that takes a fresh Ubuntu install to a production-ready Asterisk PBX.

  1. Install Asterisk

    sudo apt update
    sudo apt install asterisk asterisk-dev asterisk-config
    
  2. Verify core installation

    asterisk -rvv core show version
    
  3. Configure directories – edit /etc/asterisk/asterisk.conf

    [directories]
    astetcdir => /etc/asterisk
    astmoddir => /usr/lib/asterisk/modules
    astvarlibdir => /var/lib/asterisk
    
  4. Set maxcalls – in [options]

    maxcalls = 200
    
  5. Create modules.conf – keep autoload off and load the drivers you need

    [modules]
    autoload = no
    load => chan_sip.so
    load => chan_pjsip.so
    load => chan_dahdi.so
    load => app_dial.so
    
  6. Configure PJSIP – create /etc/asterisk/pjsip.conf with an endpoint and a transport. Example for a softphone:

    [transport-udp]
    type=transport
    protocol=udp
    bind=0.0.0.0
    
    [100]
    type=endpoint
    context=default
    disallow=all
    allow=ulaw
    auth=100
    aors=100
    
    [100]
    type=aor
    max_contacts=1
    
    [100]
    type=auth
    auth_type=userpass
    username=100
    password=secret
    
  7. Create the dialplan/etc/asterisk/extensions.conf

    [default]
    exten => 100,1,Dial(PJSIP/100)
    exten => 101,1,Dial(PJSIP/101)
    exten => 9,1,VoicemailMain()
    
  8. Add an AGI script/var/lib/asterisk/agi-bin/twitter.py (Python) that posts a message when a call is answered. It can be invoked from the dialplan:

    exten => 100,1,AGI(twitter.py)
    
  9. Enable ARI – in /etc/asterisk/ari.conf

    [general]
    enabled = yes
    bindaddr = 0.0.0.0
    bindport = 8088
    
  10. Test and monitor

    • Use asterisk -rvv to load the configuration.
    • Run core show channels to confirm the number of channels.
    • Use curl http://localhost:8088/ari/channels to see ARI output.
  11. Deploy OpenSIP for external registrations – follow the OpenSIP tutorial and point its asterisk.conf section to your Asterisk instance.

  12. Set up a Switchvox appliance (optional) – if you want a turnkey PBX with analog lines, load the E545 or E510 appliance and connect it to your network.

With this baseline, you now have a fully functional PBX that can be expanded with voicemail, IVR, and even WebRTC support.

Pitfalls & edge cases

  • Unnecessary modules – loading chan_respoke.so without a Respoke server leads to unused sockets and can cause port conflicts.
  • Over-provisioning maxcalls – setting a very high value may lead to a memory leak if the system cannot handle the number of media threads.
  • Module compatibility – a module compiled for Asterisk 13 may not work on 18; always verify the asterisk -rvv core show modules output.
  • B2BUA double channel – because Asterisk is a back-to-back user agent, a single SIP call consumes two channel objects. This can quickly exhaust maxcalls on a high-volume system if you’re not aware.
  • Respoke vs WebRTC – Respoke is a server-side WebRTC bridge; you still need a properly configured TURN server if clients are behind NAT.
  • ARIs can flood the WebSocket – keep the number of concurrent WebSocket connections in check; otherwise the server may throttle or drop events.

Quick FAQ

  1. How do I choose which modules to load in production? Start with only the channel drivers you need (chan_sip or chan_pjsip) and the applications you use (app_dial, app_voicemail). Add additional modules as features are required, and remove unused ones to reduce attack surface.

  2. What are best practices for scaling Asterisk for high concurrent calls?

    • Tune maxcalls and use directmedia=yes if possible.
    • Add more CPU cores; Asterisk scales linearly.
    • Use a SIP proxy (OpenSIP or a dedicated SBC) to distribute INVITEs.
    • Monitor memory and CPU; set up alerts for core show channels.
  3. How does ARI differ from AGI and AMI in use cases?

    • ARI: asynchronous, real-time control over channels, bridges, and media – ideal for building custom apps.
    • AGI: synchronous scripts executed from the dialplan – useful for external logic like database lookups.
    • AMI: event-driven monitoring and command execution – great for reporting and management.
  4. What are the licensing implications of using Digium’s commercial OEM license vs open source GPL? Asterisk is dual-licensed: GPL v2 for the community edition, and a commercial OEM license for enterprises that want support or to embed Asterisk in proprietary products.

  5. How do I configure and maintain analog lines (FXS/FXO) on modern hardware? Install a DAHDI-compatible card (e.g., Digium G200), load chan_dahdi, and define an endpoint in pjsip.conf that maps to the FXS/FXO line. Use astdb or a real-time database to store line status.

  6. How to set up WebRTC via Respoke with Asterisk? Install Respoke’s res_ modules, configure res_asterisk.conf with your Respoke credentials, and enable the WebRTC interface in pjsip.conf. Point the client to Respoke’s WebSocket endpoint.

  7. How do I upgrade Asterisk modules when moving to a new version? Use apt-get upgrade asterisk or rebuild from source, then run module reload. Always review the changelog for breaking changes and test modules on a staging system first.

Conclusion

By treating the configuration files as the heart of your PBX, you gain the power to tune Asterisk to your exact needs. Start small – load only the drivers you need – and grow the system with measured maxcalls, proper media routing, and the right API for each task. Whether you’re a hobbyist building a home office PBX or a telecom engineer deploying a city-wide VoIP network, the same principles apply: understand the architecture, configure deliberately, and monitor relentlessly.

Actionable next steps for me:

  • Set up a test Asterisk on a virtual machine and walk through the steps above.
  • Benchmark concurrent call handling with ab or tsung to find the sweet spot for maxcalls.
  • Experiment with ARI by building a simple web UI that can originate calls and play custom prompts.
  • Finally, write a script to automate the deployment of modules.conf and pjsip.conf via Ansible, turning configuration into code.

Good luck – your PBX is now in your hands, and with Asterisk’s modular design, the sky’s the limit.

Last updated: December 16, 2025

Recommended Articles

Zynga’s Data Playbook: 5 Lessons that Built a $12.7B Empire | Brav

Zynga’s Data Playbook: 5 Lessons that Built a $12.7B Empire

Discover how Zynga turned data, viral marketing, and strategic acquisitions into a $12.7B empire. CTOs learn actionable tactics for mobile game growth.
Build Smarter AI Agents with These 10 Open-Source GitHub Projects | Brav

Build Smarter AI Agents with These 10 Open-Source GitHub Projects

Discover 10 top open-source GitHub projects that make AI agents and backend systems fast, reliable, and production-ready. From Mastra to Turso, get guidance now.
Build a Network Security Monitoring Stack in VirtualBox: From Capture to Alerts with tshark, Zeek, and Suricata | Brav

Build a Network Security Monitoring Stack in VirtualBox: From Capture to Alerts with tshark, Zeek, and Suricata

Learn how to set up a network security monitoring stack with tshark, Zeek, and Suricata on VirtualBox. Capture, analyze, and detect threats in real time.