Basic Asterisk Configuration ============================================================================ March 2016 (Note: much of the following notes show the old chan_sip driver. The new pjsip is covered in the final section.) In Asterisk, there's no distinction between a station phone and a trunk --- everything is a **Channel**. The channels are defined in `/etc/asterisk/sip.conf`. All channels get passed through the **Dialplan**. The dialplan is defined in `/etc/asterisk/extensions.conf`. An Asterisk **extension** isn't like a number on a traditional PBX --- it's more like a named group of instructions or a function/script name. An extension might ring a phone, but it might kick of a series of other actions instead. Find Asterisk config files in `/etc/asterisk/`. Find Asterisk data files (including music on hold) in `/var/lib/asterisk/` or `/usr/share/asterisk/`. The file location is specified in `/etc/asterisk/asterisk.conf`. Voicemail and call recordings are stored in `/var/spool/asterisk/`. Asterisk logs to `/var/log/asterisk/`. The documentation, if installed, can be found either in `/var/lib/asterisk/documentation/` or `/usr/share/doc/asterisk-doc/`. The documentation contains well-commented sample config files. Connect to a running Asterisk daemon: % asterisk -r % asterisk -rTvv sip.conf can be reloaded from the Asterisk console CLI> module reload chan_sip.so The `/etc/asterisk/modules.conf` file controls which modules get loaded. By default, this contains the line 'autoload=yes', which loads all modules found in `/usr/lib/asterisk/modules/`. We may want to save resources by preventing some modules from loading, like 'no => foo.so'. Recommendation: name phones by their MAC address, not the person sitting at the desk. (Not sure about this one.) Dialplan ---------------------------------------------------------------------------- The four concepts of a dialplan: - Contexts: - syntax: a section starting with a name in square brackets, like "[local]" - act as namespaces/scopes - the [general] and [globals] contexts are special - The context defined for a channel (in sip.conf) defines _where it enters the dialplan_. - Since a context limits scope, it can be used to restrict features (e.g. allow long distance calling only in some contexts). - One context can be included in another: `include => myContext` - Extensions - syntax: an extension starts like "exten => " `exten => name,priority,application()` - not just (sometimes not at all) a numeric ID tied to a phone - might triggered by an incoming call or digits dialed on a channel - really a script/function/series of steps, with each step containing an application - Each step in an extension has three parts: - name/number of the extension - priority (i.e. then number of this step in the extension) - the application/command executed by the step - Priorities - the order number of each step of an extension - numbered (and executed) sequentially - The special "n" priority takes the number of the previous priority and increments it. (But an extension must at least always have a step "1", even if the rest are "n".) - Priorities can be labeled, which is handy when using the "n" priority: exten => 123,n(myPriorityLabel),app() - Applications - Performs an action on the channel (e.g. play a sound, dial another channel, hangup, etc.) - Common applications: Answer(), Playback(), Hangup(), Goto(), Background(), WaitExten() Playback(/home/foo/sounds/ding) (Plays 'ding.wav'.) Goto(myContext,myExtension,myPriority) The "same =>" shorthand operator: This: ``` exten => 123,1,Answer() exten => 123,n,doStuff() exten => 123,n,doMore() exten => 123,n,Hangup() ``` can be abbreviated as: ``` exten => 123,1,Answer() same => n,doStuff() same => n,doMore() same => n,Hangup() ``` (Indentation is optional.) Variables can be used: ``` PI=3.141592 Dial(${PI}) ``` By convention globals are UPPERCASE, channel variables are camelCase. System environment variables can be accessed like: ${ENV(foo)} Asterisk sets some variables: ``` ${EXTEN} Current extension ${EXTEN:1} Extension omitting first numeral (subscript one to end of number) ${EXTEN:-4:4} Start four digits from end, and return four digits (i.e. last 4 of number) ``` Pattern matching. Patterns start with an underscore. ``` X matches 0-9 Z matches 1-9 N matches 2-9 [372] matches three or seven or two . matches one or more character ! matches zero or more characters Match a ten-digit phone number: _NXXNXXXXXX Match an international number (from North America): _011. ``` https://wiki.asterisk.org/wiki/display/AST/Pattern+Matching > Asterisk treats a period or exclamation mark as the end of a pattern. See: https://wiki.asterisk.org/wiki/display/AST/Asterisk+Command+Reference Asterisk CLI ---------------------------------------------------------------------------- (Remember tab completion!) ``` CLI> module reload chan_sip.so CLI> dialplan reload CLI> sip show peers CLI> sip show peer twilio CLI> sip show users CLI> core show channels CLI> core show channels verbose CLI> core show channel PJSIP/111-00000024 CLI> channel request hangup PJSIP/111-00000024 CLI> module show CLI> module reload app_voicemail.so CLI> voicemail show users CLI> module reload features CLI> core restart now CLI> core restart gracefully CLI> core show uptime CLI> logger mute CLI> logger set level NOTICE off CLI> core show hints ``` The sample configs below assume a branch office with four phones. All phones ring when a call comes in from outside, and everybody shares a common voicemail box. All phones are SIP phones, and outside connectivity comes from a SIP trunk provider (Twilio). Debugging: ``` CLI> core set verbose 4 CLI> core set debug 4 CLI> sip set debug on ``` (If using pjsip: 'pjsip set logger on'.) Also, check listening ports with: # netstat -panu Furthermore, we can pass commands to asterisk from the shell, like: ``` # asterisk -x 'pjsip show endpoints' | grep 130 # watch "asterisk -x 'core show channels'" ``` Restarting: - `core restart now` restarts the Asterisk service immediately, ending any calls in progress. - `core restart gracefully` prevents new calls from starting up in Asterisk, but allows calls in progress to continue. When all the calls have finished, Asterisk restarts. - `core restart when convenient` waits until Asterisk has no calls in progress, then it restarts the service. It does not prevent new calls from entering the system. `/etc/asterisk/sip.conf` ---------------------------------------------------------------------------- ``` ; /etc/asterisk/sip.conf ; See /etc/asterisk/sip.conf.dist for helpful comments. [general] context=unauthenticated allowguest=no udpbindaddr=0.0.0.0 tcpenable=no tcpbindaddr=0.0.0.0 transport=udp srvlookup=no language=en nat=force_rport,comedia localnet=10.0.0.0/255.255.255.0 externaddr=nn.nnn.nn.nnn [codecs](!) disallow=all allow=g722,ulaw [twilio](!) type=peer context=incoming username=AsteriskUser secret=xxxxxxxxxxxxxxxxxx insecure=port,invite dtmfmode=auto host=foo.pstn.us1.twilio.com [phone](!,codecs) type=friend context=local host=dynamic dtmfmode=auto rtp_symmetric=yes rewrite_contact=yes aggregate_mwi=yes directmedia=nonat [101](phone) description=101 Polycom SoundPoint IP 335 secret=5Q0-#5th mailbox=100@local [102](phone) description=102 Yealink T21 E2 secret=a137$a9tY mailbox=100@local [103](phone) description=102 Yealink T21 E2 secret=a137$a9tY mailbox=100@local [103](phone) description=102 Yealink T21 E2 secret=a137$a9tY mailbox=100@local ``` `/etc/asterisk/extensions.config` ---------------------------------------------------------------------------- ``` ; /etc/asterisk/extensions.config ; See /etc/asterisk/extenstions.conf.dist for helpful comments. [general] static=yes writeprotect=no clearglobalvars=no [globals] MY_AREA_CODE=555 MY_NUMBER=15555555555 RING_TIME=25 [emergency] exten => 911,1,Verbose(1,Call initiated to 911!) same => n,Dial(SIP/911) [local] include => emergency include => parkedcalls exten => welcome,1,Answer() same => n,Playback(enter-ext-of-person) same => n,WaitExten() exten => 101,1,Dial(SIP/101,,tT) exten => 102,1,Dial(SIP/102,,tT) exten => 103,1,Dial(SIP/103,,tT) exten => 104,1,Dial(SIP/104,,tT) ; *97 is arbitrary. We can set the "voicemail" button key mapping on the phones. exten => *97,1,VoiceMailMain(100@local,s) exten => 199,1,Answer() same => n,Playback(hello-world) same => n,Hangup() ; Block toll numbers exten => _900XXXXXXX,1,Hangup() exten => _1900XXXXXXX,1,Hangup() exten => _NXX976XXXX,1,Hangup() exten => _1NXX976XXXX,1,Hangup() ; Block international exten => _011.,1,Hangup() exten => _1NXXNXXXXXX,1,Set(CALLERID(all)="+${MY_NUMBER}") same => n,Dial(SIP/+${EXTEN}@twilio) exten => _NXXNXXXXXX,1,Set(CALLERID(all)="+${MY_NUMBER}") same => n,Dial(SIP/+1${EXTEN}@twilio) exten => _NXXXXXX,1,Set(CALLERID(all)="+${MY_NUMBER}") same => n,Dial(SIP/+1${MY_AREA_CODE}${EXTEN}@twilio) ; Handle invalid entries: exten => i,1,Playback(pbx-invalid) same => n,Goto(local,welcome,1) ; Handle time-outs exten => t,1,Playback(vm-goodbye) same => n,Hangup() [incoming] exten => welcome,1,Answer() same => n,Background(/usr/share/asterisk/sounds/extra/enter-ext-of-person) same => n,WaitExten(8) same => n,Dial(allphones) exten => _+X.,1,Goto(incoming,welcome,1) exten => allphones,1,Dial(SIP/101&SIP/102&SIP/103&SIP/104,${RING_TIME},,tT) same => n,VoiceMail(100@local,u) exten => 101,1,Dial(SIP/101,,tT) exten => 102,1,Dial(SIP/102,,tT) exten => 103,1,Dial(SIP/103,,tT) exten => 104,1,Dial(SIP/104,,tT) ; Handle invalid entries exten => i,1,Playback(pbx-invalid) same => n,Goto(incoming,welcome,1) ; Handle time-outs exten => t,1,Playback(vm-goodbye) same => n,Hangup() ``` `/etc/asterisk/voicemail.conf` ---------------------------------------------------------------------------- ``` ; /etc/asterisk/voicemail.conf ; See /etc/asterisk/voicemail.conf.dist for detailed comments [general] format=wav49|gsm|wav serveremail=asterisk attach=no maxmsg=100 maxsecs=300 minsecs=1 maxgreet=120 skipms=3000 maxsilence=7 silencethreshold=128 maxlogins=2 charset=UTF-8 tz=eastern locale=en_US.utf8 callback=fromvm [zonemessages] eastern=America/New_York|'vm-received' Q 'digits/at' IMp central=America/Chicago|'vm-received' Q 'digits/at' IMp central24=America/Chicago|'vm-received' q 'digits/at' H N 'hours' military=Zulu|'vm-received' q 'digits/at' H N 'hours' 'phonetic/z_p' european=Europe/Copenhagen|'vm-received' a d b 'digits/at' HM [local] 100 => 9931,My Mailbox,voicemail@example.com ## /etc/askterisk/features.conf ## ; /etc/askterisk/features.conf ; See /etc/askterisk/features.conf for helpful comments [general] courtesytone = beep parkext => 700 parkpos => 701-750 context => parkedcalls parkingtime => 90 ``` PJSIP ---------------------------------------------------------------------------- PJSIP is the channel driver for asterisk that replaces the older chan_sip driver. Its config and concepts are slightly different. The file 'sip.conf' is replaced by 'pjsip.conf'. Unlike chan_sip, where everything is a channel, pjsip has a number of different conceptual objects. **Endpoint** specifies core SIP options, and can link to Auth, AoR, and Transport sections. An endpoint requires at least one linked AoR section. Example: ``` [201] type=endpoint context=default disallow=all allow=ulaw transport=simpletrans auth=auth201 aors=201 ``` **AoR** Address of Record links a Contact to an Endpoint. AoR objects can also set associations with mailboxes. Example: ``` [201] type=aor max_contacts=1 ``` **Contact** holds info about inbound registrations, and aliases SIP URI's. May be associated with an individual SIP user agent. Although they can be created manually, a contact is automatically created upon registration to an AoR. Example of manual contact in an AoR section: ``` [202] type=aor contact=sip:202@192.168.0.55:5060 ``` **Registration** sets up outbound registration with another system (e.g. a local peer or provider's trunk). Like an endpoint, a registration can also link to transport or auth sections. Example: ``` [mytrunk] type=registration transport=simpletrans outbound_auth=mytrunk server_uri=sip:myaccountname@203.0.113.200:5060 client_uri=sip:myaccountname@192.0.2.1:5060 retry_interval=60 ``` **Transport** transport layer options, like tcp, udp, websockets, tls. Mulitple endpoints can share the same transport. Example: ``` [simpletrans] type=transport protocol=udp bind=0.0.0.0 ``` **Auth** holds inbound or outbound authentication options and credentials. Example ``` [auth201] type=auth auth_type=userpass password=201 username=201 ``` **Identify** controls how we identify from which endpoint a packet originates (by IP or by user). If we don't define an Identify section, user identity is based on the packet's SIP "From" header. Example: ``` [201] type=identify endpoint=201 match=203.0.113.200 ``` **Domain_Alias** specifies an alias for a domain. Consulted if a session's domain doesn't match an AoR. (Not linked to other sections.) **ACL** controls all inbound SIP. Can be defined in the ACL section, or in the acl.conf file. (Not linked to other sections.) - https://wiki.asterisk.org/wiki/display/AST/PJSIP+Configuration+Sections+and+Relationships - https://wiki.asterisk.org/wiki/display/AST/Migrating+from+chan_sip+to+res_pjsip In our dialplan, we do: exten => _2XX,1,Dial(PJSIP/${EXTEN}) instead of: exten => _2XX,1,Dial(SIP/${EXTEN}) Some of the CLI commands differ with pjsip. For example: CLI> pjsip show endpoints instead of: CLI> sip show peers http://lists.digium.com/pipermail/asterisk-dev/2016-March/075422.html > The current Asterisk 13 and master git branches have a new feature that will be included in 13.8.0: The ability to compile and run Asterisk with a bundled version of pjproject > All you have to do is add the "--with-pjproject-bundled" option to your ./configure command line and remove any other "--with-pjproject" option you may have specified. Troubleshooting ---------------------------------------------------------------------------- ``` CLI> core show channels CLI> channel request hangup all ``` ``` $ sudo watch "asterisk -x 'core show channels'" $ sudo watch "asterisk -x 'core show channels verbose'" $ sudo asterisk -rx 'core show channels concise' $ sudo asterisk -rx 'core show channel PJSIP/xx_trunk-00000b8d' ``` RTCP may gather some call quality stats: $ sudo asterisk -rx 'pjsip show channelstats' Programming and Automation ---------------------------------------------------------------------------- ``` CLI> channel originate PJSIP/126 application Playback hello-world exten => 666,1,NoOp(-------- Voice Changer --------) same => n,Answer(1) same => n,Set(pranker=${CALLERID(all)}) same => n,Set(PITCH_SHIFT(both)=lower) same => n,Read(prankee,enter-ext-of-person, 4) same => n,Log(NOTICE, ${pranker} pranked ${prankee} (voice change)) same => n,Set(CALLERID(all)="April Furst" <667>) same => n,Dial(PJSIP/${prankee:0:3}, 20) same => n,Voicemail(${prankee:0:3}) same => n,Hangup() exten => 664,1,NoOp(-------- Mysterious Numbers Station --------) same => n,Answer() same => n,Set(PITCH_SHIFT(tx)=lower) same => n,Set(i=0) same => n(while_start),While($[${i} < 64]) same => n,Playback(silence/1) same => n,GotoIf($[${RAND(0,10)} < 8]?:letter) same => n,SayDigits(${RAND(0,9)}) same => n,Goto(while_end) same => n(letter),SayPhonetic(${SHELL(echo ${RAND(0,6)} | tr 0-6 A-F)}) same => n(while_end),Set(i=$[${i} + 1]) same => n,EndWhile same => n,Playback(activated) same => n,Hangup() ``` One thing to note is that once we call the Dial() function, execution of the dialplan doesn't continue until the function returns (i.e. one of the parties hangs up). If we want to do stuff during the call, use a macro with the "M()" option to Dial(): ``` exten => 699,1,NoOp(-------- Test Dial() macros --------) same => n,Dial(PJSIP/+12485552222@my_trunk,20,M(mystery-call)) [macro-mystery-call] exten => s,1,Wait(5) same => n,SayPhonetic(MYSTERY) same => n,Hangup() ``` If we're dialing a local extension, do something like this instead: ``` exten => 699,1,NoOp(-------- Test Dial() macros --------) same => n,Dial(Local/123@my_context,20,M(mystery-call)) ``` Debugging SIP ---------------------------------------------------------------------------- The signaling for a call between a SIP trunk and Asterisk server generally looks something like this: ``` A to B: INVITE B to A: 100 Trying B to A: 180 Ringing B to A: 180 Ringing B to A: 200 OK A to B: ACK ...(RTP media packets flow but no SIP packets, even in a several-minute conversation)... B to A: BYE A to B: 200 OK ``` The BYE packet often provides a Reason header, which can be helpful. Additional (but similar) exchanges occur between the Asterisk server and phones. A packet capture can help diagnose problems: # tcpdump -i eth0 'host asterisk.example.com and port 5060' -vv -w 20170316-serverA-serverB-sip-port-5060.pcap Call Parking ---------------------------------------------------------------------------- CLI> parking show default A Note About DNS and SIP ---------------------------------------------------------------------------- If our DNS server supports NAPTR records (Amazon Route 53, Windows 2008 R2+ DNS, and NSD all do), it's a good way to communicate server redundancy information to phones. Misc ---------------------------------------------------------------------------- Asterisk keeps a database of running configuration values. Access it with `show database`. ``` ~$ sudo asterisk -x 'database show' | grep 'concurrency_limit' /AMPUSER/100/concurrency_limit : 0 /AMPUSER/101/concurrency_limit : 0 /AMPUSER/103/concurrency_limit : 0 … ``` Also, `config list`: ``` ~$ sudo asterisk -x 'config list' | grep 'core' core /etc/asterisk/asterisk.conf core /etc/asterisk/cdr.conf core /etc/asterisk/cel.conf … ``` Links ---------------------------------------------------------------------------- - https://wiki.asterisk.org/wiki/display/AST/Configuring+res_pjsip - http://www.rjsystems.nl/en/2100-asterisk.php - http://www.voip-info.org/wiki/view/Asterisk+config+sip.conf - http://doxygen.asterisk.org/trunk/Config_sip.html - http://www.asteriskdocs.org/en/3rd_Edition/asterisk-book-html-chunk/Voicemail_id292544.html - https://wiki.asterisk.org/wiki/display/AST/Asterisk+Command+Reference - https://wiki.asterisk.org/wiki/display/AST/Asterisk+13+Command+Reference Asterisk: The Definitive Guide from O'Reilly is _really_ good. Buy it if you're running Asterisk.