mlan/asterisk repository
This (non official) repository provides dockerized Asterisk PBX.
docker-compose.yml and Makefile files/srvmini, base, full and xtraThe MAJOR.MINOR.PATCH SemVer
is used. In addition to the three number version number you can use two or
one number versions numbers, which refers to the latest version of the
sub series. The tag latest references the build based on the latest commit to the repository.
The mlan/asterisk repository contains a multi staged built. You select which build using the appropriate tag from mini, base, full and xtra. The image with the tag mini only contains Asterisk itself.
The base tag also include support for TLS, logging, WebSMS and AutoBan. full adds support for console audio. The xtra tag includes all Asterisk packages.
To exemplify the usage of the tags, lets assume that the latest version is 1.0.0. In this case latest, 1.0.0, 1.0, 1, full, full-1.0.0, full-1.0 and full-1 all identify the same image.
There are many things to consider when configuring Asterisk and its components. We discuss some fundamentals here and in the separate documentation for the add-ons.
If you want to test the image right away, probably the best way is to clone the github repository and run the demo therein.
git clone https://github.com/mlan/docker-asterisk.git
An example of how to configure an VoIP SIP server using docker compose is given below.
version: '3'
services:
tele:
image: mlan/asterisk
network_mode: bridge # Only here to help testing
cap_add:
- sys_ptrace # Only here to help testing
- net_admin # Allow NFT, used by AutoBan
- net_raw # Allow NFT, used by AutoBan
ports:
- "${SMS_PORT-8080}:${WEBSMSD_PORT:-80}" # WEBSMSD port mapping
- "5060:5060/udp" # SIP UDP port
- "5060:5060" # SIP TCP port
- "5061:5061" # SIP TLS port
- "10000-10099:10000-10099/udp" # RTP ports
environment:
- SYSLOG_LEVEL=${SYSLOG_LEVEL-4} # Logging
- HOSTNAME=${TELE_SRV-tele}.${DOMAIN-docker.localhost}
- PULSE_SERVER=unix:/run/pulse/socket # Use host audio
- PULSE_COOKIE=/run/pulse/cookie # Use host audio
- WEBSMSD_PORT=${WEBSMSD_PORT-80} # WEBSMSD internal port
volumes:
- tele-conf:/srv # Persistent storage
- ./pulse:/run/pulse:rshared # Use host audio
- /etc/localtime:/etc/localtime:ro # Use host timezone
volumes:
tele-conf: # Persistent storage
This repository contains a demo directory which hold the docker-compose.yml file as well as a Makefile which might come handy. From within the demo directory you can start the container simply by typing:
make up
The you can connect to the asterisk command line interface (CLI) running inside the container by typing
make cli
From the Asterisk CLI you can type
pjsip show endpoints
to see the endpoints (soft phones) that are configured in the /etc/asterisk/pjsip_endpoint.conf configuration file that comes with the image by default.
When you are done testing you can destroy the test container by typing
make destroy
Despite the fact that Asterisk is configured using configuration files, there is a handful of environmental variables that controls the behavior of services within the mlan/asterisk container. These services are logging, the management of TLS certificates, and the WebSMS add-on.
| Variable | Default | Description |
|---|---|---|
| SYSLOG_LEVEL | 4 | Logging level, from 0 to 8. 0 is the least, whereas, 8 is the most log outputs. |
| SYSLOG_OPTIONS | -SDt | S: smaller output, D: drop duplicates, t: Strip client-generated timestamps. |
| ACME_FILE | /acme/acme.json | File that contains TLS certificates, provided by Let's encrypt using Traefik. |
| HOSTNAME | $(hostname) | Used to identify the relevant TLS certificates in ACME_FILE. |
| TLS_CERTDAYS | 30 | Self-signed TLS certificate validity duration in days. |
| TLS_KEYBITS | 2048 | Self-signed TLS key length in bits. |
| WEBSMSD_PORT | 80 | PHP web server port, used by WebSMS. Undefined or non-numeric, will disable the PHP web server. |
Asterisk and its modules are configured using several configuration files which are typically found in /etc/asterisk. The /mlan/asterisk image includes a collection of sample configuration files which can serve as starting point for your system.
Some of the configuration files provided does not contain any user specific data and might initially be left unmodified. These files are:
| File name | Description |
|---|---|
| alsa.conf | Open Sound System (ALSA) console driver configuration |
| asterisk.conf | Asterisk global configuration including; debug, run-as-user and directory structure |
| ccss.conf | Call Completion Supplementary Services configuration |
| cli_aliases.conf | Asterisk Command Line Interface aliases |
| features.conf | Call Features (transfer, monitor, etc) configuration |
| indications.conf | Location specific tone indications |
| logger.conf | Logging configuration |
| modules.conf | Module Loader configuration |
| musiconhold.conf | Music on Hold configuration |
| pjproject.conf | Common pjproject options |
| rtp.conf | RTP configuration including port range |
The configuration files mentioned above are perhaps not the ones that require the most attention. The configuration files defining key aspects of the Asterisk server — like for instance, the call flow and SIP trunk and phone details — is the concern of the add-on PrivateDial. Please refer to its separate documentation for details.
By default, docker will store the configuration and run data within the container. This has the drawback that the configuration and state of the applications are lost together with the container, should it be deleted. It can therefore be a good idea to use docker volumes and mount the configuration and spool directories directories on such volumes so that the data will survive a container deletion.
To facilitate such approach, to achieve persistent storage, the configuration and spool directories of the services has been consolidated under /srv. The applications running inside the container still finds files in their usual locations since symbolic links are placed in these locations pointing back to /srv. With this approach simply mounting a docker volume at /srv let you keep application configuration and state persistent.
The volume tele-conf in the demo, which uses docker-compose, described above, achieves this. Mounting a volume using the docker CLI, can look like this:
docker run -d -v tele-conf:/srv ... mlan/asterisk
The mlan/asterisk image contains sample configuration files placed in a seeding directory. The actual configuration directory is empty. When the container starts, the configuration directory, etc/asterisk , is scanned. If it is found to be empty, sample configuration files from the seeding directory are copied to the configuration directory.
The seeding procedure will leave any existing configuration untouched. If configuration files are found, nothing is copied or modified during start up. Only when etc/asterisk is found to be empty, will seeding files be copied. This behavior should keep your conflagration safe also when upgrading to a new version of the mlan/asterisk image. Should a new version of the mlan/asterisk image come with interesting updates to any sample configuration files, it needs to manually be copied or merged with the present configuration files.
SYSLOG_LEVELThe level of output for logging is in the range of 0 to 8. 1 means emergency logging only, 2 for alert messages, 3 for critical messages only, 4 for error or worse, 5 for warning or worse, 6 for notice or worse, 7 for info or worse, 8 debug. Default: SYSLOG_LEVEL=4
The mlan/asterisk repository contains add-ons that utilizes and extends the already impressive capabilities of Asterisk.
PrivateDial is a suite of Asterisk configuration files. This configuration is tailored to residential use cases, supporting the capabilities of mobile smart phones, that is, voice, video, instant messaging or SMS, and voice mail delivered by email.
It uses the PJSIP channel driver and therefore natively support simultaneous connection of several soft-phones to each user account/endpoint.
The underlying design idea is to separate the dial plan functionality from the user data. To achieve this all user specific data has been pushed out from the main extensions.conf file.
AutoBan is an intrusion detection and prevention system which is built-in the mlan/asterisk image. The intrusion detection is achieved by Asterisk itself. Asterisk generates security events which AutoBan listens to on the AMI interface.
When security events occurs AutoBan start to monitor the source IP address. Should repeated security events occur intrusion prevention is activated. Intrusion prevention is achieved by AutoBan asking the Linux kernel firewall nftables to drop packages from offending source IP addresses.
Asterisk supports SMS to be sent and received using the extended SIP method; MESSAGE, natively. Still many Internet Telephony Service Providers (ITSP) does not support this method, but instead used a web API based on HTTP requests. This leaves your Asterisk server without a mechanisms to exchange SMS externally.
The WebSMS service bridges this limitation, with the help of two components. The first, websmsd, which waits for incoming SMS to be sent from your ITSP and once received, forwards it to Asterisk. The second, websms, is used by Asterisk to send outgoing SMS to your ITSP.
WEBSMSD_PORTWebSMS uses PHP's integrated web server. The environment variable WEBSMSD_PORT=80 determinate which port the web server listens to. If WEBSMSD_PORT is undefined or non-numeric the PHP web server is disabled, and consequently, WebSMS too. Disabling the web server might be desired in scenarios when the container runs in host mode and there are concerns with port number clashes with other services running on the host.
SIP networking is quite complex and there is many things that can go wrong. We try to offer some guidance by discussing some fundamentals here.
The Session Initiation Protocol (SIP) is a signaling protocol used for initiating, maintaining, and terminating real-time sessions that include voice, video and messaging applications.
SIP is designed to be independent of the underlying transport layer protocol, and can be used with the User Datagram Protocol (UDP), the Transmission Control Protocol (TCP), and the Stream Control Transmission Protocol (SCTP). For secure transmissions of SIP messages over insecure network links, the protocol may be encrypted with Transport Layer Security (TLS). For the transmission of media streams (voice, video) the Session Description Protocol (SDP) payload carried in SIP messages typically employs the Real-time Transport Protocol (RTP) or the Secure Real-time Transport Protocol (SRTP).
When sending an audio stream it is far better to lose a packet than to have a packet retransmitted, causing excessive jitter in the packet timing. Audio is real-time and requires a protocol like UDP to work correctly. Packet loss does not break audio, it only reduces the quality. Therefore it is no surprise that RTP is built on top of UDP; an connection-less protocol.
TCP is a connection-oriented protocol as it establishes an end to end connection between computers before transferring the data. TCP is therefore, by contrast, ideal for SIP signaling. The somewhat unexpected fact that most SIP communication uses UDP should not discourage you from choosing TCP when possible. TCP often provide more reliable contacts with endpoints/phones than UDP.
TLS, operating as an application protocol layered directly over TCP, protects against attackers who try to listen on the signaling link but it does not provide end-to-end security to prevent espionage and law enforcement interception, as the encryption is only hop-by-hop and every single intermediate proxy has to be trusted.
The media streams which are separate connections from the signaling stream, may be encrypted with the Secure Real-time Transport Protocol (SRTP). The key exchange for SRTP is performed with SDES, or with DTSL.
SIP traffic typically use the port numbers 5060 or 5061. Port 5060 is commonly used for non-encrypted signaling traffic, i.e., TCP or UDP, whereas port 5061 is used for encrypted, TLS, traffic.
RTP uses a dynamic port range generally between 10000-20000. This range can usually be customized on the client to suit differing firewall configurations or other concerns.
When publishing ports on a docker container, using the default bridge networking, two things happen; routing rules are updated in the Linux kernel firewall and a proxy processes are stated. The current networking implementation in docker (19.03.8), built on the aged iptables and docker-proxy, cannot publish port ranges, but instead publish them one by one.
Normally RTP uses the port range 10000-20000, encompassing 10001 ports. This is problematic since, updating the firewall rules 10001 times and starting 10001 proxy processes can take unacceptable long time (minutes) and can cause the container startup to stall. Longterm this limitation will be addressed, since it is inevitable that docker networking will have to be redesigned. But right now we have to work around this imitation and we describe two ways to address this here.
First, you can use the host network mode (docker run --network host …). The host network mode does not use the docker-proxy and does not need to set up routing rules in the firewall. The downside is that a container stated in this way cannot communicate on any of the docker networks.
Second, you can stay with the default or user-defined bridge mode and instead limit the RTP port range to something manageable say 10000-10099, or up to 10000-10999. This actually seems to work in practice, at least with some trunk providers (ITSP). The RTP port range is configured in rtp.conf
[general]
rtpstart = 10000
rtpend = 10099
Network address translation (NAT) is a method of remapping one IP address space into another by modifying the network address information in the IP header of packets while they are in transit across a traffic routing device. Network environments often results in NAT being used. On the one hand, the SIP server we deploy using mlan/asterisk often uses a Docker bridge network, connecting Dockers local network with the one the host is connected to. On the other, SIP clients running on mobile phones often end up connect to remote local networks.
To provide SIP clients with the external network address of a server behind NAT it can explicitly be defined on the transport used which is configured in pjsip_transport.conf
[t_wan](!)
type = transport
bind = 0.0.0.0:5060
domain = example.com
external_signaling_address = sip.example.com
external_media_address = sip.example.com
For endpoints connected to remote local networks you need the following parameters which are defined in pjsip_wizard.conf
[_nat](!)
endpoint/rewrite_contact = yes
endpoint/direct_media = no
endpoint/rtp_symmetric = yes
endpoint/bind_rtp_to_media_address = yes
Strict RTP learning is not compatible with NAT. When enabled, RTP media packets that have passed NAT will be dropped, resulting in an one way audio experience. Disable strict RTP learning in rtp.conf
[general]
strictrtp = no
Sometimes there is a need for other more elaborate NAT traversal methods; ICE, STUN or TURN. A treatment of these is a little bit out of scope for this text.
Transport Layer Security (TLS) provides encryption for call signaling. A excellent guide for setting up TLS between Asterisk and a SIP client, involving creating key files, modifying Asterisk's SIP configuration to enable TLS, creating a SIP endpoint/user that's capable of TLS, and modifying the SIP client to connect to Asterisk over TLS, can be found here Secure Calling Tutorial.
The PrivateDial configuration is already set up to provide both UDP and TCP transport. TLS, SDES and DTSL SRTP are also prepared, but a TLS/SSL server certificate and key are needed for their activation. If the certificate and key do not exist when the container starts a self-signed certificate and private key will automatically be generated.
TLS_KEYBITS, TLS_CERTDAYSThe private key length and self-signed certificate validity duration can be configured using the environment variables: TLS_KEYBITS=2048 and TLS_CERTDAYS=30.
Let’s Encrypt provide free, automated, authorized certificates when you can demonstrate control over your domain. Automatic Certificate Management Environment (ACME) is the protocol used for such demonstration.
There are many agents and applications that supports ACME, e.g., certbot. The reverse proxy Traefik also supports ACME. mlan/asterisk can use the TLS certificates Traefik has acquired.
ACME_FILE, ACME_POSTHOOKThe mlan/asterisk image looks for the file ACME_FILE=/acme/acme.json at container startup. If it is found certificates within this file are extracted. If the host or domain name of one of those certificates matches HOSTNAME=$(hostname) or DOMAIN=${HOSTNAME#*.} it will be used by the TLS transport. Moreover, the ACME_FILE will be monitored and should it change the certificates will be exported anew. So when Traefik renews its certificates Asterisk will automatically also have access to the new certificate.
Once the certificates and keys have been updated, we run the command in the environment variable ACME_POSTHOOK="sv restart asterisk". Asterisk needs to be restarted to reload the transport, i.e., TLS parameters to be updated. If automatic restarting of Asterisk is not desired, set ACME_POSTHOOK= to empty.
Using Traefik's certificates will work "out of the box" simply by making sure that the /acme directory in the Traefik container is also is mounted in the mlan/asterisk container.
docker run -d -v proxy-acme:/acme:ro mlan/asterisk
Note, if the target certificate Common Name (CN) or Subject Alternate Name (SAN) is changed the container needs to be restarted.
Attempts by attackers to crack SIP passwords and hijack SIP accounts are very common. Most likely the server will have to fend off thousands of attempts every day. here we mention three means to improve intrusion prevention; obscurity by using non-standard ports, SIP passwords strength, and AutoBan; an Intrusion Detection and Prevention System.
When using non-standard ports the amount of attacks drop significantly, so it might be considered whenever practical. When changing port numbers they need to be updated both for docker and asterisk. To exemplify, assume we want to use 5560 for UDP and TCP and 5561 for TLS, in which case we update the configuration in two places:
docker run -p "5560-5561:5560-5561" -p "5560:5560/udp" …Content type
Image
Digest
sha256:96c2e8f04…
Size
93.4 MB
Last updated
6 months ago
docker pull mlan/asterisk:xtra-1.1.13