Introduction
Having your own phone server can do many things for you at home or your small business. Asterisk is a free open-source PBX (Private Branch Exchange) that can manage phone calls with voicemail, email notification, blacklisting/call blocking, video conferencing, instant messaging and more. For the purposes of this article we will be covering phone calls using the SIP protocol.
This guide will help you get a home/small business phone server up and running. As of the time of publishing this guide I have been running Asterisk on Arch Linux for just under 2 years. I would suggest that you use a SIP provider that does not require you to open ports to the internet on your router. I use IXICA for my provider and the enterprise SIP trunks have been excellent.
Asterisk will allow you to do almost anything you can imagine a phone doing and likely a whole lot more. What I will be covering will be the basic settings required to be able to connect 2 or more phones locally, call between those phones, make local/long-distance calls using 7/10/11-digit numbers, have voicemail and receive email when you receive it, transfer phone calls between phones and park calls.
Installing Asterisk on Arch
Let's start by installing Asterisk. Update your system. Assuming you use yaourt as your AUR helper:
$ yaourt -Syua
$ yaourt -S asterisk
We have asterisk installed and need to save a couple of the original configuration files for reference. We will not be using the example for sip.conf or extensions.conf so we will move them instead of copying them.
$ cd /etc/asterisk
$ sudo mv sip.conf sip.conf.orig
$ sudo mv extensions.conf extensions.conf.orig
$ sudo cp features.conf features.conf.orig
$ sudo cp voicemail.conf voicemail.conf.orig
Now, that we have that done, we can move on to setting up the default SIP settings
Create accounts
Open /etc/asterisk/sip.conf in your favorite editor.
$ sudo vim sip.conf
/etc/asterisk/sip.conf
[general]
context=incoming ; The default context for all calls not belonging to another context
allowoverlap=no
udpbindaddr=0.0.0.0 ; IP address range to allow connections from using UDP. 0.0.0.0 allows all or use similar to 192.168.1.0
transport=udp ; Default transport UDP/TCP
srvlookup=yes
qualify=yes ; Re-qualify you SIP connections regularly
That takes care of our default settings. We need to setup the SIP accounts and settings for them. Just like the general section, accounts are specified with [Account-name] as a section header and look similar to this.
[301] ; Account name
secret=12345678 ; Account passphrase
callerid="Shaun Foulkes"<301> ; Caller ID sent by account
mailbox=5064714419@default ; Voicemail account
context=incoming ; Context used for the account
allowoverlap=no
udpbindaddr=0.0.0.0 ; IP range to accept connections from
transport=udp ; Default transport for account
srvlookup=yes
qualify=yes ; Check connection on interval
Contexts will begin to make more sense when we get into our dialplans in extensions.conf.
We have the ability to set account settings that are shared among multiple accounts. We name these in the same way as the accounts, but with one addition on the end. We use [Name-of-shared-settings] (!). The (!) says that this is a grouping and can be used by accounts. To use these settings we specify the account header as such [Account-name] (Name-o-shared-settings). For example:
[local-phone](!)
context=incoming
allowoverlap=no
udpbindaddr=0.0.0.0
transport=udp
srvlookup=yes
qualify=yes[301](local-phone)
secret=12345678
callerid="Shaun Foulkes"<301>
mailbox=5552591223@default[302](local-phone)
secret=87654321
callerid="John Smith"<302>
mailbox=5552591224@default
Let‘s put it all together. Your sip.conf should look similar to this.
[general]
context=incoming ; The default context for all calls not belonging to another context
allowoverlap=no
udpbindaddr=0.0.0.0 ; IP address range to allow connections from using UDP. 0.0.0.0 allows all or use similar to 192.168.1.0
transport=udp ; Default transport UDP/TCP
srvlookup=yes
qualify=yes ; Re-qualify you SIP connections regularly[local-phone](!)
type=friend ; Allow calls out and in
dtmfmode=rfc2833
host=dynamic ; Allows connection from multiplr IPs
canreinvite=no
deny=0.0.0.0/0.0.0.0 ; defauls to deny connection from anywhere
permit=192.168.1.0/255.255.255.0 ; Allows your local subnet to connect. Change this to match you LAN, assuming you put this on your LAN
transport=udp
context=sip-phones
allow=!all,ulaw ; Reject all audio codecs except ulaw[301](local-phone)
secret=12345678
callerid="Shaun Foulkes"<301>
mailbox=5552591223@default[302](local-phone)
secret=87654321
callerid="John Smith"<302>
mailbox=5552591124@default
Check your connection
With that done, we are able to connect our phones. Take a moment and start the asterisk server and connect your phones. For username use the account name eg.301 and for passphrase use the corresponding secret.
$ sudo systemctl start asterisk
Once you have put you credentials into your phones, you will need to check if they‘re connected to Asterisk. We will call up the Asterisk console and issue ‘sip show peers‘ and we should see that they are connected. If you don‘t know what server name to use just issue ‘ip addr‘ from a terminal and connect to the ip address that your server shows you.
$ sudo asterisk -rvvv
hostname*CLI> sip show peers
The output should look similar to this
Name/username Host Dyn Forcerport Comedia ACL Port Status Description
301/301 192.168.1.11 D Auto (No) No A 5062 OK (5 ms)
302/302 192.168.1.11 D Auto (No) No A 5060 OK (6 ms)
2 sip peers [Monitored: 2 online, 0 offline Unmonitored: 0 online, 0 offline]
If your output looks similar to mine, then great! If not, go back and check that your settings are correct in sip.conf and make sure that your phone or soft phone is configured correctly.
Although, we are now connected to the server, we still can‘t make any phone calls. In order to make a phone call, we need to tell Asterisk how to do that. We can accomplish this by programming our functionality into dialplans. Dialplans are written in the extensions.conf file.
Creating dialplans
There are a couple of things I need to explain before we start the dialplan. When a call is initiated they begin in a context that is preset in sip.conf. You can think of each context as a container. A call will stay in its container until the dialplan gives it a path to another context or the call is terminated. Contexts are listed in extensions.conf much in the same way an account is listed in sip.conf. This is [context-name]. In each context, you will layout you intended call behavior in blocks that look like this: (Each call behavior is defined by an application and its options).
[context]
exten => extension,step,application(option1, option2)
exten => same_extension,step,application(option1, option2, option3)
To show a clear example, here is a dialplan for calling from one phone we have connected to the other.
* Tip: always end every context with the application Hangup(). If you don‘t and a function doesn‘t complete or has other errors, a call could continue forever. Putting Hangup() as the last application in every context ensures that if error occur then the call will be terminated not just held on dead air.
[sip-phones]
exten => 301,1,Dial(SIP/301,20,tTkK)
exten => 301,2,Hangup()
What does tTkK stand for in the Dial application?
t - allow the called party to transfer calls
T - allow caller to transfer calls
k - allow called party to park calls
K - allow the caller to park calls
For short examples, like this writing our dialplans in this format is fine. However, if you are writing many contexts and longer functions then you will want to shorten up the way you write them. To help in this I will show another more complex example with a shorthand method of doing dialplans. This example is taken right out of my production server.
exten => 301,1,Set(PHONE=${EXTEN}) ; Set variable PHONE to the extension dialed
same => n,NoOp(Calling extension ${PHONE}) ; Display information on console only for debug
same => n,Set(MAILBOX=${DB(extdid/${EXTEN})}) ; Set the mailbox for the number dialed based on the Asterisk database values I set
same => n,Goto(s,1) ; Path to extension s in the same context
same => n,Hangup() ; Hangup if above failsexten => s,1,NoOp(Calling to ${PHONE}) ; Display extension called in the console for debug
same => n,Dial(SIP/${PHONE},20,tTkK) ; Dial via SIP to the extension equal to PHONE
same => n,GotoIf($[ "${DIALSTATUS}" = "BUSY" ]?onphone) ; If line is busy go to step onphone else next step
same => n,Voicemail(${MAILBOX},u) ; Go to voicemail and give unavailable message
same => n,Hangup() ; Hangup call
same => n(onphone),VoiceMail(${MAILBOX},b) ; special voicemail if line is busy
same => n,Hangup() ; Hangup call
As you can see, I have shortened the format by using ‘same =>‘ to mean ‘exten => 301‘ and ‘n‘ instead of the step number. Basicly same => next_step,application. Step 1 must always be explicitly stated. All subsequent steps may be identified by a the step variable ‘n‘. Because of this and wanting to jump steps from time to time, we can name the variable steps like so. same => n(useful-name),application(). This is useful when using applications like Goto() or GotoIf().
Time to setup our dialplans. We need to put in our general section, then we will make it possible to call between phones.
$ sudo vim extensions.conf
You should be in an empty file. Insert the following
[general]
static=yes ; allow dialplan save from console
writeprotect=no ; This and the above must be set to allow diaplan save in console
clearglobalvars=no ; clear global vars on reload of dialplan
Next, we will create the sip-phones context and dialplan.
[sip-phones]
exten => 301,1,Dial(SIP/301,20,tTkK) ; call extension SIP user 301, next step after 20 seconds
same => n,Hangup()exten => 302,1,Dial(SIP/302,20,tTkK)
same => n,Hangup()
That is all it will take to make calls back and forth from one phone to the other. Try it out. If all went well, carry on to the next step.
Setup outbound routes
While making calls between phones on-site is nice, making calls to the outside world is better. We need some rules for making outbound calls. We will make these lead to an outbound context. It is best practice to have a separate context for inbound, outbound and internal calls. This makes it less likely that an outside caller can make a long distance call from your server. First, I need to explain the patterns
X matches any digit from 0-9
Z matches any digit from 1-9
N matches any digit from 2-9
[0-9] matches the character to any digit 0-9
[a-z] matches the character to any lower case alpha character
[A-Z] matches the character to any upper case alpha character
[1,2,5-7,9] matches the character to 1,2,5,6,7 and 9
Pattern matches start with “_“ at the beginning of the extension. Generally they take a format similar to _NXXNXXXXXX and need to be modified if the caller dials in any other format. For example, the caller may dial using a 1 before the number or they may dial a 7 digit number. In either case we will need to change the dialed number to match our SIP provider‘s requirement. In this case a 11 digit number. I will show an example where each pattern will take in our dialed number into a variable, then transform it to the correct format into another variable. After that we go to the outbound context and send the dialed number to the provider from the final variable. You will also notice that I send a notice to the log. I do this to make it easier to pick out when looking through the log.
One thing to keep in mind when you are doing this section of your dialplan is that you will likely need to send the phone number you are calling in a specific format. For my provider I am required to send the 10 digit phone number for Canada/US calls and more if I wanted to do international calling. To date I have not had a need for international call capability, so I never programmed it in. Thus, why I won‘t be covering it.
To make life easier yet again I will be using variables in my dialplan. Some variables we set ourselves and some are set by the Asterisk server for things like status, caller id and many many more things.
So we have already looked at a use of ${DIALSTATUS} earlier. That being one on the Asterisk provided variables I spoke of earlier. We will see another here in the for of ${EXTEN}. This variable is the “dialed“ number. This is not the same as ${CALLERID(all)}, which we will also see. That one is for the inbound caller id to you phone. If someone was to call you the ${EXTEN} would be your phone number and ${CALLERID(all)} would be the caller‘s name and number.
; -----------------
; Call POTS (Plain Old Telephone System) numbers
; -----------------exten => _1NXXNXXXXXX,1,Log(NOTICE, Dialing out from ${CALLERID(all)} to ${EXTEN} through IXICA Provider) ; This is the pattern used for calls dialed with 11 digits starting with 1
same => n,Set(FINALEXTEN=${EXTEN}) ; Extension already correct for sending
same => n,Goto(outgoing,s,1) ; Go to the context outbound, extension s, step 1
same => n,Hangup() ; Hangup if fail or fallbackexten => _NXXNXXXXXX,1,Log(NOTICE, Dialing out from ${CALLERID(all)} to 1${EXTEN} through IXICA Provider) ; Call POTS numbers through CAN/US 10 digit
same => n,Set(FINALEXTEN=1${EXTEN}) ; Add 1 to the number dialed
same => n,Goto(outgoing,s,1)
same => n,Hangup()exten => _NXXXXXX,1,Log(NOTICE, Dialing out from ${CALLERID(all)} to 1506${EXTEN} through IXICA Provider) ; Call POTS numbers through IXICA 7 digit (I can dial any number in the same area code as a 7 digit number)
same => n,Set(FINALEXTEN=1555${EXTEN}) ; Add 1+area code to the number dialed
same => n,Goto(outgoing,s,1)
same => n,Hangup()exten => _+1NXXNXXXXXX,1,Log(NOTICE, Dialing out from ${CALLERID(all)} to ${EXTEN:1} through IXICA Provider) ; Call POTS numbers through IXICA +1 preceeded 10 digit CAN/US for cell contacts
same => n,Set(FINALEXTEN=${EXTEN:1}) ; Remove the first character dialed (useful for redial of +1 numbers)
same => n,Goto(outgoing,s,1)
same => n,Hangup()exten => _911,1,Log(NOTICE, Dialing out from ${CALLERID(all)} to ${EXTEN} through IXICA Provider) ; Call 911 through IXICA
same => n,Set(FINALEXTEN=1${EXTEN}) ; My provider has funny rules. Final extension the provider expects for 911 is 1911
same => n,Goto(outgoing,s,1)
same => n,Hangup()exten => _411,1,Log(NOTICE, Dialing out from ${CALLERID(all)} to ${EXTEN} through IXICA Provider) ; Call 411 through IXICA
same => n,Set(FINALEXTEN=1${EXTEN}) ; My provider has the same silly rule for 411
same => n,Goto(outgoing,s,1)
same => n,Hangup()
That takes care of setting the outbound number. We need to send it to the outbound context. Again, to save on time and typing, I will be using more variables and introducing the Asterisk database. This built in database will store associations for us between an extension and an external phone number for outbound calls. We will add other things later.
[outgoing]
exten => s,1,Set(EXTDID=${DB(extdid/${CALLERID(num)})}) ; Set variable EXTDID to the value stored in family extdid, key is the extension you dialed from which is the caller id number
same => n,Set(CALLERID(num)=${EXTDID}) ; Set the phone number you say you are calling from
same => n,Log(NOTICE, outbount phone number set to ${CALLERID(num)}) ; Place it in you log
same => n,Dial(SIP/ixica-enterprise-trunk/${FINALEXTEN},60,TK) ; Rote the call to your provider
same => n,Playtones(congestion) ; Play busy signal if line is busy
same => n,Hangup()
Did you notice the ‘Dial(SIP/ixica-enterprise-trunk/‘? Clearly we haven‘t made that account yet. We will need to put your provider‘s information into sip.conf. If you don‘t already have a SIP trunk and settings to use from the provider then you may wish to take advantage of IXICA‘s free trial. Save extensions.conf.
Adding data to the Asterisk database
Let's set some of your Asterisk database entries. For this, we need the Asterisk console. We will set your inbound/outbound extension to phone number associations and phone number to name. We'll use extdid for the family for outbound, inext for inbound and calleridname for the name association.
$ sudo asterisk -rvvv
hostname*CLI> database put extdid 301 5552591223
hostname*CLI> database put extdid 302 5552591224
hostname*CLI> database put inext 15552591223 SIP/301
hostname*CLI> database put inext 15552591224 SIP/302
* if you would like calls to a phone number to ring multiple line then do something like SIP/301&SIP/302
hostname*CLI> database put calleridname 301 “Shaun Foulkes“
hostname*CLI> database put calleridname 302 “John Smith“
hostname*CLI> database show
you will get a result like this
/calleridname/5552591123 : Shaun Foulkes
/calleridname/5552591124 : John Smith
/extdid/301 : 5552591123
/extdid/302 : 5552591124
/inext/15552591123 : SIP/301&SIP/401
/inext/15552591124 : SIP/333
Add your SIP trunk
Go into sip.conf. If you went with IXICA then you can use these settings and substitute your username and passphrase. Add your SIP provider to the file at the end. I broke it up like the other account in case you have multiple user accounts with your provider. An example where you might have this is where you have multiple residential accounts with a single provider. I did this with IXIXCA residential when I set up my service.
[provider-ixica-enterprise](!)
host=sbc1.ixica.com
fromdomain=sbc1.ixica.com
type=friend
context=incoming
insecure=port,invite
trustrpid=yes
sendrpid=yes
directmedia=no
qualify=yes
keepalive=45
nat=force_rport,comedia
dtmfmode=rfc2833
disallow=all
allow=ulaw[ixica-enterprise-trunk](provider-ixica-enterprise)
username=provided_username
secret=super_secret_passphrase
You will need to put the register string into the general section.
[general]
….
register => provided_username:super_secret_passphrase@sbc1.ixica.com
That gets us hooked up to our SIP service provider. We need to modify our internal dialplan to work with our outbound routes. Save your sip.conf and open extensions.conf again.
Improve on-site code
Modify your sip-phones section. Lets remove the 301 and 202 extensions we already created and replace it with this.
[sip-phones]
exten => 301,1,Set(PHONE=${EXTEN}) ; Set variable PHONE to the dialed extension
same => n,NoOp(Calling extension ${PHONE}) ; Display in console for debug
same => n,Set(MAILBOX=${DB(extdid/${EXTEN})}) ; Retreive the mailbox number for called extension
same => n,Goto(s,1)
same => n,Hangup()exten => 302,1,Set(PHONE=${EXTEN})
same => n,NoOp(Calling extension ${PHONE})
same => n,Set(MAILBOX=${DB(extdid/${EXTEN})})
same => n,Goto(s,1)
same => n,Hangup()
exten => s,1,NoOp(Calling to ${PHONE})
same => n,Dial(SIP/${PHONE},20,tTkK) ; Dial the internal extension
same => n,GotoIf($[ "${DIALSTATUS}" = "BUSY" ]?onphone) ; If line busy go to busy voicemail
same => n,Voicemail(${MAILBOX},u) ; otherwaise go to unavailable voicemail
same => n,Hangup() ; Hangup
same => n(onphone),VoiceMail(${MAILBOX},b) ; special voicemail if line is busy
same => n,Hangup()[outbound]
…..
You should be able to make a phone call to an outside number. Give it a try. If you achieved success then move on.
Add an incoming route
Let's set inbound call ability. Still in extensions.conf add this section
[incoming]
exten => 15552591123,1,Log(NOTICE, Incoming call from ${CALLERID(all)} calling to ${EXTEN} through IXICA Provider)
same => n,Set(PHONE=${DB(inext/${EXTEN})})
same => n,Set(MAILBOX=${EXTEN:1})
same => n,Goto(s,1)
same => n,Hangup()exten => 15552591124,1,Log(NOTICE, Incoming call from ${CALLERID(all)} calling to ${EXTEN} through IXICA Provider)
same => n,Set(PHONE=${DB(inext/${EXTEN})})
same => n,Set(MAILBOX=${EXTEN:1})
same => n,Goto(s,1)
same => n,Hangup()exten => s,1,Dial(${PHONE},23,tk)
same => n,GotoIf($[ "${DIALSTATUS}" = "BUSY" ]?onphone)
same => n(vm),Voicemail(${MAILBOX},u)
same => n,Hangup()
same => n(onphone),VoiceMail(${MAILBOX},b) ; special voicemail if line is busy
same => n,Hangup()
Save the file and reload asterisk. Either 'sudo systemctl restart asterisk‘ from the terminal or ‘reload‘ from the Asterisk console. Call yourself. Did it work? If so, move on.
Voicemail
We can call between phones on-site, call outside numbers and receive calls from the outside world. I‘m sure that you have noticed that I already included the voicemail in our dialplans, but we didn‘t configure it yet. Let‘s open voicemail.conf. Then we will scroll down until we get to the default section. Comment out the existing line with a ; and then create your mailbox in the default section (the ; at any point in a line will comment out anything that come after it). The mailbox takes the format of
mailbox => pin,Full Name,email@address.com
So your mailboxes will look similar to:
5552591123 => 1234,Shaun Foulkes,shaun@shaunpc.com
5552591124 => 1234,John Smith,john@example.com
Save that and reload asterisk. Give yourself a call from on-site phone to on-site phone. Don‘t answer it. After 23 seconds you should get sent to voicemail. Great, now we have voicemail, but no way to check it. Let‘s go back to extensions.conf and put a way to do that in. We will put the following into the section [sip-phones]
exten => *99,1,NoOp(Calling mailbox ${CALLERID(num)}) ; Allow all voice mail boxes to be accessed by *99 from
same => n(check),GotoIf($[VM_INFO(${DB(extdid/${CALLERID(num)})},exists)]="1"?thisphone) ; Check if the mailbox exists for the extension being called from, go to thisphone if true
same => n,Playback(enter-phone-number10) ; Asks caller to enter their 10 digit phone number
same => n,Read(BOX,,10,,,15) ; Waits up to 15 seconds for the caller to enter the 10 digit number
same => n,VoiceMailMain(${BOX}@default) ; Access the mailbox entered
same => n,Hangup()
same => n(thisphone),VoiceMailMain(${DB(extdid/${CALLERID(num)})}@default) ; same extension as the mailbox number
same => n,Hangup()
Save the file and reload asterisk. Call *99 and you should get a prompt for you passphrase.
Call parking
When someone calls and you need to get the call to someone, but you know they are not in their office, put the call in the parking lot. When you do this Asterisk will speak a number to you. Then you give that number to the person the call is for and they dial it from any phone in the correct context to dial it. The call will then be connected. Just like a transfer. We need to configure things in features.conf, res_parking.conf and extensions.conf. Open features.conf and uncomment the lines
blindxfer => #1
parkcall => #72
We uncomment blindxfer so that we can do blind transfers. Save features.conf and open res_parking.conf. Scroll down until you find parkext =>. Take note of the extension used, default 700. If you want to use something else you can. If you change it you should change the parpos=> as well to match, default 701-720. Go to parkingtime => and set it to something more reasonable. Default is to park the call for 45 seconds. I prefer 300 seconds to allow time to find the person you want to answer the call. Save the file. To make parking work we need to add one more thing to extensions.conf. Open it and add the following in the sip-phones context.
[sip-phones]
...
...
include => parkedcalls
Take a moment and call yourself. When you are connects hit #72 to park the call. You will hear the line it was parked on. Hang up. Now dial the number that was spoken to you. It will pick-up the call again. To test the transfer just call yourself from another extension and hit #1 then an extension that you want to transfer to. You may need to add another extension to try this.
Conclusion
That‘s it. You have a multi-line phone server with voicemail, call transfer and call park. If you want to have your voicemail delivered to your email then you will need to have something like Postfix or SMTPS installed on the server to handle that. If you want to relay through a third party such as Gmail or Zoho then try my guide here for that.