Asterisk in a Debian LXC container

(January 2017)

We want to safely build and deploy new versions of Asterisk, and easily roll back changes. So, we package Asterisk in an LXC container. There are three stages:

  1. Build a new Asterisk container
  2. Inject the existing production config and data into the new Asterisk container
  3. Deploy the new container to production, and swap out the old container

To complicate matters, we pile FreePBX on top of Asterisk, to accommodate our more point-and-click-oriented staff.


We have a build/testing host with LXC installed and a NAT bridge. The external interface of this build host has the IP address The NAT bridge device is ‘lxcbr0’ with the network The host iptables FORWARD chain accepts traffic to and from lxcbr0, and the nat table has a POSTROUTING MASQUERADE rule for (both likely set up by lxc-nat). See for more about LXC.

We have a production host set up for LXC like our build/testing host. The production host has an exteral IP of (a placeholder for use in these notes).

We want our new container named “asterisk-debian-$(date +%Y%m%d)” to receive IP Our host NATs for the container, like:

# iptables -t nat -A PREROUTING --dst -p udp --dport 5060 -j DNAT --to
# iptables -t nat -A PREROUTING --dst -p tcp --dport 5061 -j DNAT --to
# iptables -t nat -A PREROUTING --dst -p udp --dport 10000:20000 -j DNAT --to

We may also want to NAT ports to the container’s sshd or httpd.

Building a container with Asterisk

On the build host:

# lxc-create -n asterisk-debian-$(date +%Y%m%d) -t debian -- -r jessie
# sed -i '/' /etc/lxc/dnsmasq.conf
# echo "dhcp-host=asterisk-debian-$(date +%Y%m%d)," >> /etc/lxc/dnsmasq.conf
# systemctl restart lxc-net
# lxc-start -n asterisk-debian-$(date +%Y%m%d)
# lxc-attach -n asterisk-debian-$(date +%Y%m%d)

Enter the container:

# du -hs
253M    .

# apt-get update
# apt-get dist-upgrade
# apt-get install wget build-essential vim-tiny less inetutils-ping tcpdump netcat-openbsd lsof libncurses5-dev uuid-dev libjansson-dev libxml2-dev libssl-dev libsqlite3-dev sqlite3 cron logrotate unixodbc-dev libltdl-dev
# cd /usr/local/src
# wget
# tar xf asterisk-13-current.tar.gz
# cd asterisk-13*
# ./configure --with-pjproject-bundled
# make menuselect


# make
# make install
# adduser asterisk --uid 3333 --disabled-password
# mkdir -p /etc/asterisk /usr/lib/asterisk /var/{lib,log,run,spool}/asterisk
# chown -R root:asterisk /etc/asterisk /usr/lib/asterisk /var/{lib,log,run,spool}/asterisk
# chmod -R 775 /etc/asterisk /usr/lib/asterisk /var/{lib,log,run,spool}/asterisk

# cd / ; du -hs
1.4G    .
# cd - ; make clean ; cd - ; du -hs
1011M   .
# apt-get clean; du -hs
835M    .

# cat << 'EOF' > /etc/systemd/system/asterisk.service

[Unit] Description=Asterisk PBX and telephony daemon Documentation=man:asterisk(8)

[Service] Type=simple User=asterisk Group=asterisk PermissionsStartOnly=true ExecStartPre=-/bin/mkdir -p /var/run/asterisk ExecStartPre=-/bin/chown -R root:asterisk /var/run/asterisk ExecStartPre=-/bin/chmod -R 775 /var/run/asterisk ExecStart=/usr/sbin/asterisk -g -f -C /etc/asterisk/asterisk.conf ExecStop=/usr/sbin/asterisk -rx ‘core stop now’ ExecReload=/usr/sbin/asterisk -rx ‘core reload’

Restart=always RestartSec=5

[Install] EOF # systemctl daemon-reload


# systemctl enable asterisk
# systemctl start asterisk
# lsof -Pi

Stacking FreePBX on top

In our container:

# apt-get install apache2 mysql-server mysql-client php5 php5-mysql php-pear libmyodbc sudo php5-curl php5-gd sox
# sed -i 's/\(^upload_max_filesize = \).*/\120M/' /etc/php5/apache2/php.ini
# sed -i 's/^\(User\|Group\).*/\1 asterisk/' /etc/apache2/apache2.conf
# sed -i 's/AllowOverride None/AllowOverride All/' /etc/apache2/apache2.conf

# ln -s /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/rewrite.load
# ln -s /etc/apache2/mods-available/ssl.conf /etc/apache2/mods-enabled/ssl.conf
# ln -s /etc/apache2/mods-available/ssl.load /etc/apache2/mods-enabled/ssl.load
# ln -s /etc/apache2/mods-available/socache_shmcb.load /etc/apache2/mods-enabled/socache_shmcb.load
# rm /etc/apache2/sites-enabled/000-default.conf
# cat << 'EOF' > /etc/apache2/sites-enabled/freepbx.conf

ServerAdmin webmaster@localhost DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined ServerName SSLEngine ON SSLVerifyClient optional SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key EOF # systemctl restart apache2 # rm /var/www/html/index.html # cat >> /etc/odbcinst.ini << EOF [MySQL] Description = ODBC for MySQL Driver = /usr/lib/x86_64-linux-gnu/odbc/ Setup = /usr/lib/x86_64-linux-gnu/odbc/ FileUsage = 1 EOF # cat >> /etc/odbc.ini << EOF [MySQL-asteriskcdrdb] Description=MySQL connection to ‘asteriskcdrdb’ database driver=MySQL server=localhost database=asteriskcdrdb Port=3306 Socket=/var/run/mysqld/mysqld.sock option=3 EOF # pear install Console_Getopt # cd /usr/local/src # wget # tar xf freepbx-13.0-latest.tgz # cd freepbx # ./install -n

Restore our production setting into our new container, assuming we’ve copied a backup from production (/var/spool/asterisk/backup/) into the container:

# fwconsole moduleadmin upgradeall
# fwconsole moduleadmin downloadinstall backup
# /var/www/html/admin/modules/backup/bin/restore.php --restore=/home/asterisk/20170127-101341-1485530021- --items=all

Since the host NAT’s for the container, we may want to change the external IP sent out by Asterisk depending on where we deploy:

# for f in /etc/asterisk/*;    do sed -i 's/' $f;    done
# sed -i 's/localnet.*$/localnet=\/24/g' /etc/asterisk/sip_general_additional.conf
# mysql -u root asterisk -e "UPDATE kvstore SET kvstore.val='' WHERE kvstore.key='externip';" -p
# mysql -u root asterisk -e "UPDATE kvstore SET kvstore.val='[{\"net\":\"\",\"mask\":\"24\"}]' WHERE kvstore.key='localnets';" -p

If any modules are listed as “broken”, reinstall them, like:

# fwconsole moduleadmin list
# fwconsole moduleadmin uninstall asterisk-cli callforward cidlookup configedit ivr miscapps miscdests paging parking phonebook ringgroups speeddial
# fwconsole moduleadmin downloadinstall asterisk-cli callforward cidlookup configedit ivr miscapps miscdests paging parking phonebook ringgroups speeddial

Set up log rotation in the container.

# cat << 'EOF' >> /etc/logrotate.conf
/var/log/asterisk/full /var/log/asterisk/*log {
	su asterisk asterisk
	minsize 250k
	maxsize 20M

If the vi in the container misbehaves, add a minimal .vimrc:

root@asterisk:~# cat .vimrc
set nocompatible
set backspace=indent,eol,start