Darwvin

How to connect a softphone to FreePBX or Asterisk (PJSIP), step by step

FreePBX softphone setup over PJSIP: create the extension, match the Asterisk endpoint, auth and aor config, set NAT options, and fix 401, 403 and timeouts.

Published 11 min read

Connecting a softphone to FreePBX or Asterisk takes four things: a PJSIP extension with a secret, a server address and port the phone can reach, a transport (UDP, TCP or TLS) that matches that port, and NAT settings when the phone and the PBX sit on different networks. Registration shows whether the first three are right, and two CLI commands on the PBX show what the server sees. The steps below cover FreePBX's extension form, the equivalent pjsip.conf sections for plain Asterisk, and the checks to run after each step.

What you need

  • Admin access to the PBX: the FreePBX web interface, or shell and Asterisk CLI access on a plain Asterisk server.
  • Network reachability from the phone to the PBX on its SIP port. RFC 3261 sets the defaults at 5060 for SIP over UDP or TCP, and 5061 for SIP over TLS. The RTP media port range has to be open as well, or calls connect and then stay silent.
  • A softphone. Darwvin Softphone is the example client in this guide, but any SIP softphone takes the same fields.

Step 1: Create the extension in FreePBX

FreePBX 17 uses PJSIP as its default SIP driver, and the default Asterisk 21 build does not include chan_sip. New extensions are therefore PJSIP extensions.

  1. Go to Applications, then Extensions.
  2. Open the Add Extension dropdown and choose Add New PJSIP Extension. Labels change between releases, so match them to your screen.
  3. Enter the extension number, a display name and a secret. The extension number is also the SIP user name, so the softphone signs in as 1001, not as the display name.
  4. Save, then apply the configuration changes.

Make the secret long and random, and use letters and digits. Symbols are easy to mistype on a phone keyboard. Keep the secret in your password manager, because you will type it into the softphone in Step 4.

Step 2: PJSIP endpoint configuration for plain Asterisk

On a plain Asterisk server, the same extension is four sections in pjsip.conf: a transport, an endpoint, an auth section and an AOR (address of record). The shape follows the Asterisk res_pjsip examples. Change the names, codecs, context and secret to fit your system.

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

[1001]
type=endpoint
transport=transport-udp
context=internal
disallow=all
allow=opus,g722,ulaw,alaw
auth=auth1001
aors=1001
direct_media=no
rtp_symmetric=yes
rewrite_contact=yes

[auth1001]
type=auth
auth_type=userpass
username=1001
password=replace-with-a-long-random-secret

[1001]
type=aor
max_contacts=1
remove_existing=yes

Each section does one job:

  • The endpoint is the identity. By default Asterisk matches an incoming request to an endpoint by the user part of the From header. The softphone's user name has to equal the endpoint name, here 1001. If a phone sends a different From user, add auth_username to identify_by. The res_pjsip reference lists it among the identification methods.
  • The auth section is separate. The endpoint points to it with auth=. Asterisk checks the digest against username and password in that section, so both must match what the softphone sends.
  • The AOR stores registrations. max_contacts=1 allows one registered device. remove_existing=yes replaces the old contact when the phone registers again, which is what you want after a reboot.
  • The context has to exist. Calls from the endpoint go to the dialplan context named in context=. Run dialplan show internal to confirm the context holds the extensions you expect.
  • Opus needs a module. Opus needs the codec_opus module, so check it with module show like codec_opus.so. In our lab, Asterisk without codec_opus could not terminate or bridge Opus calls.

For TLS, add a transport with a certificate and a key:

[transport-tls]
type=transport
protocol=tls
bind=0.0.0.0:5061
cert_file=/etc/asterisk/keys/pbx.pem
priv_key_file=/etc/asterisk/keys/pbx.key

cert_file holds the certificate and priv_key_file holds the private key, and the two must match. Point the endpoint at the transport with transport=transport-tls. If you leave the line out, Asterisk picks the first suitable transport for the destination, which works but is less predictable. For TCP, use protocol=tcp with the same shape.

Reload rules matter here. Transport changes take effect only after a full Asterisk restart, so run core restart now or restart the service. A module reload does not apply them. For endpoint, auth and AOR changes, reload the PJSIP module with module reload res_pjsip.so.

Step 3: Check the endpoint on the Asterisk CLI

Connect to the console with verbose output:

asterisk -rvvv

Then run:

pjsip show endpoints
pjsip show endpoint 1001
pjsip show aor 1001

Read the output this way:

  • The endpoint appears in pjsip show endpoints. If it does not, look for ERROR lines in the startup log, and check that the section contains type = endpoint. Asterisk ignores a section without it.
  • pjsip show endpoint 1001 lists an InAuth: line, which shows the auth section is attached, and an Aor: line that points at the AOR.
  • Before the phone registers, the AOR has no contact. After a successful REGISTER, pjsip show aor 1001 shows a Contact: line with the phone's address. Contact lines also appear in the endpoint output.

When something fails, turn on logging, reproduce the attempt and read the messages:

core set verbose 4
core set debug 4
pjsip set logger on

pjsip set logger on prints every SIP message to the console. Turn it off with pjsip set logger off once you have what you need.

Step 4: Point the softphone at the PBX

The fields are the same in every softphone, even when the labels differ:

Softphone fieldValueNotes
User name1001The extension number. It must match the endpoint name, or identify_by has to cover it.
PasswordThe secretMust match the auth section exactly, including case.
Serverpbx.example.com or an IP addressThe name must resolve from the phone's network.
Port5060 for UDP or TCP, 5061 for TLSSet it only if you changed the PBX port.
TransportUDP, TCP or TLSMust match the transport the PBX listens on.
Auth user1001Only if it differs from the user name.

The setup guide for the example client uses the same inputs: user name, password and server, with Transport on Auto unless the PBX needs a specific one. On Linux, open Settings, then Accounts. On Android, tap Add Account, then Manual SIP Setup.

Step 5: Set NAT options when the phone or the PBX is behind NAT

NAT breaks SIP in two places. The reply to a REGISTER has to go back to the port the request came from, not to the port the phone claims to use. And the media addresses in the SDP can be private addresses the other side cannot reach. RFC 3581 defines the rport mechanism, and force_rport is Asterisk's way of applying it.

Asterisk's defaults are not NAT-friendly. rtp_symmetric and rewrite_contact default to no, and direct_media defaults to yes. These are the options that matter:

OptionWhereWhat it does
local_nettransportLists your internal networks. Addresses inside them are not rewritten.
external_signaling_addresstransportThe public address Asterisk uses in SIP messages sent outside local_net.
external_media_addresstransportThe public address Asterisk uses for RTP in SDP sent outside local_net.
rtp_symmetricendpointSends RTP back to the address and port it arrived from.
rewrite_contactendpointUses the address and port the request arrived from in the Contact header.
force_rportendpointSends SIP responses back to the port the request came from. The default is yes.
direct_mediaendpointSet it to no to keep Asterisk in the media path, as the NAT examples do.

A NAT-ready UDP transport looks like this. It replaces the plain transport from Step 2, and the endpoint keeps transport=transport-udp:

[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0
local_net=192.168.0.0/16
external_signaling_address=203.0.113.10
external_media_address=203.0.113.10

Replace 203.0.113.10, which is a documentation address, with your public address. Then restart Asterisk, because transport changes do not take effect on a module reload.

On FreePBX, do not hand-edit the generated pjsip.conf, since FreePBX rewrites it. Forum answers name FreePBX's custom PJSIP files for this job: pjsip.endpoint_custom.conf for hand-written endpoints, and pjsip.endpoint_custom_post.conf for endpoints made in the GUI. Check which one your release reads, then confirm the result with pjsip show endpoint.

Step 6: Test registration and audio

  1. The softphone shows the account as registered.
  2. On the PBX, pjsip show aor 1001 lists a Contact line.
  3. Call an echo test or another extension, and check that audio runs both ways.

If the call connects but one side hears nothing, the cause is usually NAT or the RTP ports rather than SIP. Work through one-way audio on VoIP calls before you change the PBX again.

Failures you will see, and what they mean

What you seeWhat it meansFix
401 Unauthorized, again after the phone answers the challengeRFC 3261 uses 401 to ask for credentials. Asterisk also sends a 401 challenge to a request it cannot match to any endpoint. A challenge, a retry and another 401 point to an unmatched request, not necessarily a wrong password.Check that the endpoint shows InAuth: and Aor:. Search the log for "Could not identify endpoint by username" or "does not match identify". Fix the From user or identify_by first, then check the password, its spelling and its case.
403 Forbidden on REGISTERRFC 3261 says the server understood the request and refuses it, and adding credentials will not change the outcome. In Asterisk, the usual causes are an AOR with no max_contacts, or a registration that would exceed it.Set max_contacts on the AOR, typically 1 for one phone. The log says "has no configured max_contacts" or "will exceed max contacts".
No response, then a timeoutNo reply reached the phone. RFC 3261 says a non-INVITE client waits 64*T1 seconds before it gives up. With T1 at its default of 500 ms, that is 32 seconds. Some stacks report the timeout as a locally generated 408 Request Timeout.Check the server name, port and transport. Make sure UDP 5060 or TLS 5061 reaches the PBX through every firewall. On the PBX, run tcpdump -ni any port 5060 while you retry, and see whether the REGISTER arrives.
TLS fails straight awayTransport and port disagree. TLS normally uses 5061, while UDP and TCP use 5060.Match the transport and the port on both ends.
488 Not Acceptable Here on the callThere is no codec in common between the phone and the PBX.Add codecs both sides support to allow=. Check codec_opus if you want Opus.
Registered, but one side is silentNAT or the RTP ports.Review Step 5, then the one-way audio guide.

To see what a 403 looks like on purpose, set max_contacts=0 on a test AOR. With the right password, the phone then gets a 403. We reproduced this in our lab. For the full list of response codes, see SIP response codes explained.

FAQ

Should I use chan_sip or PJSIP on FreePBX 17?

Use PJSIP. FreePBX 17 uses it by default, and the default Asterisk 21 build does not include chan_sip. If you still have chan_sip devices, check how your release migrates them before you change anything.

Which transport should I choose?

UDP is the simplest on a private network. TCP keeps a connection open, and TLS also encrypts the SIP signalling, on port 5061 by default. Choose a transport that both the PBX offers and the phone supports, and match it on both sides. Use TLS when SIP crosses the internet.

Why does registration work but calls have no audio?

Signalling and media take different paths. A successful registration shows that the SIP path works. One-way or no audio usually means RTP cannot reach the other side, because of NAT or closed RTP ports. Check the NAT options in Step 5, confirm that direct_media=no is set, and open the RTP range. The one-way audio guide has the full checklist.

Does the app work with FreePBX?

FreePBX is built on Asterisk, and we test the app against Asterisk. Other PBXs are not qualified yet, FreePBX included. The app uses standard SIP, so a PJSIP extension configured as in this guide is the right starting point. On Linux, Darwvin Softphone's diagnostics show a SIP message ladder, so you can follow the SIP messages of a failed call in order.

References

Get product news by email

We use your address only for these emails. The unsubscribe link is in every email. Read our privacy policy.