Migrating from chan_sip to PJSIP

Getting Started -- Last reviewed 2026-06-26 pjsip chan_sip sip migration configuration getting-started trunking nat Found this useful? Upvote it. ×

Migrating from chan_sip to PJSIP

chan_sip and chan_pjsip handle SIP differently at the object level, so there is no clean 1:1 mapping between them. chan_sip compressed everything into a single [peer] block: auth, location, codecs, NAT settings, all of it. PJSIP splits those responsibilities across separate objects (endpoint, auth, aor, registration, identify) that reference each other by name. You write more config upfront. It pays off when you have fifty endpoints and need to change one setting across all of them.

If you are coming from chan_sip for the first time, start with the conversion script to get a working base, then compare the examples below to understand what changed and why.

On this page

The conversion script

Asterisk ships a Python script that converts sip.conf to pjsip.conf. It handles the common cases, not every edge case. Treat the output as a draft, not a finished config.

The script is in the Asterisk source tree:

contrib/scripts/sip_to_pjsip/sip_to_pjsip.py

Run it from /etc/asterisk so it finds any #include'd files:

cd /etc/asterisk
/path/to/asterisk/source/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py

Output:

Reading sip.conf
Converting to PJSIP...
Writing pjsip.conf

Default input is sip.conf, default output is pjsip.conf. Included files are converted with a pjsip_ prefix. Use --prefix=xxx to change that.

PJSIP syntax is stricter than chan_sip

Extra spaces around =, unexpected capitalization, or missing required objects will cause silent failures or log warnings. If something does not load after conversion, check /var/log/asterisk/messages.

Side-by-side configuration examples

Endpoint configuration (phones)

Two phones registered to Asterisk with password authentication. Phone 6001 uses dynamic registration; 6002 has a static IP.

sip.conf:

[general]
udpbindaddr=0.0.0.0

[6001]
type=friend
host=dynamic
disallow=all
allow=ulaw
context=internal
secret=1234

[6002]
type=friend
host=192.0.2.1
disallow=all
allow=ulaw
context=internal
secret=1234

pjsip.conf:

[simpletrans]
type=transport
protocol=udp
bind=0.0.0.0

[6001]
type=endpoint
context=internal
disallow=all
allow=ulaw
aors=6001
auth=auth6001

[6001]
type=aor
max_contacts=1

[auth6001]
type=auth
auth_type=userpass
password=1234
username=6001

[6002]
type=endpoint
context=internal
disallow=all
allow=ulaw
aors=6002
auth=auth6002

[6002]
type=aor
contact=sip:6002@192.0.2.1:5060

[auth6002]
type=auth
auth_type=userpass
password=1234
username=6002

The PJSIP config is longer because chan_sip's type=friend block breaks into three separate objects: endpoint, aor, and auth. At two phones it looks like extra work. At fifty phones with templates, you change one line instead of fifty.

SIP trunk configuration

A provider trunk: register outbound, authenticate on outbound calls, accept inbound from the provider's IP.

sip.conf:

[general]
udpbindaddr=0.0.0.0

register => myaccountname:1234567890@203.0.113.1:5060

[mytrunk]
type=friend
secret=1234567890
username=myaccountname
host=203.0.113.1
disallow=all
allow=ulaw
context=from-external

pjsip.conf:

[simpletrans]
type=transport
protocol=udp
bind=0.0.0.0

[mytrunk]
type=registration
outbound_auth=mytrunk
server_uri=sip:myaccountname@203.0.113.1:5060
client_uri=sip:myaccountname@203.0.113.1:5060

[mytrunk]
type=auth
auth_type=userpass
password=1234567890
username=myaccountname

[mytrunk]
type=aor
contact=sip:203.0.113.1:5060

[mytrunk]
type=endpoint
context=from-external
disallow=all
allow=ulaw
outbound_auth=mytrunk
aors=mytrunk

[mytrunk]
type=identify
endpoint=mytrunk
match=203.0.113.1

The identify object is the part people miss first. In chan_sip, host=203.0.113.1 handled both outbound dialing and inbound matching. In PJSIP those are separate: the AOR handles where to send calls, and identify maps inbound traffic from that IP to the endpoint. Without it, Asterisk receives the call but cannot tell which endpoint it belongs to.

NAT settings

chan_sip used a single nat= value per peer. PJSIP breaks NAT behavior into three endpoint options you can set independently.

chan_sip nat= values (Asterisk 1.8+):

nat= Description
no No NAT handling beyond RFC 3581
force_rport Always send responses to the source address and port, even without rport in the Via header
comedia Send media to the address and port Asterisk received it from, ignoring SDP
auto_force_rport Automatically enable force_rport if NAT is detected (default)
auto_comedia Automatically enable comedia if NAT is detected

Equivalent PJSIP endpoint options:

chan_sip pjsip.conf
nat=yes rtp_symmetric=yes, force_rport=yes, rewrite_contact=yes
nat=no rtp_symmetric=no, force_rport=no, rewrite_contact=no
nat=never rtp_symmetric=no, force_rport=no, rewrite_contact=no
nat=route force_rport=yes, rewrite_contact=yes (rtp_symmetric stays no)

The three options break down like this:

Running chan_sip and PJSIP together during migration

You do not have to cut over all at once. Disable PJSIP until you are ready by adding these lines to modules.conf:

noload => res_pjsip.so
noload => res_pjsip_pubsub.so
noload => res_pjsip_session.so
noload => chan_pjsip.so
noload => res_pjsip_exten_state.so
noload => res_pjsip_log_forwarder.so

Restart Asterisk after editing. Remove the noload lines when you are ready to switch.

To run both at the same time on different ports, change the bind port in the PJSIP transport (e.g., chan_sip on 5060, PJSIP on 5061). Point test phones at the PJSIP port while production traffic stays on chan_sip.

A solid choice for hosting Asterisk.

High-performance cloud compute starting at $2.50/mo. Deploy a VPS in seconds.

Get $100 Free Credit

Referral link. Helps support this site.

User Notes

Know a tip or gotcha for this topic? Share it below and help others.

Contribute a note

Share a tip, gotcha, or practical example. Keep it under 2000 characters. No questions (use the Asterisk community forums for support). Wrap code in backticks.

Moderated before publishing. Email never shown.
Related Snippets