Geek-Tips

Didactic musings on assorted geekery

Asterisk on AWS Linux

A couple of months ago I decided to move my company’s Asterisk PBX system from one of our physical data-center servers to Amazon’s AWS EC2 Platform. We had been using Trixbox since 2006, but the Community Edition of that product (Trixbox CE) is no longer being developed and is no longer supported. Since I was starting with a fresh installation on AWS, I decided to go with FreePBX which is very similar to Trixbox. The only problem with this idea is that FreePBX, like Trixbox, ships as its own Linux Distribution. I wanted to use Amazon Linux as my distro of choice in the AWS cloud because the OS is optimized for that environment. This meant I needed to install, configure, and in many cases, compile all of the necessary components to make my PBX work. This approach isn’t as “easy” as dropping a distro in place and configuring, but is sure is a lot more fun!

Amazon AWS Services
Amazon AWS Services

Following is a step by step walk-through of my installation process.

Passwords

An installation of this magnitude uses a lot of various software components and systems that require credentials. Be sure to change these passwords to match your internal security requirements:

  • PASSWORD1 – MySQL root password
  • PASSWORD2 – Used for the asterisk database user
  • PASSWORD3 – Used for the FreePBX administrator
  • PASSWORD4 – Used for Flash Operator Panel
  • PASSWORD5 – Used for the Asterisk Recording Interface

Create Virtual Machine

  • Deploy a 64Bit medium instance of Amazon Linux with all of the default settings.
  • Name the instance “FreePBX”
  • Attach an Elastic IP Address
  • Open Ports 80 and 443

Prep the Instance

The first step is to download the certificate from AWS that you will need to SSH to the server. Once that’s in place, establish a SSH session, login as ec2-user and execute the following commands:

sudo su
 yum -y update
 yum -y groupinstall "DNS Name Server"
 yum -y groupinstall "Web Server"
 yum -y groupinstall "Mail Server"
 yum -y groupinstall "MySQL Database"
 yum -y groupinstall "Development Tools"

After completing the installation of the above package groups, we’ll need to install following prerequisites:

yum -y install e2fsprogs-devel keyutils-libs-devel
yum -y install krb5-devel libogg libselinux-devel libsepol-devel libxml2-devel
yum -y install libtiff-devel gmp php-pear php-pear-DB php-gd php-mysql php-pdo
yum -y install kernel-devel ncurses-devel audiofile-devel libogg-devel
yum -y install openssl-devel mysql-devel zlib-devel perl-DateManip sendmail-cf
yum -y install php php-process vsftpd sqlite-devel

Configure Timezone

All Amazon instances are in GMT time by default. To make sure that logs and such reflect the correct times, we should set the correct local timezone. To do so, you first point the correct timezone data file at “/etc/localtime” file, and then edit the “/etc/sysconfig/clock” file to ensure that the correct timezone gets applied the next time the system reboots.

ln -sf /usr/share/zoneinfo/America/Chicago /etc/localtime

Now change following:

vi /etc/sysconfig/clock
  • Change ZONE=“UTC” to ZONE=“Chicago”

Build / Install LAME

LAME is required for some of Asterisk’s audio features. We need to download LAME to a source directory, compile and then install it.

wget http://downloads.sourceforge.net/project/lame/lame/3.98.4/lame-3.98.4.tar.gz
tar zxvf lame-3.98.4.tar.gz
cd lame-3.98.4
./configure
make
make install

Now let’s remove the source data:

cd ..
rm -fr lame-3.98.4
rm -f lame-3.98.4.tar.gz

Build / Install SOX

SOX is required for some of Asterisk’s audio features. We need to download SOX to a source directory, compile and then install it.

wget http://sourceforge.net/projects/sox/files/sox/14.4.1/sox-14.4.1.tar.gz
tar xvzf sox-14.4.1.tar.gz
cd sox-14.4.1
./configure
make
make install

Now let’s remove the source data:

cd ..
rm -fr sox-14.4.1
rm -f sox-14.4.1.tar.gz

Build / Install spandsp

Asterisk needs a fax engine to support the processing of inbound faxes. We could use Digum’s Fax for Asterisk (paid) option or, as we’ll use here, the free spandsp option.

cd /home/ec2-user/asterisk-11.4.0/contrib/thirdparty
wget http://www.soft-switch.org/downloads/spandsp/spandsp-0.0.6pre21.tgz
tar zxvf spandsp-0.0.6pre21.tgz
cd spandsp-0.0.6pre21
./configure
make
make install

Now we need to make sure that the module can be found:

sudo cat >> /etc/ld.so.conf.d/usrlocallib.conf
/usr/local/lib

Ctrl+D to save the file then let’s refresh the library paths:

sudo ldconfig

Notes: spandsp information

Build / Install Asterisk

Let’s grab a copy of Asterisk 11 and extract it to its own source folder:

wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-11-current.tar.gz
tar xvfz asterisk-11-current.tar.gz
cd asterisk-11.4.xx.xx
contrib/scripts/get_mp3_source.sh
./configure CC="gcc -O3" CFLAGS=-O3
make menuconfig

The last command will launch the source configuration manager. The we want to install:

  • Add-Ons
    • app_mysql
    • app_saycountpl
    • cdr_mysql
    • format_mp3
    • res_config_mysql
  • Resource Modules
    • res_fax_spandsp
  • Extra Sound Packages
    • EXTRAS-SOUNDS-EN-GSM

When done, press x to save your selections and exit.

Now let’s compile the source and install:

make
make install
cp /usr/lib/libasteriskssl.so.1 /usr/lib64/

Now let’s remove the source data:

cd ..
rm -fr asterisk-11.2.xx.xx
rm -f asterisk-11-current.tar.gz

Configure PHP Timezone

Now we need to configure our timezone for PHP:

vim /etc/php.ini
  • set date.timezone = “US/Central”

Install FreePBX

Let’s get the latest version of FreePBX and extract it to its own source folder:

wget http://mirror.freepbx.org/freepbx-2.xx.xx.tar.gz
tar xvfz freepbx-2.xx.xx.tar.gz
cd freepbx-2.xx.xx

Let’s start MySQL, create the asterisk databases and run the initial SQL setup scripts:

/etc/init.d/mysqld start
chkconfig mysqld on
mysqladmin create asterisk
mysqladmin create asteriskcdrdb
mysql asterisk < SQL/newinstall.sql
mysql asteriskcdrdb < SQL/cdr_mysql_table.sql

Now let’s start the MySQL command line tool:

mysql

Let’s define the user and password for each of the databases:

GRANT ALL PRIVILEGES ON asteriskcdrdb.* TO asteriskuser@localhost IDENTIFIED BY 'PASSWORD2';
GRANT ALL PRIVILEGES ON asterisk.* TO asteriskuser@localhost IDENTIFIED BY 'PASSWORD2';
flush privileges;
\q

Let’s change the MySQL user to root:

mysqladmin -u root password 'PASSWORD1'

Now we need to create the Asterisk user and set folder permissions:

useradd -c "Asterisk PBX" -d /var/lib/asterisk asterisk
chown -R asterisk:asterisk /var/run/asterisk
chown -R asterisk:asterisk /var/log/asterisk
chown -R asterisk:asterisk /var/lib/php/session/

Now we need to update the Apache configuration file:

vim /etc/httpd/conf/httpd.conf
  • Change User apache and Group apache to User asterisk and Group asterisk
  • Change AllowOverride None to AllowOverride All
  • Change ServerName to servername.domain.com:80

Now we can start Apache:

/etc/init.d/httpd start
chkconfig httpd on

Let’s start Asterisk:

./start_asterisk start

Set Up FTP Server

We installed the vsftp server at the beginning of this process, now we need to configure it.

Create Polycom User

useradd polycom
passwd polycom

Set the password to polycom as well.

Just to be cautious, let’s lock the polycom user down so the account can only be used for FTP:

vim /etc/passwd

Scroll to the end of the file and change:

polycom:x:502:502::/home/polycom:/bin/bash

to

polycom:x:502:502::/home/polycom:/sbin/nologin

Now add polycom to the bottom of the following files:

vim /etc/vsftpd.chroot_list

vim /etc/vsftpd/user_list

The vsftp server restricts users in the user_list file by default, we want to only allow users in this file. Be sure to comment out all users listed in the file except for the polycom user we added previously.

vim /etc/vsftpd/vsftpd.conf

Now add the following line to the bottom of the file:

userlist_deny=NO

Now we need to restart the vsftpd server to read our new configuration:

service vsftpd restart

Configure FreePBX

./install_amp --username=asteriskuser --password=PASSWORD2

The install_amp script will now present us with a series of prompts along with default values, within square brackets, which you can accept by hitting enter.

  • [asteriskuser]
  • [PASSWORD2]
  • [localhost]
  • [admin]
  • [amp111] – Change to PASSWORD3
  • [/var/www/html]
  • [xx.xx.xx.xx] – Set to the assigned Elastic IP Address
  • [extensions]
  • [/var/lib/asterisk/bin]
  • [/usr/local/sbin]

Now we need to change the Asterisk Recording Interface password and turn on user authentication for the web interface by editing the amportal.conf file.

vim /etc/amportal.conf
  • Change the ARI_ADMIN_PASSWORD entry to update the ARI password: ARI_ADMIN_PASSWORD=PASSWORD5
  • Change the AUTHTYPE entry to database to enable authentication: AUTHTYPE=database
  • Save and exit

Finally, let’s make sure FreePBX starts a boot:

echo "/usr/local/sbin/amportal start" >> /etc/rc.local

Install Zend Guard

wget http://downloads.zend.com/guard/5.5.0/ZendGuardLoader-php-5.3-linux-glibc23-x86_64.tar.gz
tar -zxf ZendGuardLoader-php-5.3-linux-glibc23-x86_64.tar.gz
cp ZendGuardLoader-php-5.3-linux-glibc23-x86_64/php-5.3.x/ZendGuardLoader.so /usr/lib64/php/modules

Now we need to tell PHP to load the module:

vim /etc/php.ini
  • Add zend_extension=/usr/lib64/php/modules/ZendGuardLoader.so anywhere in the file

Now restart apache:

/etc/init.d/httpd restart

Now let’s cleanup:

rm -f ZendGuardLoader-php-5.3-linux-glibc23-x86_64.tar.gz
rm -fr ZendGuardLoader-php-5.3-linux-glibc23-x86_64/

Install icrond

wget http://inotify.aiken.cz/download/incron/incron-0.5.10.zip
unzip incron-0.5.10.zip
cd incron-0.5.10
make
make install
ln -s /usr/local/sbin/incrond /usr/sbin/incrond

Now let’s cleanup:

rm -f incron-0.5.10.zip
rm -fr incron-0.5.10

FreePBX Configuration

Now that we have the base system installed, let’s load up the FreePBX management console by navigating to your server’s IP address.

Now we need to navigate to Admin → Module Admin and perform the following:

  • Enable the FreePBX Framework
  • Install the Conferences Application
  • Install the System Admin Module
  • Install Asterisk Info Module
  • Install PHP Info Module
  • Install IVR Module
  • Install Fax Configuration Module
  • Install Follow Me Module
  • Install Ring Groups Module
  • Install Blacklist Module
  • Install CallerID Lookup Module
  • Asterisk SIP Settings Module

Load Asterisk SIP and IAX2 Modules

asterisk -r
module load chan_iax2.so
module load chan_sip.so
quit

Configure FreePBX Settings

Navigate to the Advanced Settings menu item and set:

  • Browser Stats = False
  • SIP nat = yes

Navigate to the Asterisk SIP Settings menu item and set:

  • NAT = yes
  • External IP = Static IP
  • AUTO Configure

Final Configuration

At this point you have a functional Asterisk and FreePBX installation running on AWS. All that’s left to do is to configure the PBX to meet your specific needs. Following is a sample of the items you’ll need to set up:

  • Crete Extensions
  • Set up Trunks
  • Set up Outbound Routes
  • Set up Inbound Routes
  • Setup phone config files
  • Create Ring Groups
  • Create Conferences
  • Create IVR
  • Configure Follow-Me

Until next time – GEEK OUT!

~GT~

How To Properly Test Batteries

Testing batteries seems like an overly simple topic for a blog post, but unless you have a good quality battery tester, then chances are you’re not testing your batteries correctly.

When testing with a multimeter, most people will simply take an open circuit voltage measurement from their cell. The problem with this approach is that simply measuring the voltage directly from the battery only tells us what the voltage of the UNLOADED cell is. Let’s suppose that we were to test two AAA batteries. Let’s say our voltage test shows 1.45V for each cell. Now we connect each battery to a load, say a small motor, and we notice that one spins nicely, and the other doesn’t spin at all, or perhaps spins slowly and stalls.

How could this be? The answer is CAPACITY. The typical Alkaline AAA battery has a capacity of between 860 – 1200 mAh. Let’s assume our cells are at 1000 mAh when new. That means that one battery can support a load of 1000 mA for 1 hour or 500 mA for 2 hours. This means that if you were running a toy that drew about 200 mA, it would run for 1000mAh/200mA or 5 hours.

To properly test our batteries while considering capacity, we need a multimeter and a known load. I like to use a 100Ω resistor and a couple of alligator clips.

Resistor w/Clips
Resistor w/Clips

Now we can test our cells again. If the results are between 1.3V – 1.5V the cell is good. If the results are much lower, then chances are the cell won’t do well in a typical application (i.e. remote or toy), and the cell may not work at all in a high draw application such as a smoke detector.

Testing w/Load
Testing w/Load

It’s worth noting that NiCd/NiMh batteries produce lower voltage so be sure to take that into account when testing.

Until next time – GEEK OUT!

~GT~

Detecting Failed AD2USB to Raspberry Pi Connections

One of my ongoing home automation frustrations is the interface between my Ademco Alarm Panel and the Raspberry Pi I use to monitor the panel’s bus traffic. The problem that I have is a termination of the USB connection between the AD2USB (AlarmDecoder) that taps into the Ademco panel and the Pi itself. This always happens during a lightning storm and seems to be the USB port on the Raspberry Pi shutting down in response to voltage fluctuations coming from the AD2USB. Rebooting the Raspberry fixes the issue, but it usually takes a couple of days before I realize I’m not getting notifications from my HA system at which point I take steps to reset the Raspberry Pi.

I think I can resolve this issue once and for all by putting a USB Isolator between the AD2USB and the Raspberry Pi. To test this theory, I’ve ordered a unit from Circuits@Home which I hope to have in place within a few days.

USB Isolator
USB Isolator

I expect the isolator will greatly improve the reliability of the communications between the AD2USB and my HA system, but I also wanted to implement a monitoring system to notify me if messages stop coming from the AD2USB. Following is a simple python script that runs on the Raspberry Pi. If no messages are received within a five minute timeframe then a variable is set on my Indigo server which I then use to notify me of the failure.

import time
from alarmdecoder import AlarmDecoder
from alarmdecoder.devices import SocketDevice
import urllib2
import logging

# Configuration values
logging.basicConfig(filename='ad2socket.log',format='%(asctime)s %(message)s',level=logging.DEBUG)
HOSTNAME = '127.0.0.1'
PORT = 10000
FAIL_URL = "http://indigo:8176/variables/ser2sockMon?_method=put&value=FAIL"
PASS_URL = "http://indigo:8176/variables/ser2sockMon?_method=put&value=PASS"
ALARM_COUNTER = 0

def main():
    """
    monitor socket communications if they stop sending data send an alert.
    """
    try:
        # Retrieve an AD2 device that has been exposed with ser2sock on localhost:10000.
        device = AlarmDecoder(SocketDevice(interface=(HOSTNAME, PORT)))

        # Set up an event handler and open the device
        device.on_message += handle_message
        with device.open():
            global ALARM_COUNTER
            while True:
                time.sleep(1)
                ALARM_COUNTER+=1;
                if ALARM_COUNTER > 300:
                    logging.info('FAIL')
                    ALARM_COUNTER=0
                    try:
                        response = urllib2.urlopen(FAIL_URL)
                    except Exception, ex:
                        logging.warning('Exception opening url ', ex)

    except Exception, ex:
        logging.warning('Exception: ', ex)

def handle_message(sender, message):
    """
    reset our alarm counter on every message
    """
    global ALARM_COUNTER

    try:
        response = urllib2.urlopen(PASS_URL)
    except Exception, ex:
        logging.warning('Exception opening url ', ex)
    ALARM_COUNTER=0

if __name__ == '__main__':
    main()

One helpful note to anyone wanting to mimic what I’ve done here is that there can be extended periods of time with little to no traffic on the alarm panel bus. In order to force traffic, I’ve set up a job on my Indigo server to send a panel message consisting of a single pound symbol (#) every five minutes. This always results in an updated alarm-state message being sent across the bus.

Until next time – GEEK OUT!

~GT~