Fresh out of the box, ICTPBX is perfectly happy talking to itself. Internal extensions can call each other all day long. What it can’t do yet is reach a single phone number out in the real world, and for that you need a SIP trunk, the on-ramp that connects your system to the public phone network. The good news is this isn’t a big project. With your provider’s credentials sitting in front of you, you’ll be done in roughly ten minutes. I’ll walk through every setting you touch and, just as importantly, tell you what each one is actually for, so you’re configuring the thing instead of blindly pasting in values and hoping for the best.
Before you start
Round up a few things first, because nothing stalls a setup faster than getting halfway in and realizing you’re missing a password. You’ll want ICTPBX installed and running (that’s the ICTCore, FreeSWITCH, and Angular stack), Super Admin access to the web interface, and an active SIP trunk account with a VoIP provider. From that provider specifically, you need their SIP server hostname or IP, your SIP username and password, and at least one DID, which is just industry shorthand for an inbound phone number.
On the network side, know your server’s public IP address and open two things inbound on your firewall: UDP/TCP 5080, which is ICTPBX’s SIP port, and UDP 16384 to 32768 for call audio (RTP). Outbound, allow your provider’s SIP port. That’s usually 5060 on their side, but nothing on ICTPBX listens on 5060. One last thing worth nailing down now: ask whether your provider uses registration-based or IP-based authentication, because the steps diverge a little depending on the answer.
Step 1: Collect your provider credentials
Don’t open ICTPBX just yet. First, go dig through your provider’s portal or that welcome email and write everything down, because grabbing it all now is exactly what saves you from a trunk that looks fine but silently refuses to connect. You’re after the SIP server (the proxy, usually something like sip.providername.com or a bare IP), your SIP username (often your account number or a trunk-specific name), and the matching SIP password. Note the authentication type too, registration-based or IP-based.
A couple more. Codecs: nearly every provider supports G.711 ulaw and alaw, and some throw in G.729, so jot down which ones yours offers. And your DID numbers, written in E.164 format, meaning with the country code and a leading plus sign, like +14085551234. Got all of it? Good. Trying to wing this with partial credentials is the single most common reason people end up troubleshooting a dead trunk for an hour.
Step 2: Add the trunk in ICTPBX
Now log in as Super Admin, go to Routing → Trunks and click Add. Tenant admins can’t do this, because trunks are shared by the whole system. Give the trunk a Provider Name you’ll recognize later when you build routes, something like “Twilio-US-Main” rather than “trunk1”. Then fill in the rest:
- Username and Password: exactly as your provider supplied them.
- Host/Proxy: the SIP server hostname or IP.
- Port: your provider’s SIP port. That’s usually 5060 on their end (nothing on ICTPBX listens on 5060), or 5061 for TLS.
- From User, From Domain and Realm: often just the username and SIP server again. Some providers won’t accept your calls until these are set.
- Transport, Expire and Retry: leave the defaults unless your provider says otherwise.
- Codec Prefs: see Step 4.
- Outbound Caller ID (DID): the number people see when you call them.
- Channels: match what your provider plan allows.
The one field that catches people out is Register. Set it to true for registration-based auth, where your server logs in to the provider. Set it to false for IP-based auth, where you instead whitelist your server’s IP on the provider’s side. Get that backwards and the trunk will never come up, no matter how perfect your password is. Fill it in and click Save. The trunk applies straight away, with no restart, and ICTPBX tries to register on the spot.
Step 3: Confirm it registers
There’s no trunk status screen in the portal. Give it 30 to 60 seconds after saving, then check registration with the API (GET /api/status/providers), or ask your administrator to check the gateway on the server. If it isn’t registered, stop right there, because a broken trunk won’t carry a single call. Work through these in order: re-type the username and password by hand (copy-paste slip-ups are the usual villain), confirm the SIP server hostname actually resolves from your server, check that the firewall allows outbound traffic to your provider’s SIP port, and double-check whether the provider expects IP-based auth, since if they do and you’ve set Register to true, no amount of correct credentials will ever get it to register.
One wrinkle to keep in mind: with IP-based authentication, the trunk won’t show as registered even when it’s working perfectly, because the provider routes calls straight to your IP without any registration handshake. So don’t trust the status check here, just prove it with a real call in Step 5.
Step 4: Pick your codecs
Open the trunk again and fill in Codec Prefs with the codecs your provider supports, in your order of preference. For most deployments, lead with G.711 ulaw (PCMU), the safe default that works with practically every provider and phone. Follow it with G.711 alaw (PCMA) if you’re in Europe or a region where that’s standard. Add G.729 only if your provider supports it and you genuinely need the bandwidth savings, and be aware it needs a license on some FreeSWITCH builds.
Strip out anything your provider doesn’t support. Leaving dead codecs in the list won’t break the connection, but it piles on pointless negotiation overhead and can trip up the stricter providers. Since ICTPBX rides on FreeSWITCH, whatever you set here flows straight into the FreeSWITCH SIP profile for this trunk, so if you’ve got SSH access and want to be certain, peek at the generated gateway XML after saving.
Step 5: Route your inbound DIDs
A registered trunk still won’t answer inbound calls on its own. You have to tell ICTPBX what to do when a call lands on each DID. It takes two steps:
- Add the number under Routing → DID Numbers and assign it to a tenant.
- Go to PBX → Inbound Routes and click Add. Enter the DID Number exactly as your provider sends it in the SIP INVITE (usually E.164 without the plus sign, like
14085551234). Then pick the Destination Type (Extension, Ring Group, IVR Menu or Voicemail) and the Destination.
You don’t pick a trunk on the route. DIDs on a registered trunk (SignalWire, for example) are detected automatically. Want calls to reach a queue or a conference? Point the DID at an IVR menu or ring group that leads there.
That DID format trips people up constantly, so watch it: some providers prepend a 1, some don’t, and ICTPBX needs an exact match. Got more than one number? Create a separate inbound route for each. A DID gets exactly one route, and ICTPBX rejects a second one for the same number. They can all point at the same destination or scatter to different ones, whatever suits you. The ICTPBX features overview covers the rest of the routing features. In a multi-tenant deployment you assign each DID to a tenant, which is what white-label and managed-service operators are after.
Step 6: Add an outbound dial rule
Outbound calls need a route that tells ICTPBX which trunk carries which destinations. Go to Routing → Routes and click Add:
- Choose the Service: Voice, Fax or SMS.
- Pick the Provider. That’s the trunk you just built.
- Choose a Region and a Country, then move the destinations this trunk should carry into Selected.
- Click Save.
Each route uses one provider. If your provider wants extra digits in front of every number, such as a leading 1, put them in the trunk’s Prefix field, not on the route. The caller ID people see comes from the trunk’s Outbound Caller ID.
Step 7: Test both directions
Don’t declare victory until you’ve tested both ways. For outbound, log into a SIP softphone registered to ICTPBX and dial your own mobile. Check that the call connects, audio runs cleanly in both directions, and the caller ID on your phone matches the trunk’s Outbound Caller ID. For inbound, call your DID from an outside phone and confirm it rings the destination you configured. Listen closely, and compare it to a plain mobile-to-mobile call. Noticeable jitter or delay almost always points at your network rather than the trunk itself. If both directions sound clean, you’re live. Our IP PBX guide digs into how trunks fit into the wider ICTPBX architecture if you want the bigger picture.
Troubleshooting
A few failures show up again and again, so here’s how to read them. If the trunk registers but outbound calls die instantly with a “403 Forbidden” or “401 Unauthorized”, the provider is bouncing your calls even though login worked. Usually that’s a caller ID they haven’t verified, or outbound calling that’s switched off on your account. Open the provider portal, confirm outbound is enabled, and make sure your caller ID number is verified, because plenty of providers won’t carry a thing until you’ve whitelisted it.
If inbound calls never reach the destination you set, the DID in your route almost certainly doesn’t match what the provider sends. They might send 4085551234 while your rule waits for 14085551234, or the reverse. With SSH access, run ngrep or tcpdump on port 5080, read the To: header on the incoming INVITE, and match your pattern to that exact format.
One-way audio, where one side can’t hear the other, is a NAT problem nearly every time. The call connects (signaling is fine) but the RTP media stream is blocked one way. Set your server’s external IP correctly in the FreeSWITCH SIP profile’s ext-sip-ip and ext-rtp-ip settings, and make sure the RTP range (UDP 16384-32768) is open both directions on the firewall. And if calls connect but sound jittery or robotic, suspect the network path, not your config, check the server’s bandwidth during a live call, watch for noisy neighbors on a shared VPS, and pin G.711 ulaw as the required codec so negotiation can’t quietly slide to a compressed one.
Frequently Asked Questions
Can I add multiple SIP trunks for redundancy? Yes, you can add more than one. Add each provider as its own trunk, then create routes for the destinations each one carries. Each route uses a single provider, so don’t count on calls rolling over to a second trunk on their own.
Does ICTPBX support encrypted calls with SIP TLS and SRTP? FreeSWITCH underneath it does, both encrypted signaling (TLS) and encrypted media (SRTP). Whether that’s surfaced in the admin panel or needs FreeSWITCH-level config depends on your build, so if encryption is non-negotiable, for healthcare or legal clients say, confirm it with us through a support ticket before you deploy.
My provider uses IP authentication instead of registration. Now what? Set Register to false when you build the trunk, then add your server’s public IP to the provider’s allowed list. The trunk won’t show as registered on your side, which is normal here, so prove it with a live call instead.
Do I need a separate trunk per DID? No. One trunk happily carries dozens or hundreds of numbers, since it’s just an authenticated connection to your provider. You’ll add one inbound route per DID, but they all share the same trunk. More trunks only come into play when you use more than one provider.
Can each tenant have its own trunk in a white-label setup? No. The administrator manages trunks and outbound routes for the whole system, and every tenant shares them. What you give each tenant is its DIDs, under Routing → DID Numbers. Tenant admins don’t see or manage trunks.
ICTPBX is white-label, multi-tenant PBX software built on ICTCore and FreeSWITCH for service providers and enterprises. Learn more about ICTPBX and explore your deployment options.