Why your SIP trunk drops every 30 minutes — registration TTL, NAT pinholes, OPTIONS keepalives
You've got a SIP trunk that comes up, runs fine, and falls over at the same interval — every 30 minutes, every hour, every 15 minutes. It re-registers and works for another window, then drops again. This article explains why that happens (NAT pinhole timeouts) and the three places to fix it.
Why the timer is periodic
SIP signaling is unsolicited UDP from the carrier's perspective. The carrier knows your PBX exists because your PBX registered with it; the carrier then sends INVITEs to the IP and port the PBX registered from. If your PBX is behind any kind of NAT, that IP/port mapping is a transient pinhole in the NAT table.
NAT tables hold mappings for a configurable timeout. After the timeout, the mapping is removed, and the carrier's next INVITE arrives at a closed pinhole. From the carrier's view your PBX vanished. From yours: incoming calls stop working until you re-register.
Typical NAT mapping timeouts:
- Consumer routers: 30 seconds to a few minutes for UDP.
- Enterprise firewalls: 30 seconds to 30 minutes, configurable.
- Carrier-grade NAT (mobile, some ISPs): unpredictable, sometimes as short as 30 seconds.
Your LYLIX PBX has a public IP and isn't behind NAT, so this problem applies only to PBX-to-carrier trunks where the carrier is doing the NAT-keeping, and to phones behind customer-site NAT registering to your PBX. Different ends, same mechanism.
Three places to fix it
1. Lower the SIP REGISTER refresh interval
The SIP registration Expires header tells the carrier "this registration is valid for N seconds; I'll re- register before it expires."
If you re-register more often than the NAT pinhole closes, the pinhole stays open because re-registration traffic flows. For typical NAT timeouts you want the registration to refresh every ~25 seconds.
In FreePBX®, on the trunk:
- Register String includes
:expires=60(or removeexpires=from the URI and set it via the pjsip endpoint).
For pjsip trunks:
# /etc/asterisk/pjsip.endpoint_custom.conf
[your-trunk]
qualify_frequency=30
2. Enable SIP OPTIONS keepalives
OPTIONS keepalive sends a small SIP OPTIONS packet at a fixed interval, regardless of registration. The packet keeps the NAT pinhole open without re-registering.
For pjsip trunks, set qualify_frequency=30 on the endpoint (above also covers this case). For chan_sip: qualify=yes sends OPTIONS every 60 seconds by default; lower for tighter NAT:
# /etc/asterisk/sip_custom.conf
[your-trunk]
qualifyfreq=30
3. RTP keepalive during calls
During an active call, the RTP audio itself keeps the audio NAT pinhole open — but during silence, some codecs send no packets, which can let the pinhole close mid-call. The fix:
# /etc/asterisk/rtp.conf
[general]
rtpkeepalive=15
Sends a small RTP packet every 15 seconds during silence.
Diagnosing the actual timeout
Find out exactly when the trunk drops:
asterisk -rvvv
pjsip set logger on
<wait until trunk drops>
<note exact time between successful registrations>
The interval tells you the NAT timeout. If the trunk drops exactly at 30 seconds: super-aggressive NAT, you need qualify_frequency=20. If it drops at 30 minutes: typical enterprise NAT, default keepalive is enough but check that it's running.
"It drops every 60 minutes exactly"
Carriers also have their own registration TTL. Some default to 3600 seconds (1 hour). If your PBX is configured to refresh at the carrier's exact expiry, you race the expiry on every refresh. Symptoms: trunk drops briefly every 60 minutes even with NAT keepalive working.
Fix: set the refresh interval to roughly half the carrier's TTL. For a 3600 second TTL, refresh every 1800 seconds. The carrier's expected TTL is usually documented; if not, observe what they return in REGISTER responses.
"All my phones drop every 30 minutes"
Same problem, different endpoint. Phones behind customer-site NAT registering to your PBX. Fix on the phone side:
- Polycom: SIP Server Registration period — set to 60 seconds.
- Yealink: Account → Advanced → Server Expires → 60 seconds.
- Sangoma / Cisco / Grandstream: similar per-account setting.
Also set STUN on the phone and confirm keep-alive packets are enabled. See SIP behind NAT for the full phone-side configuration.
Verifying the fix held
Watch the trunk for at least double the previously-observed drop interval:
asterisk -rvvv
pjsip show registrations
Status should stay "Registered" continuously. Successful re-registrations show up in the verbose log but the trunk never drops out of Registered state.
When it's not NAT
If your PBX has a static public IP and there's genuinely no NAT between the PBX and the carrier:
- Carrier-side issue: the carrier may be rotating their POP, expiring the registration mid-window. Open a ticket with them.
- Your firewall is closing the connection. Check stateful UDP timeouts in nftables / iptables.
- Asterisk crashed and respawned. Check
journalctl -u asteriskaround the drop time.
Also Read
Powered by WHMCompleteSolution