Establish the version and ownership boundary first
Inventory the installed FreePBX, framework, Core, Trunks and Asterisk versions before changing a trunk. Asterisk documents chan_sip as deprecated from Asterisk 17 and removed from Asterisk 21. Sangoma says Asterisk 21 does not support it, strongly discourages it on FreePBX 17, and no longer tests or develops the retained legacy path. A configuration that still loads on an older engine is therefore not evidence that it will survive an engine upgrade.
Keep FreePBX as the durable configuration owner. Record the exact GUI objects, generated files and supported custom-include boundaries; do not paste a raw sip.conf conversion over FreePBX-managed output. Take a protected backup and prove the restore procedure on an isolated target before changing production.
Freeze the legacy service contract, not just its text
For one trunk, preserve its provider handoff, registrar or proxy, authentication direction, registration requirement, signaling sources, codecs, DTMF method, fax expectations, number formats, asserted identity, encryption profile, media networks, capacity controls, failover and emergency process. Redact secrets while retaining their owner and rotation path.
Also capture the active FreePBX inbound and outbound routes, trunk sequence, dial manipulation, caller-ID controls and destinations that depend on the trunk. A register => line and one [peer] block do not describe the complete service. Registration, outbound requests, inbound endpoint identification, dialplan authorization and media are separate boundaries.
Translate behavior into PJSIP relationships
Asterisk's migration example expands a typical legacy trunk into distinct outbound-registration, auth, AOR, endpoint and identify sections. Use that object model to explain each current FreePBX field: registration creates the remote binding when the provider requires it; outbound auth answers a challenge; the AOR supplies a contact; the endpoint owns call behavior; identify maps permitted inbound traffic to that endpoint. Do not infer one object from another.
The bundled sip_to_pjsip.py script is documented as a basic conversion aid that is not intended to cover every scenario. Its output can inform a review, but it is not a FreePBX import, a carrier certification or proof that legacy nat, type=friend, host matching, header manipulation or dialplan behavior was preserved. Rebuild the trunk through supported FreePBX fields and review the generated PJSIP relationships.
Rehearse listeners, registration and routes without collision
Prefer an isolated restored system or provider-approved test identity. If both channel drivers exist temporarily on an older Asterisk branch, they cannot own the same local address, protocol and port. Inventory the generated transports and chan_sip bind, the operating-system listeners and the firewall or NAT mapping before applying a change. Do not downgrade Asterisk merely to preserve an obsolete recipe.
Avoid simultaneous registration of the same production identity unless the provider explicitly supports it. Build a named PJSIP trunk, submit and apply the FreePBX configuration, then inspect the loaded endpoint, AOR, contact, auth references, identify match, transport and outbound registration. A clean reload or a Registered label proves neither route selection nor inbound identification.
Cut over with per-direction acceptance evidence
Move an explicitly bounded outbound route or authorized test pattern first, then correlate the selected FreePBX route and PJSIP endpoint with one outbound SIP exchange. For inbound service, preserve the provider source, Request-URI or delivered number, identified endpoint, inbound route and final destination. Keep caller identity and number normalization separate from authentication.
For each required direction, record alerting, answer, hangup, two-way audio, codec and RTP endpoints, DTMF, hold, blind and attended transfer, forwarding and call records. Qualify fax, TLS/SRTP, failover, capacity and emergency calling only through their separately approved procedures. A successful ordinary call is not evidence that those paths work.
Retire the legacy trunk only after rollback is credible
Define the observation period, success criteria and rollback trigger before cutover. Preserve the old trunk and route state without leaving both paths able to originate or accept unintended traffic. If acceptance fails, revert the route and configuration through FreePBX, apply it, then verify the loaded objects and service rather than restoring fragments of generated files.
After acceptance, remove or disable the legacy trunk through its owning module, confirm that no route, extension, gateway or custom context still names it, and schedule any engine upgrade as a separate change. No FreePBX or Asterisk host, provider account, trunk, listener, registration, route, call, media path, emergency workflow or rollback was tested for this guide.
Sources & applicability
Primary references for the technical details above. Operational examples and planning checklists are VoIP.info editorial guidance.
- Sangoma: using FreePBX 17 with chan_sip ↗
- Asterisk: chan_sip status and support boundary ↗
- Asterisk: migrating from chan_sip to res_pjsip ↗
- Asterisk 21 chan_sip module removal ↗
- Asterisk PJSIP configuration objects and relationships ↗
- Asterisk PJSIP troubleshooting guide ↗
Examples require adaptation to your topology. No live PBX or hardware testing is claimed.