Linux tips & techniques for developers and system administrators.
The IP phones we are using are made by Aastra, and are great pieces of equipment. When booting up they contact (by default) a TFTP server, which is identified by DHCP option 66.
We needed to have our phones portable, and didn’t want to go through the hassle of setting up an external TFTP server for several reasons, among them security. So I set up an ftp server using VSFTP, and wrote a script which synchronizes the tftp directory with the ftp directory.
The script does the following:
Only run if any file in the tftp directory is newer than the newest file in the ftp directory
Update the aastra.cfg to have the phone use an FTP server instead of a TFTP server
Rsync the tftp directory to the ftp directory
Modify all *.cfg files in the ftp directory:
Change the local IP address with the DNS of the server
Change the HTTP lines which reference port 80 to the configured port
Change the HTTP lines which don’t reference a port at all to use the configured port
Change the permissions on all the files in the ftp directory to read only
You will need to configure the following values at the beginning of the script:
If you are using a non-standard tftp directory or ftp directory, you will need to update those values as well (also at the beginning of the script).
I’ve also attached a copy of the vsftpd.conf file. You will need to create a user that your phones will use to access the FTP server, and add that user to the /etc/vsftpd/user_list file. I would suggest using the following command for security to add your user:
useradd -s /sbin/nologin -b /var/ftp aastrauser
and don’t forget to put a password on the account
vsftpd.conf (1.7 KiB, 942 hits)
syncftp.sh (2.6 KiB, 1,178 hits)
I chose Elastix, partially because it is a a popular distribution, partly because it is easy to install, and partly because it includes additional functionality which we may use in the future. Elastix is actually a complete communications server, including email, fax, VOIP, IM via Jabber, and integration with different CRMs
You can download it from their web site, or from SourceForge. Going to SourceForge has additional files and documentation available, including Elastix Without Tears, an excellent installation & reference guide.
IP phones are plentiful, but we wanted reliable phones which the phone system could use to the fullest. I’ve used several, including Aastra and Grandstream. The best supported IP phones for Asterisk are made by Aastra.
Their line includes:
Any one of these phones are a great choice. We’ve decided to go with the 9143i for most of our desktops because it is relatively inexpensive yet has enough features to satisfy us for the foreseeable future.
One of the great things about the Aastra phones is the support available. There are some script written by Aastra support, although these are officially unsupported there is actually plenty of support available, and the scripts are updated on an as-needed basis. You can get them here:
The install script is called install-aastra-xml.x.gz, and it takes care of installing all dependencies. To install these scripts, use the following set of commands:
gzip -d install-aastra-xml.x.gz
chmod +x install-aastra-xml.x
When complete, the scripts will be installed and ready to use. Be sure to read the documentation supplied (see link above) to get a full understanding of what they do.
The scripts are installed, now run the configuration:
This command creates a proper aastra.cfg in the TFTP directory (/tftpboot) to allow self-configuration. If you need to change how the phones are configured that is all done in the template files /var/www/html/aastra/asterisk/:
Here is the official Aastra XML script 2.0.0 manual.
The saga of replacing a legacy phone system with a complete VOIP solution
The lease was coming to an end on our legacy phone system, and we started looking for an alternative. We considered the following choices:
- Extend the lease for another 3 years, at which time we would own the system
- Replace the phone system with a hosted VOIP solution
- Replace the phone system with an internal VOIP solution
For phone service, we looked at the following:
- Continue with Verizon POTs lines
- Replace POTs lines with the hosted VOIP solutoin
- Replace POTs lines with a VOIP provider
- Get a T1 line for the phone lines
When considering to replace POTs lines, we needed to consider the reliability, cost, and quality of the VOIP providers. We decided to go with two providers, in case one has problems, and we are probably going to keep one POTs line just in case the internet goes down on us.
After doing our due diligence, we decided to go with the third option for each, in other words, we are setting up a VOIP server and have selected two external VOIP providers. While the initial upfront costs are higher, after 10-12 months we will have more than saved money. Going with a hosted solution would have cost us about $450/month, going with an extended lease would have cost us $180/month plus about $400 phone charges/month. The all-VOIP solution will cost us about $2500-$3000 for the initial hardware, and our phone charges will be less than $100/month plus an extra $50/month for the spare POTs line. After running the numbers, it showed that after 9 months we would be ahead in terms of absolute cost using the all-VOIP solution. In actuality, the physical system we built cost about $200 using an Atom 525 with a gig of memory and a decent hard disk, which was about $300 less than anticipated.
Then came the choice on VOIP providers. We considered the cost of the phone service and also investigated their reputation and quality of service. There were several finalists, and our final choice came down to the cost, all other factors being equal. Without going into all the details, we settled on the following two providers:
nexMatrix (www.nexmatrix.com) as our primary VOIP provider
Teliax (www.teliax.com) as our backup VOIP provider.
Finally, the choice of what VOIP system to use. There are several very good Asterisk-based solutions, including:
We decided against sipXecs because of our need to eventually integrate the phone system with SugarCRM
For a more complete list of Asterisk-based solutions, take a look at the following two links:
Having had experience with Trixbox, I first looked at that, but was disappointed at the lack of progress in recent years. I also tried to roll our own Asterisk solution. The roll-your-own, while I was able to build a working system, wasn’t supportable enough; we didn’t want to have to constantly be the ones to download and install updates, etc. Also, doing a roll-your-own means that the underlying OS may not be optimized to the fullest for Asterisk.
The final decision was to go with Elastix, both because the UI was easy to use, and it was FreePBX based. This opened up a large number of add-ons if we ever desired to use them.
For FreePBX & Asterisk 1.6, here are the settings I used to set up the Elastix trunk, with my specific details removed. There is no direct editing of files.
I’ve replaced my details with the following:
secret -> ***password*** username -> ***custid*** Register string -> ***registerString***
Outgoing Settings Trunk Name: nexMatrix-OUT PEER Details:
type=friend host=sip10.nexmatrix.net context=inbound username=***custid***-OUT secret=***password*** allow=all insecure=very canreinvite=no qualify=no
Incoming Settings USER Context: nexMatrix User details
type=friend host=sip10.nexmatrix.net username=***custid***-IN secret=***secret*** allow=all insecure=port,invite canreinvite=no qualify=no context=from-trunk
Registration Register String: ***registerString***
A common task is to set up a mail server. A less common task is to be able to support multiple domains on the same mail server, with the possibility of the same address on different domains.
An easy way to do this is to use Postfix and Dovecot, using MySql as a backend to store the user information, and using PostfixAdmin as a management interface.
The following link does a very nice job of explaining how to do this:
I have used this page as a reference to create a script to almost fully automate this. The script has been tested on CentOS 5.5, and in fact was used to build our new mail server.
Additionally, this script installs Roundcube and Squirrelmail on the server for webmail access, and creates a minimal index.html to grant access to Roundcube & Squirrelmail.
Just do a minimal install, upload the script and execute it. It will take care of disabling SELinux, if required.
install_mailserver.sh (24.9 KiB, 1,507 hits)
SugarCE is an open-source version of the SugarCRM, (CRM meaning Customer Relationship Manager). I needed to install it on a CentOS system, so made the attached script. The script assumes that you are starting with a minimal CentOS 5.5 install, Fedora will most likely work as well.
The SugarCRM site is located: http://www.sugarcrm.com/crm/
and here is the install script:
install_sugarcrm.sh (17.8 KiB, 738 hits)
Zoneminder hasn’t been updated in over a year, and in that time new browsers have been released. One of them, IE 8, has depreciated the use of the <applet> tag, which Zoneminder uses to load Cambozola (a java-based viewer)
The following is a replacement for the applet code. Simple replace the applet code in the file:
around line 415, with the following:
<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" width="<?= $width ?>" height="<?= $height ?>" title="<?= $title ?>"> <PARAM name="code" value="com.charliemouse.cambozola.Viewer"> <PARAM name="archive" value="<?= ZM_PATH_CAMBOZOLA ?>"> <param name="accessories" value="none"/> <param name="url" value="<?= $src ?>"/> > </OBJECT>
I recently had to update about 30 different servers with the identical software. This is an all-too-common occurance for an administrator, and there are many different systems available to do this. However, most of them do too much and are generally non-trivial to set up and manage. I wanted a system which would be easy to install, and easy for a non-administrator to use. Enter PullIt, a simple system which solves these requirements:
pullit.tar.gz (32.5 KiB, 308 hits)
PullIt Software Distribution System
2. Installation Details
4. Parameter Definitions
6. Error Codes
Pullit is a small system which gives administrators the ability to remotely install files on various systems. It has been designed to be simple to understand and simple to operate. Based on the KISS principle, it doesn’t try to do everything. There are many other packages which provide much more extensive services, if you need more than this can provide.
This system does not have any security attached. The code for all packages will be copied to all systems, only the required packages will be installed. What this means is that if you have a malicious user who wants to install a package and they are not supposed to, they will be able to copy the files and install them by hand.
PullIt consists of two parts, pullit.sh and pullitd.sh The first, pullit.sh, is the shell by which the administrator/user queues up a set of file to be distributed. The second, pullitd.sh, is a daemon which is run periodictly by cron.
The basic idea is that there is a master server, on which the users/administrators will place files for distribution. The files will be packaged up into a shar file and placed into a distribution directory.
The clients will have the pullitd.sh script running in a cronjob. The script firsts uses rsync to syncronize it’s local directory of packages with those on the server. This design allows each client to also function as a server, which both relieves the load on the main server in cases where either there are a large number of clients, or if the server is a very low-powered machine. It also allows remote distribution of packages
The system is flexible enough to allow for multiple architectures, and multiple distribution groups.
So for example, you can have a “manager” and “employee” group, and inside each group there could be both 32 bit, 64 bit, and noarch architectures. Packages intended for the manager group will not get installed on the employee group, and vice-versa. Currently a client can only have one group active; this will be modified in the future to allow for multiple groups.
Also, when installing files, there is a configuration option which says that a backup should be kept. When this is set, if the file exists then the system will first createa subdirectory in the destination directory and then MOVE (not copy) the files to it. The reason for the move is in case the file is currently being executed, it will be able to continue to execute without having to worry about the file being overwritten.
When installing a client, the group the client belongs to is specified in the configuration file.
2. Installation Details
On the server, the file pullit.sh will be installed to /usr/local/sbin (or whereever you specify), a configuration directory will be created in /etc, and a configuration file installed in the configuration directory.
On the client, the file pullitd.sh will be installed to /usr/local/sbin, a configuration directory will be created in /etc, and a configuration file installed in the configuration directory. Also, a file will be installed into /etc/cron.d
It is your responsibility to make sure that rsync is working properly on all systems.
To install, unpack the tar file into a directory and run the script:
The install script can optionally use the “dialog” command to have a curses- based installer. If you would like to use the text-based mode even if you have the dialog command available, invoke the installer as follows:
The installer should usually be run as root, however it will allow you to run as a regular user. Obviously, a regular user will not be able to change system files or directories, so if a regular user is installing this then it will be installed local to that user.
The installer has the ability to create an installation script for the clients. I strongly recommend you use this, since the installation script will also create ssh keys on the client and install them on the server. This makes the complete installation process extemely easy. The client installation creates the necessary ssh keys, and also asks for the group that the client is in, and the architecture of the client.
The system runs as a simple shell with a limited number of commands. The system is actually a bash shell script, and does not do any fancy screen manipulation, so you can very easily have this run in a batch mode.
The command to run is:
The valid shell commands are:
|done||[ packagename [groupname]]|
|noarch||(shortcut for “arch noarch”)|
|arch||32 | 64 | noarch (anything will work, as long as all clients use the same)
noarch is special, it means that ALL platforms in the group will install the package
|add||[ file [file]] destinationDirectory|
|del||file [file...] | all|
|commit||all | packagename [group]|
|list||[ files | packages | groups | archtypes ] (defaults to files)|
|runbefore||filename [in directory] [rc expected]|
|runafter||filename [in directory] [rc expected]|
|prune||packagename [packagename...] | all|
|at||[ yyyy-mm-dd [ hh:mm:ss ] ]|
4. Parameter Definitions
|packagename||Name of the package being worked on.|
|groupname||Name of the group the current package is intended for|
|filename||Name/path of the file being installed/deleted|
You can use quotes, either single or double, to enclose a parameter with spaces. Also, you can use a backslash to escape the next character; this will allow you to embed a quote inside a single parameter. All quotes, except for a quoted parameter at the end, must be closed with the same quote which started the quoting.
|start||[ packagename ]||Use this command to start building a package. Specify the name of the package with the command. The packagename needs to obey the rules for directory names. The packagename is optional at this point, but will need to be specified on the “end” command if not entered here.|
|group||groupname||An alternate method of specifying what group the current package will be distributed to. If specified with this command, it will not need to be specified with the “end” command|
|done | end||[ packagename [ groupname ] ]||This command finishes a package. However, the package is NOT released for distribution yet, use the “commit” command for that. The packagename and groupname are optional here, in that if they were specified using the “start” and “group” command you wouldn’t need to specify them here.|
|arch||archtype | noarch||The archicture specifies the destination system. While it would be advisable to use the same arch as the basic OS, there is no technical reason to do so. This allows you to specify any number of archictures. One reason to do so is to use a single server to distribute files to 32 bit, 64 bit, x86 x86_64, arm avr32 blackfin m68k m68knommu microblaze mips powerpc. However, if you specify any architecture types during the server install, only those types will be allowed.|
|noarch||This is a shortcut for “arch noarch”|
|(archtype)||If the archtype is simply typed on a line by itself, and it doesn’t match a command name, then the architecture will be set to the entered archtype. This is similar to the “noarch” command as a shortcut. This relies on the default architectures being specified in the configuration file.|
|add||[ filename [ filename ]…] destinationDirectory||Multiple files can be specified here. This command adds files to the package; the last paramenter is the destination directory on the client computers. The files don’t have to be in the current directory, the full paths will be stripped before building the package.|
|del||filename | all||Delete the specified file from the current package. If “all” is specified, then delete all files from the current package.|
|commit||all | packagename [ groupname ]||Commit a package for distribution. If a groupname is specified, then only commit packages which are ready for the specified group. If “all” is specified, then commit all available packages for distribution.|
|list||[ files | packages | groups | archtypes ]||This will list the following types of information:
files All files in the current package
|runbefore||filename [ inDirectory [ expectedReturncode ] ]||Specify a command or program to run before the files are installed. These commands are run BEFORE any files are renamed for backup. If inDirectory is specified, then the command will be run in the specified directory. If specified, the return code from the command must match the expectedReturncode, otherwise the install will abort. If the directory the command is run in is not important, but you do want to specify the returncode, then use a . as the directory.|
|runafter||filename [ inDirectory [ expectedReturncode ] ]||Specify a command or program to run after the files are installed. These commands are run BEFORE any files are renamed for backup. If inDirectory is specified, then the command will be run in the specified directory. If specified, the return code from the command must match the expectedReturncode, otherwise the install will abort. Note that since the files have been installed and backups made if specified, that an abort at this point could leave your systems in an unexpected state.|
|prune||packagename [packagename...] | all||Prune specified packages from the cache directory, or all packages|
|at||[ yyyy-mm-dd [ hh:mm:ss ] ]||Install the package at or after the specified date/time|
|quit||Both quit and exit will exit the shell.|
6. Error Codes
The following error codes can be returned by the pullit.sh script. These may be useful if you are calling it from a script:
0 All ok
1 Missing configuration file
2 Missing bash_arrays.sh file
3 Unable to create libdir
4 Unable to install sharutils with yum
5 Niether yum nor apt-get detected
6 unable to install sharutils with apt-get
7 Unable to create the cache dir
The following error codes can be returned by the pullitd.sh script:
0 All ok
1 Missing configuration file
2 Unable to create libdir
3 Unable to create the top journaldir
4 Unable to create the cachedir
5 Transfer program missing
6 Unable to create the lower journal directory
7 Not running as specified user
Lets say that you have a number of web servers, all being load-balanced together in a colo facility. You need to update some files in a directory on all the servers. A problem is that some of the servers are always down for maintenance or other problems.
Here is the situation:
|Main HTML directory:||/var/www/html|
|Directory containing files to be updated:||/var/www/html/mydir|
|Files to be updated/added:||index.php .htaccess config.php|
First, copy the files to the master server:
scp index.php .htaccess config.php jbb@master:
Then log in to the master:
Now start the pullit shell:
The shell gives the following prompt:
Enter the following commands, one per line:
start mydir group webserver arch noarch add index.php .htaccess config.php /var/www/html/mydir runbefore "/etc/init.d/httpd stop" runafter "/etc/init.d/httpd start" end commit all quit
Note that because there are spaces in the commands you want to run, you need to surround the command with quotes.
The commands do the following:
Start a package called "mydir"
This package is intended for the group called "webserver"
No architecture, so this will be installed on all servers in the group
add index.php .htaccess config.php /var/www/html/mydir
Add the three files to the package, they will be installed to the /var/www/html/mydir directory
runbefore "/etc/init.d/httpd stop
Stop the webserver before doing the installation
runafter "/etc/init.d/httpd start
|start the webserver after the install is done|
End the package, ready for commit
Commit all packages. At this point, the packages are available for the servers to pull them down and install
exit the pullit shell
A coworker was trying to install Ubuntu 10.10 Maverick Meerkat onto an older laptop. The installer would simply hang at a black screen as soon as the install was started.
This brought to mind the problems people have installing onto different hardware; I’m going to keep this updated with various ideas and suggestions.
Maverick Meerkat on an HP Pavilion zv5000 (zv5380us)
In this case, the solution was to use the alternate install CD and change some of the boot options. After selecting the location, press F6 to get to the option screen. There will be a small menu at the lower right, you want to use the up/down keys to select the following options:
Then press the escape key, and press return to start the installation. If you like, you can change the VGA mode to something different, I tend to use:
The complete install will be done using a text-mode installer.
If you are on a 64 bit Linux system, and need to build a 32 bit executable (for example if you need to install it on another, 32 bit, system), you can build it by passing the following argument to the configure script:
./configure --build=i686-pc-linux-gnu "CFLAGS=-m32" "CXXFLAGS=-m32" "LDFLAGS=-m32"