PJSIP is the modern SIP channel driver for Asterisk, replacing the legacy chan_sip. This guide explains every PJSIP object type with working pjsip.conf examples, then covers the questions that come up once the basics work: what pjsip reload actually reloads, NAT transport options, contact limits, WebRTC and moving off chan_sip.
Unlike the legacy chan_sip which used a single configuration block per peer, PJSIP uses a modular design with multiple object types that work together. This can seem complex at first, but it provides much more flexibility and clarity.
Everything below applies to Asterisk 18 and 20 LTS, 22 LTS, and the 21 and 23 standard releases. chan_sip was removed outright in Asterisk 21, so on current versions PJSIP is the only SIP channel driver (see migrating from chan_sip below).
PJSIP uses six main object types:
Transport
Defines how SIP messages are sent (UDP, TCP, TLS, WebSocket)
Endpoint
Represents a SIP device or trunk - the core configuration object
AOR
Address of Record - where a device can be reached
Auth
Authentication credentials (username/password)
Identify
Matches inbound traffic to an endpoint by IP
Registration
Registers Asterisk to an external SIP server
Transports
Transports define the network protocol and port for SIP communication. You need at least one, and most systems define UDP and optionally TLS:
pjsip.conf - Transports
; UDP transport (standard SIP)
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0:5060
; NAT settings - set to your public IP
external_media_address=YOUR_PUBLIC_IP
external_signaling_address=YOUR_PUBLIC_IP
local_net=10.0.0.0/8
local_net=172.16.0.0/12
local_net=192.168.0.0/16
; TLS transport (encrypted SIP)
[transport-tls]
type=transport
protocol=tls
bind=0.0.0.0:5061
cert_file=/etc/asterisk/keys/asterisk.crt
priv_key_file=/etc/asterisk/keys/asterisk.key
method=tlsv1_2
Transport options reference
The NAT-related transport options are the ones people search the documentation for most, because getting one of them wrong produces registrations that work and audio that does not. What each one does:
Option
What it controls
Typical value
bind
Local IP and port to listen on. 0.0.0.0 means every IPv4 address; [::] adds IPv6.
0.0.0.0:5060
external_signaling_address
Public IP written into the Via and Contact headers when the far end is outside local_net. Fixes registrations and INVITEs that carry a private address.
your public IP or a hostname
external_signaling_port
Public port to advertise when your router forwards a different external port to 5060. Defaults to the bind port, so it is only needed with port translation.
5060 (omit) or the forwarded port
external_media_address
Public IP written into the SDP c= line so the far end sends RTP to your public address instead of your LAN address. Missing this is the classic cause of one-way audio.
same as signaling address
local_net
Networks treated as local. Destinations inside these ranges keep the real private address and no rewriting happens. Repeat the line for each subnet.
RFC 1918 ranges you actually use
allow_reload
Lets pjsip reload re-create this transport. Off by default because re-creating a TCP, TLS or WSS transport drops its live connections.
no (default)
symmetric_transport
Send responses and in-dialog requests over the transport the request arrived on. Useful when several transports share an address family.
yes on multi-transport systems
tos / cos
DSCP and 802.1p marking for SIP signalling. RTP marking is set per endpoint with tos_audio and cos_audio.
tos=cs3, cos=3
The two external addresses are independent on purpose: signalling can be proxied while media goes direct, so Asterisk does not assume they match. In a normal single-NAT office set both to the same public IP, list every internal subnet in local_net, and forward UDP 5060 plus the RTP range (10000-20000 by default) from the router. If you set external_signaling_address and forget external_media_address, phones register and ring but calls have audio in one direction only. Our one-way audio troubleshooting guide walks through diagnosing that from a packet capture.
If your public IP changes (a DHCP business cable line, for example) put a dynamic DNS hostname in the two external address options; Asterisk resolves it at load time, so pair that with a periodic pjsip reload and allow_reload=yes.
Endpoints
Endpoints are the central PJSIP object. Every SIP phone, softphone, or trunk is an endpoint. They reference other objects (AOR, auth) and define media settings:
context - The dialplan context for calls from this endpoint
disallow/allow - Codec negotiation (always disallow=all first, then allow specific codecs)
direct_media=no - Routes media through Asterisk (required for recording, and for NAT)
rtp_symmetric=yes - Send RTP to the same address/port from which it was received (NAT fix)
force_rport=yes - Force use of the port from the received packet (NAT fix)
rewrite_contact=yes - Rewrite the Contact header with the received address (NAT fix)
Endpoint options you will reach for next
from_user / from_domain - Override the From header on outbound calls. Trunk providers that validate the From domain need from_domain=sip.ipcomms.net; on IPComms it is recommended but not required.
send_pai / send_rpid / trust_id_inbound - Send P-Asserted-Identity or Remote-Party-ID for caller ID on trunks, and trust the caller ID the trunk sends you.
dtmf_mode - rfc4733 (out-of-band, the default and what carriers expect), inband or info. Mismatched DTMF is why IVR menus ignore keypresses.
tos_audio / cos_audio - Mark RTP with DSCP EF (tos_audio=ef, cos_audio=5) so your switches and router prioritise voice.
Building this? Your PBX will need a number
Find a phone number for your trunk
Local numbers $1.50 a month, toll-free $2.00, $1.00 one-time setup. Pick one here and it carries into signup.
Enter an area code, or wait a moment for numbers near you.
AORs define where a device can be reached and how many simultaneous registrations are allowed:
pjsip.conf - AOR for phone
; AOR for extension 100 (phone registers to Asterisk)
[100]
type=aor
max_contacts=1
remove_existing=yes
qualify_frequency=60
; AOR for a trunk (static contact, no registration)
[ipcomms]
type=aor
contact=sip:sip.ipcomms.net:5060
qualify_frequency=60
max_contacts - How many devices can register with this AOR simultaneously
remove_existing - Remove old registrations when max is exceeded (avoids ghost registrations)
qualify_frequency - Send OPTIONS pings every N seconds to check if the device is reachable
contact - Static contact URI for trunks that do not register to your system
max_contacts, remove_existing and qualify in practice
With max_contacts=1 and remove_existing=no, the second device that tries to register to extension 100 is refused with 403 Forbidden and the Asterisk log shows the contact was rejected because the maximum was reached. That is the right behaviour for a single desk phone: a stale registration from a reboot cannot be replaced by an attacker guessing the password. With remove_existing=yes the newest registration wins and the oldest is dropped, which is what you want when a user moves between a desk phone, a laptop softphone and a mobile app on the same extension; set max_contacts=3 if all three should ring at once instead.
qualify_frequency=60 makes Asterisk send a SIP OPTIONS request to each contact every 60 seconds and mark it Avail or Unreach based on the reply, with qualify_timeout (default 3.0 seconds) deciding how long to wait. For phones behind NAT the pings have a second job: they keep the router's UDP mapping alive so inbound calls can reach the phone between registrations, so use 30 to 60 seconds rather than disabling it. remove_unavailable=yes (Asterisk 18 and later) goes one step further and deletes contacts that stop answering, so a phone that was unplugged does not sit in the contact list until its registration expires.
Check what is actually registered with pjsip show contacts (every contact with its RTT and status) or pjsip show aor 100. Trunk AORs with a static contact= never register, so max_contacts is irrelevant there; qualify_frequency still works and is the quickest way to see whether your provider is reachable.
Authentication
Auth objects store credentials for inbound authentication (phones registering to Asterisk) and outbound authentication (Asterisk registering to a trunk provider):
Identify objects match inbound SIP traffic to an endpoint based on the source IP address. This is essential for trunks using IP authentication where there is no REGISTER to identify the source:
pjsip.conf - Identify
; Match inbound calls from IPComms to the ipcomms endpoint
[ipcomms-identify]
type=identify
endpoint=ipcomms
match=34.23.59.14
Without an identify section, Asterisk will not know which endpoint to associate with inbound INVITE requests from your SIP trunk provider. The call will be rejected.
match= accepts a single IP, a CIDR range (203.0.113.0/28) or a hostname, which Asterisk resolves when the config loads. Several providers send from more than one address, so repeat the match= line for each. The order Asterisk tries identifiers is set in the [global] section with endpoint_identifier_order=ip,username,anonymous; if ip is missing there, identify sections are never consulted.
Registration
Registration objects tell Asterisk to register with an external SIP server. This is needed when your trunk provider uses digest authentication:
The matching dialplan is two lines: Dial(PJSIP/100) in from-ipcomms to ring the phone, and Dial(PJSIP/${EXTEN}@ipcomms) in internal to send calls out the trunk. For the full step-by-step trunk build, including test calls, see the Asterisk PJSIP trunk setup guide.
pjsip reload vs core reload vs core restart
The most common PJSIP question after "why is there no audio" is which reload command to run. Each one touches a different set of objects, and only a restart touches everything:
Command
What it re-reads
Effect on live calls
pjsip reload
pjsip.conf endpoints, AORs, auth, identify, registrations, outbound publish and ACLs. Equivalent to module reload res_pjsip.so plus the related res_pjsip_* modules.
None
core reload
Every loadable module's config: pjsip.conf, extensions.conf, rtp.conf, voicemail.conf, queues.conf and so on.
None, but it is slower and reloads things you did not change
dialplan reload
extensions.conf only.
None
module reload res_pjsip_outbound_registration.so
Registration objects only; handy after changing trunk credentials.
None, the trunk re-registers
core restart when convenient
Full restart once no calls are active.
None
core restart gracefully
Stops accepting new calls, restarts when the last call ends.
New calls refused until restart
core restart now
Immediate full restart.
All calls dropped
Three things need a restart no matter which reload you run: transports without allow_reload=yes, the [system] section (timers, threadpool, compact headers) and the [global] section's endpoint_identifier_order. Everything else in pjsip.conf, including adding brand-new endpoints, is picked up by pjsip reload. From a shell script use asterisk -rx "pjsip reload"; the exit code is 0 even when the config has errors, so follow it with asterisk -rx "pjsip show endpoints" and check the count.
WebRTC Endpoints with DTLS-SRTP
A browser softphone (JsSIP, SIP.js, a web dialer embedded in a CRM) connects to Asterisk over secure WebSocket and encrypts media with DTLS-SRTP. Since Asterisk 15 a single webrtc=yes endpoint option turns on every setting the browser requires. Three files are involved.
http.conf - WebSocket listener (the port lives here, not in pjsip.conf)
The browser then registers to wss://pbx.example.com:8089/ws. Two things trip most first attempts. The certificate in http.conf must be trusted by the browser, so use a real certificate (Let's Encrypt works) rather than the self-signed one Asterisk generates for TLS phones; and res_http_websocket and res_pjsip_transport_websocket must be loaded (check with module show like websocket). If registration works but there is no audio, the usual cause is the RTP range being blocked at the firewall or ICE candidates pointing at a private address; the Asterisk firewall and SIP ports guide covers the rules you need. WebRTC endpoints and an IPComms trunk coexist without special handling: Asterisk transcodes Opus from the browser to G.711 for the trunk.
Migrating from chan_sip to PJSIP
chan_sip was deprecated in Asterisk 17 and removed in Asterisk 21, so it is gone from 21, 22 LTS and 23. On Asterisk 18 and 20 it still loads, but nothing has been fixed in it for years. If you are planning an upgrade, convert sip.conf first and run PJSIP for a while on the old version; a chan_sip endpoint and a PJSIP endpoint can coexist as long as they bind to different ports (for example chan_sip on 5060 and PJSIP on 5062 during the transition, then swap).
Asterisk ships a converter at contrib/scripts/sip_to_pjsip/sip_to_pjsip.py. It reads sip.conf and writes a pjsip.conf you can review:
Shell - convert sip.conf
cd /usr/src/asterisk-*/contrib/scripts/sip_to_pjsip
python3 sip_to_pjsip.py /etc/asterisk/sip.conf /etc/asterisk/pjsip.conf.new
# review, then move into place and run: asterisk -rx "pjsip reload"
Review the output rather than trusting it, because a handful of settings do not map one-to-one:
sip.conf (chan_sip)
pjsip.conf (PJSIP)
Notes
host=dynamic
AOR with max_contacts=1
Phones that register
host=1.2.3.4 + insecure=invite,port
type=identify with match=1.2.3.4, no auth= on the endpoint
external_signaling_address, external_media_address, local_net on the transport
Moves from [general] to the transport
Dial(SIP/100)
Dial(PJSIP/100)
Every dialplan reference changes
Dial(SIP/${EXTEN}@trunk)
Dial(PJSIP/${EXTEN}@trunk)
Same syntax, new technology prefix
Also search the dialplan for SIPPEER(), SIP_HEADER() and SIPAddHeader(); their PJSIP equivalents are PJSIP_ENDPOINT(), PJSIP_HEADER() and PJSIP_HEADER(add,...). Device state hints change from SIP/100 to PJSIP/100 as well. If your dialplan is large, the Asterisk dialplan tutorial shows how to keep technology prefixes in a single global variable so a migration like this is a one-line change.
Troubleshooting PJSIP
Asterisk CLI - Useful PJSIP commands
; Show all endpoints and their status
pjsip show endpoints
; Show specific endpoint details
pjsip show endpoint 100
; Show all registrations
pjsip show registrations
; Show AOR contacts (who is registered)
pjsip show aors
; Every registered contact with RTT and Avail/Unreach status
pjsip show contacts
; Which identify sections exist and what they match
pjsip show identifies
; Show transport status
pjsip show transports
; Enable SIP debugging
pjsip set logger on
; Debug only traffic to or from one address (quieter on busy systems)
pjsip set logger host 34.23.59.14
; Per-call RTP statistics (jitter, loss) for active channels
pjsip show channelstats
; Reload PJSIP config (NOT transports)
pjsip reload
Common log messages and what they mean
Request 'INVITE' from '<sip:...>' failed for 'x.x.x.x:5060' (callid: ...) - No matching endpoint found Asterisk could not tie the inbound call to an endpoint. If the IP is your provider's, the identify section is missing, the match= address is out of date, or a hostname in match= did not resolve when the config loaded. If the IP is unknown it is a scanner probing your PBX; see Asterisk security hardening for fail2ban rules that ban these automatically.
Request 'REGISTER' from ... failed for ... - Failed to authenticate Wrong password, or the endpoint's auth= points at an auth object whose username= does not match what the phone sends. Repeated hits from one IP for extensions you do not have are brute-force attempts.
Request 'INVITE' from ... failed for ... - Failed to authenticate (from your trunk) The trunk endpoint has an auth= line, so Asterisk is challenging the carrier for a password it will never send. IP-authenticated trunks must have no inbound auth=; use outbound_auth= only if the provider requires registration.
Contact 100/sip:100@192.168.1.50:5060 is now Unreachable. RTT: 0.000 msec The OPTIONS qualify went unanswered: the phone is off, a firewall is dropping the ping, or NAT closed the mapping. Lower qualify_frequency to 30 for phones behind consumer routers.
Registration shows "Rejected" in pjsip show registrations The provider returned 401 or 403: wrong credentials in the auth object, or a client_uri whose user part does not match the account. Turn on pjsip set logger on and read the WWW-Authenticate realm in the 401 to confirm which server is answering.
403 Forbidden on a phone REGISTER, log says max_contacts reached Another device still holds the AOR's registration. Set remove_existing=yes or raise max_contacts.
Call connects, audio in one direction only Almost always external_media_address or local_net on the transport, rtp_symmetric=yes missing on the endpoint, or the RTP port range closed at the firewall. Capture with pjsip set logger on and compare the IP in the SDP c= line against your public address; the one-way audio guide has the full checklist.
For anything the CLI logger does not show, sngrep on the Asterisk host gives a live ladder diagram of every SIP dialog, and pjsip set history on followed by pjsip show history lets you filter past messages by address or call-id without leaving the console.
Asterisk PJSIP FAQ
What does pjsip reload actually reload?
pjsip reload re-reads pjsip.conf and applies changes to endpoints, AORs, auth, identify, registration, outbound publish and global ACL objects. It is the same as module reload res_pjsip.so plus the related res_pjsip_* modules. It does not touch transports (unless the transport has allow_reload=yes), the [system] section, the dialplan or rtp.conf. Active calls are not dropped.
How do I reload a PJSIP transport without restarting Asterisk?
Add allow_reload=yes to the transport section. After that, pjsip reload will re-create the transport when its settings change. The default is no because re-creating a transport drops any established TCP, TLS or WebSocket connections on it, so phones on those transports re-register. UDP transports reload without visible impact. Without allow_reload you need core restart now or core restart gracefully.
What is the difference between an endpoint, an AOR and an auth object?
The endpoint is the device or trunk itself: codecs, context, NAT and media behaviour. The AOR (address of record) is where that endpoint can be reached, either dynamically through registration (max_contacts) or a static contact for a trunk. The auth object holds a username and password. An endpoint references its AOR with aors= and its auth with auth= or outbound_auth=. Naming all three the same, for example [100], keeps small configs readable but is not required.
Why does Asterisk log "No matching endpoint found" for my SIP trunk?
Inbound INVITEs from a trunk arrive without a REGISTER, so Asterisk can only match them by source IP. You need a type=identify section whose match= covers the provider's signalling IP or hostname and whose endpoint= points at the trunk endpoint. If the message names an IP you do not recognise it is usually a scanner; if it names your provider, their IP changed or the hostname in match= did not resolve at load time. Check pjsip show identifies and confirm endpoint_identifier_order in [global] includes ip.
What do max_contacts and remove_existing do on an AOR?
max_contacts is how many devices may be registered to that AOR at the same time. When the limit is reached, remove_existing=yes drops the oldest registration so the new device gets in; with remove_existing=no the new REGISTER is refused with 403 Forbidden. Use max_contacts=1 for a single desk phone, 2 or 3 when the same extension also runs a softphone or mobile app. remove_unavailable=yes (Asterisk 18 and later) additionally drops contacts that stopped answering OPTIONS qualify pings.
Is chan_sip still available in Asterisk 21 and 22?
No. chan_sip was marked deprecated in Asterisk 17 and removed completely in Asterisk 21 (October 2023), so Asterisk 21, 22 LTS and 23 ship PJSIP only. Asterisk 18 and 20 LTS still include chan_sip but it is unmaintained. Any sip.conf peers must be converted to pjsip.conf objects, and Dial(SIP/...) in the dialplan must become Dial(PJSIP/...), before you upgrade.
Do I need a registration section for an IPComms trunk?
Not if you use IP authentication, which is the recommended setup. IPComms authenticates your trunk by the public IP of your Asterisk server, so you only need an endpoint, a static-contact AOR and an identify section matching the IPComms signalling address. A type=registration object plus outbound_auth is only required when a trunk uses username and password registration, for example a server on a dynamic IP.
Need a SIP Trunk for Your Asterisk System?
IPComms provides SIP trunking built for Asterisk PJSIP: IP authentication, $0 per channel with no set call limits, $0.009/min inbound and $0.010/min outbound, local numbers from $1.50/month, no contracts, and VoIP engineers on support. Stop worrying about SIP trunk capacity. We have you covered.