DEV Community

Cover image for Building scalable IVRs for businesses with Routr and Asterisk
Pedro Sanders for Fonoster Inc

Posted on • Edited on

Building scalable IVRs for businesses with Routr and Asterisk

In this tutorial, I will share how to create a VoIP network combining Routr, RTPEngine, and Asterisk for highly available voicemail, conference, IVR, or any other application in Asterisk.

The added advantage of this setup is that you can use Asterisk as a feature server and have dedicated instances for each feature you would like to provide.

GitHub logo fonoster / routr

⚡ The future of programmable SIP servers.

Requirements

Before you start this tutorial, you will need the following:

  • Docker Engine installed on your computer or the cloud
  • NodeJS 18+ (Use nvm if possible)
  • Routr command-line tool (Install it with npm install -g @routr/ctl)

Deploying Routr and Asterisk using Docker Compose

You will use Docker Compose for this setup; however, I recommend using Docker Swarm mode or Kubernetes for a production-ready setup.

Please see Routr's Helm chart for details on how to run Routr in K8s

To get started, first create a folder named voipnet. In the new folder, create a file name compose.yaml with the following content:

Filename: voipnet/compose.yaml

version: "3"

services:
  routr:
    image: fonoster/routr-one:latest
    environment:
      EXTERNAL_ADDRS: ${DOCKER_HOST_ADDRESS}
      RTPENGINE_HOST: rtpengine
    ports:
      - 51908:51908
      - 5060:5060
      - 5062:5062
    volumes:
      - shared:/var/lib/postgresql/data

  rtpengine:
    image: fonoster/rtpengine:latest
    ports:
      - 22222:22222/udp
      - 10000-10100:10000-10100/udp
    environment:
      PUBLIC_IP: ${DOCKER_HOST_ADDRESS} 
      PORT_MIN: 10000
      PORT_MAX: 10100

  asterisk-01:
    image: fonoster/mediaserver:latest
    expose:
      - 6060
    environment:
      EXTERN_ADDR: ${DOCKER_HOST_ADDRESS}
      SIPPROXY_HOST: routr
      SIPPROXY_USERNAME: asterisk
      SIPPROXY_SECRET: asterisk
    volumes:
      - ./extensions.conf:/etc/asterisk/extensions.conf
      - ./sounds/count_1.sln16:/var/lib/asterisk/sounds/count.sln16

  asterisk-02:
    image: fonoster/mediaserver:latest
    expose:
      - 6060
    environment:
      EXTERN_ADDR: ${DOCKER_HOST_ADDRESS}
      SIPPROXY_HOST: routr
      SIPPROXY_USERNAME: asterisk
      SIPPROXY_SECRET: asterisk
    volumes:
      - ./extensions.conf:/etc/asterisk/extensions.conf
      - ./sounds/count_2.sln16:/var/lib/asterisk/sounds/count.sln16

  simplephone:
    image: psanders/simplephone:latest
    ports:
      - 8080:8080

volumes:
  shared:
Enter fullscreen mode Exit fullscreen mode

A few things to note:

  • We added the shared volume to make sure the data survives container restarts
  • The simplephone and rtpengine services are optional, and you may remove them if you don't need support for WebRTC
  • Notice how we mapped the sounds count_1.sln16 to asterisk-1 and count_2.sln16 to asterisk-2 respectively.

Next, in the same folder, create the file extensions.conf

Filename: voipnet/extensions.conf

[local-ctx]
exten => asterisk,1,NoOp()
 same => n,Playback(count)
 same => n,Hangup()
Enter fullscreen mode Exit fullscreen mode

The previous configuration features the equivalent of a "Hello world" for Asterisk. However, you could use the same principle and instead connect it to a voice application or conference.

Then, create a sounds folder and download count_2.sln16 and count_2.sln16 from here.

Your folder structure will end up like this:

.
├── compose.yaml
├── extensions.conf
└── sounds
    ├── count_1.sln16
    └── count_2.sln16
Enter fullscreen mode Exit fullscreen mode

Finally, run the following command to start all the services:

# NOTE: Be sure to update the IP address
DOCKER_HOST_ADDRESS=192.168.1.7 docker compose up
Enter fullscreen mode Exit fullscreen mode

The previous command will pull all the services from Docker Hub and run the containers. You could also add the -d option to run the service in the background.

Configuring the network with Routr Command-Line Tool

You will use Routr's command-line tool to issue commands to the server and build the VoIP network.

For the setup, we will create a Domain with the sip.local URI, an Agent to test the calls and a Peer to represent Asterisk.

Remember that while we are using Agents for testing, in production, you would instead use Trunks to accept PSTN traffic, which is not covered in this tutorial.

We will start by creating a Domain with:

rctl domains create --insecure
Enter fullscreen mode Exit fullscreen mode

Notice the --insecure flag, which is required since we don't have a TLS certificate.

The output of your command will look similar to the output below:

Press ^C at any time to quit.
 ›   Warning: Egress rules unavailable due to 0 configured numbers.
? Friendly Name Local Domain
? SIP URI sip.local
? IP Access Control List None
? Ready? Yes
Creating Domain Local Domain... 3b20410a-3c80-4f66-b7b3-58f65ff65352
Enter fullscreen mode Exit fullscreen mode

Next, create two sets of credentials, one for Asterisk and one for John Doe, by issuing the following command:

rctl credentials create --insecure
Enter fullscreen mode Exit fullscreen mode

Your output will be similar to this:

This utility will help you create a new set of Credentials.
Press ^C at any time to quit.
? Friendly Name John Doe - Credentials
? Username 1001
? Password [hidden]
? Ready? Yes
Creating Credentials John Doe - Credentials... 5fbc7367-a59d-4555-9fc4-a15ff29c24c8
Enter fullscreen mode Exit fullscreen mode

Repeat the process for Asterisk, and set the password to asterisk.

Next, create an Agent to represent the test Agent, John Doe, with the following command:

rctl agents create --insecure
Enter fullscreen mode Exit fullscreen mode

Your output will be like the one below:

This utility will help you create a new Agent.
Press ^C at any time to quit.
? Friendly Name John Doe
? Select a Domain sip.local
? Username 1001
? Credentials Name John Doe - Credentials
? Max Contacts
? Privacy None
? Enabled? Yes
? Ready? Yes
Creating Agent John Doe... 662a379d-66f1-4e6e-9df5-5126f1dcb930
Enter fullscreen mode Exit fullscreen mode

Finally, create a Peer to represent Asterisk with:

rctl peer create --insecure
Enter fullscreen mode Exit fullscreen mode

Follow the prompt, select Round Robin as the balancing algorithm, and sip:asterisk as the Address of Record (AOR).

The output should look like this:

This utility will help you create a new Peer.
Press ^C at any time to quit.
? Friendly Name Asterisk PBX
? Username asterisk
? Address of Record sip:asterisk
? Contact Address 
? Max Contacts 
? IP Access Control List None
? Credentials Name Asterisk - Credentials
? Enable Session Affinity? No
? Balancing Algorithm Round Robin
? Enabled? Yes
? Ready? Yes
Creating Peer Asterisk PBX... 1f859fee-5c4c-4771-b8fd-a6c469ffe9bf
Enter fullscreen mode Exit fullscreen mode

You might use the get subcommand to verify your settings.

For example:

rctl agents get --insecure --extended
Enter fullscreen mode Exit fullscreen mode

Calling Asterisk from the Browser using SIP.js

The compose file we created at the beginning of this tutorial contains the simplephone container, a softphone implemented with SIP.js, which is available at http://localhost:8080.

Here is what the SimplePhone will look like:

Example using the SimplePhone

Set your instance to look like the one below, then click "Save and connect," followed by "Call."

You should hear the numbers alternate every time you press "Call," showing that the calls are correctly load-balanced.

What’s next?

Please comment if you find this tutorial helpful and check out the following relevant tutorials:

Top comments (0)