(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:
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 10.0.0.76.
The NAT bridge device is ‘lxcbr0’ with the network 10.100.0.0/24.
The host iptables FORWARD chain accepts traffic to and from lxcbr0
, and the nat
table has a POSTROUTING MASQUERADE rule for 10.100.0.0/24 (both likely set up by lxc-nat
).
See https://paulgorman.org/technical/linux-lxc.txt 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 203.0.113.100 (a placeholder for use in these notes).
We want our new container named “asterisk-debian-$(date +%Y%m%d)” to receive IP 10.100.0.10. Our host NATs for the container, like:
# iptables -t nat -A PREROUTING --dst 10.0.0.76 -p udp --dport 5060 -j DNAT --to 10.100.0.10
# iptables -t nat -A PREROUTING --dst 10.0.0.76 -p tcp --dport 5061 -j DNAT --to 10.100.0.10
# iptables -t nat -A PREROUTING --dst 10.0.0.76 -p udp --dport 10000:20000 -j DNAT --to 10.100.0.10
We may also want to NAT ports to the container’s sshd or httpd.
On the build host:
# lxc-create -n asterisk-debian-$(date +%Y%m%d) -t debian -- -r jessie
# sed -i '/10.100.0.10/d' /etc/lxc/dnsmasq.conf
# echo "dhcp-host=asterisk-debian-$(date +%Y%m%d),10.100.0.10" >> /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 http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-13-current.tar.gz
# tar xf asterisk-13-current.tar.gz
# cd asterisk-13*
# ./configure --with-pjproject-bundled
# make menuselect
Add CORE-SOUNDS-EN-ULAW, CORE-SOUNDS-EN-G722, MOH-OPSOUND-ULAW, MOH-OPSOUND-G722, EXTRA-SOUNDS-EN-ULAW, and EXTRA-SOUNDS-EN-G722.
# 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) Wants=network.target After=network.target
[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] WantedBy=multi-user.target EOF # systemctl daemon-reload
And:
# systemctl enable asterisk
# systemctl start asterisk
# lsof -Pi
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
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-13.0.190.11-1587130262.tgz --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/203.0.113.100/10.0.0.76/g' $f; done
# sed -i 's/localnet.*$/localnet=10.100.0.0\/24/g' /etc/asterisk/sip_general_additional.conf
# mysql -u root asterisk -e "UPDATE kvstore SET kvstore.val='10.0.0.76' WHERE kvstore.key='externip';" -p
# mysql -u root asterisk -e "UPDATE kvstore SET kvstore.val='[{\"net\":\"10.100.0.0\",\"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
missingok
minsize 250k
maxsize 20M
}
EOF
If the vi
in the container misbehaves, add a minimal .vimrc
:
root@asterisk:~# cat .vimrc
set nocompatible
set backspace=indent,eol,start