Recently, I decided to setup a much more feature filled phone system, and in the open source telephony / PBX landscape there is only one serious option: Asterisk. Given our CoreOS and Docker based infrastructure, and the fact that there is no official Asterisk Docker image, I needed to make my own Docker image to support all of the advanced features I wanted including:
PJSIP - The modern SIP channel driver
Websockets and TLS Websockets (ws://, wss://)
SRTP (encrypted RTP media)
Modern versions, e.g. 13 and 14, to test between
Project Layout with docker-compose
The following docker-compose.yml is useful when testing local SIP clients, and smaller installs (the main limiting factor here being the RTP port range size).
version: '2' services: asterisk: image: hibou/asterisk:13 ports: - "5060:5060/udp" - "5060:5060/tcp" - "10000-10099:10000-10099/udp" - "8088:8088" - "8089:8089" volumes: - "./var/conf/msmtprc:/etc/msmtprc" - "./var/conf/asterisk:/etc/asterisk" - "./var/data/asterisk:/var/lib/asterisk" - "./var/data/asterisk-spool:/var/spool/asterisk" networks: default: ipv4_address: 10.3.2.10 networks: default: ipam: config: - subnet: 10.3.2.0/24
Some key points here:
Don’t forward too many ports to the container (RTP port range)
Setup a static IP range which helps to be able to reference in your configuration files
SIP signaling is traditionally over UDP, so you must tell docker to bind UDP when needed. (though you can use TCP)
RTP Ports are always over UDP
Depending on your call volume, you may need to have more RTP ports setup, or reduce the load due to forwarding ports into the container’s bridge network. A pretty typical setup has 10k ports in a range 10000-20000, and with the current Docker implementation this is impossible to do efficiently.
To achieve this, you can use "host" network mode.
version: '2' services: asterisk: image: hibou/asterisk:13.15.0 volumes: - "./var/conf/msmtprc:/etc/msmtprc" - "./var/conf/asterisk:/etc/asterisk" - "./var/data/asterisk:/var/lib/asterisk" - "./var/data/asterisk-spool:/var/spool/asterisk" hostname: sip domainname: sip.yourhost.name network_mode: "host"
With no port forwards, ensure that your configuration only binds to IP’s and ports that are necessary (e.g. if you have multiple Asterisk containers, config files must not have 0.0.0.0 in them).
By default, Asterisk is configured heavily through configuration files. The image comes with the default configuration files from the Asterisk source code. You can extract the sample configurations (and data directories) by binding your local folders into different directories for a single run. So swap out the volumes in one of the above `docker-compose.yml` files for these.
volumes: - "./var/conf/asterisk:/ic" - "./var/data/asterisk:/id" - "./var/data/asterisk-spool:/ids"
And then run `docker-compose run --rm asterisk bash -c “cp -R /etc/asterisk/* /ic && cp -R /var/lib/asterisk/* /id && cp -R /var/spool/asterisk/* /ids”` . This will get you in a good starting point to start your specific customizations.
At the bare minimum, you will want to spend time in the following files.
extensions.conf : Setup your dialplan contexts.
sip.conf or pjsip.conf : Setup the addresses and ports where SIP clients and trunks will communicate with your server.
http.conf : Setup addresses and ports for websocket based clients (e.g. Odoo Enterprise VoIP integration using sip.js for WebRTC)
If you plan on sending mail (e.g. sending a user their voicemail), you will need to provide some way for Asterisk to send mail. Asterisk uses `/etc/sbin/sendmail` to do this (and appears to be hardcoded to do so). Given this is docker, we don’t want Postfix or some other MTA running in the server. Instead, I have installed and symlinked msmtp to that location. All you need to do is provide msmtp a configuration file at `/etc/msmtprc`, and msmtp will send your mail out by connecting to a SMTP server of your choice (e.g. smtp.gmail.com or smtp.mandrillapp.com).
For more information check out the msmtp project and documentation.
Asterisk has two ‘data like’ folders, one at `/var/lib/asterisk` which holds media files that are commonly used to play sounds and greetings to people, as well as storing on hold music. Typically you will record custom greetings into a path in this folder as well. It is possible to use the defaults inside the image and instead mount a custom recording directory inside of the sounds directory.
Note, if you try to record into something like ‘custom/greeting’, Asterisk will not create the folder for you, so make sure the folder exists beforehand.
The next data directory is at `/var/spool/asterisk` where call recordings and voicemail lives.
WebRTC and Odoo
One of the main reasons I wanted to do this was to be able to use the existing integration inside of Odoo Enterprise to enable a sales user to call leads in a sequential list using only their browser.
This leads to challenges beyond the typical Asterisk use cases requiring both Websockets (http.conf) to be configured, as well as special options for the dialing peers (sip.conf/pjsip.conf). Odoo’s documentation will help here, just keep in mind that you will not be able to use the same SIP peer for a deskphone and WebRTC. Additionally, if you are running Odoo on SSL then you need even more work to get WSS and SRTP configured and working.
Note that the current version of Odoo’s sip.js is a little out of date, and has some issues communicating with PJSIP. Using sip.js version 0.7.7 release instead has gotten me the best results so far.
Browser support is a mixed bag here, currently I have outgoing calls working with modern Safari (Technology Preview Release 33 (Safari 11.0, WebKit 12604.1.25.0.2)), Firefox (53.0.3), and Chrome (58.0.3029.110).
However, both Safari and Firefox cannot receive calls. They start, but when you accept the call in the browser, Asterisk immediately returns from the Dial with NOANSWER.
While this implementation is not perfect, I will continue looking into what can be done to improve upon this with newer versions of SIP.js and other settings changes.
If you have any Asterisk or WebRTC tips or questions, please drop me a line or comment below.
If you want to see it in action, just call us at 1-206-800-7778