Asterisk 30 Second Call Drop: Find the Lost ACK
An Asterisk 30 second call drop with no ACK happens because the ACK to the 200 OK never reaches Asterisk, so it gives up at 64*T1 = 32 seconds and sends BYE. Capture the SIP trace, find which address the ACK was sent to, and fix that header.
- A BYE at about +32s after answer, with repeated 200 OK and no ACK, is the Timer H signature of a lost ACK, not a codec, RTP or session-timer fault.
- The ACK goes to the Contact of the 200 OK, or to the Record-Route set, so a private IP in either header is the most common cause.
- In PJSIP set external_signaling_address, external_media_address and local_net on the transport, and include every internal, VPN and VLAN subnet in local_net.
- Compare tcpdump on the PBX with one on the far side or firewall to see whether the ACK was never sent, lost in transit, or received and ignored.
- Verify by calling for over a minute from LAN, remote and trunk paths and confirming the ACK follows the 200 OK immediately.
Why does an Asterisk call drop after about 30 seconds?
An Asterisk 30 second call drop, where the call connects and then hangs up about half a minute later, almost always means a lost ACK. A SIP INVITE is a three-way handshake: INVITE, 200 OK, ACK. Asterisk sends the 200 OK and then waits for the ACK.
Because UDP can lose packets, Asterisk retransmits the 200 OK on a backoff schedule: 500 ms, 1 s, 2 s, then 4 s repeating. This is the RFC 3261 behaviour for INVITE server transactions.
The retransmissions stop at 64*T1, which is 64 x 500 ms = 32 seconds. With no ACK by then, the call is considered failed and Asterisk sends BYE. So a hangup at 32 seconds is the signature of a lost ACK.
That timing is what separates this from other faults. A codec mismatch fails at setup or gives silence. A session-timer problem usually shows at half the Session-Expires interval, often many minutes in. An RTP problem leaves the call up with no audio. A call that connects, even with audio in both directions, and dies at +32s is an ACK problem.
Audio can work because RTP flows to the addresses negotiated in SDP, independently of where SIP signalling goes. The call looks healthy until the timer fires.
| Symptom | Likely cause |
|---|---|
| BYE at +32s, 200 OK repeated in log | ACK lost or ignored (this page) |
| Silence from the start, call stays up | RTP/SDP address problem |
| Drop at 15 or 30 minutes, or half of Session-Expires | Session timer refresh failing |
| Drop at +30s to +60s with no 200 OK repeats | Provider billing or credit limit, or max call duration |
How do I capture the trace that proves where the ACK is lost?
Start on the PBX. Enable the SIP logger, place a test call, and let it die.
Then capture packets at the PBX and, if you can, at the far side or firewall. Comparing both shows whether the ACK left the phone or provider, reached your firewall, and reached the PBX interface.
- Run pjsip set logger on (chan_sip: sip set debug on) and place the call.
- Look for the 200 OK repeated at roughly +0.5s, +1.5s, +3.5s, +7.5s, +11.5s and so on, with no ACK between them.
- Capture on the PBX: tcpdump -ni any -s0 -w /tmp/sip.pcap port 5060. Add the SIP TLS port 5061 or your custom ports if used.
- Capture at the same moment on the remote phone's network or the firewall WAN interface.
- Open the pcap in sngrep or Wireshark and note the Contact, Record-Route and Via headers of the 200 OK, and the destination of any ACK.
asterisk -rx "pjsip set logger on"
sngrep -d any port 5060
tcpdump -ni any -s0 -w /tmp/sip.pcap port 5060 or port 5061
# afterwards
asterisk -rx "pjsip set logger off"Which header decides where the ACK goes?
For a 2xx response, the caller builds the ACK from the dialog state. The destination is the Record-Route set (as Route headers) if the 200 OK has one, otherwise the Contact URI of the 200 OK. The Via and source IP of the original INVITE are not used.
So a broken call usually looks like this. The 200 OK is sent to the right place, because responses follow the Via header. But it advertises an address the caller cannot reach:
The comments mark the bad header. The caller sends its ACK to 192.168.1.10, which on the public internet is either dropped or delivered to someone else's LAN.
# BROKEN: Asterisk behind NAT, no external_signaling_address
SIP/2.0 200 OK
Via: SIP/2.0/UDP 203.0.113.50:5060;received=198.51.100.7 <- response goes here, fine
Record-Route: <sip:192.168.1.10;lr> <- private, ACK will be routed here
Contact: <sip:192.168.1.10:5060> <- private
(200 OK repeats at +0.5s +1.5s +3.5s +7.5s ... no ACK)
(BYE from Asterisk at +32s)
# FIXED
SIP/2.0 200 OK
Contact: <sip:198.51.100.7:5060> <- public address
ACK sip:198.51.100.7:5060 SIP/2.0 <- arrives immediately after 200 OK How do I fix the advertised address in PJSIP and chan_sip?
Asterisk rewrites Contact and Record-Route to the external address only when the destination is outside local_net. So the three transport values must agree with your real topology.
Every internal range must be listed, including VPN pools, VLANs and Docker bridges. If one is missing, internal callers receive the public address, which often fails because of no hairpin NAT. If local_net is too wide, remote callers receive the private one.
Endpoint settings then deal with the phone side. rewrite_contact=yes makes Asterisk send in-dialog requests to the source IP and port of the request rather than the Contact header. This helps phones behind NAT. It does not fix a wrong Record-Route, which is generated by Asterisk's own transport settings.
force_rport=yes answers to the source port, rtp_symmetric=yes sends RTP back to where RTP arrives from, and direct_media=no keeps Asterisk in the media path so phones do not exchange private addresses.
; pjsip.conf (FreePBX: Settings > Asterisk SIP Settings > Chan PJSIP)
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0:5060
external_signaling_address=198.51.100.7
external_media_address=198.51.100.7
local_net=192.168.1.0/24
local_net=10.8.0.0/24 ; VPN
local_net=172.16.20.0/24 ; VLAN
[remote-phone]
type=endpoint
transport=transport-udp
rewrite_contact=yes
force_rport=yes
direct_media=no
rtp_symmetric=yes
; chan_sip equivalent (sip.conf [general])
; externaddr=198.51.100.7
; localnet=192.168.1.0/255.255.255.0
; nat=force_rport,comedia
; directmedia=noWhere is the ACK lost: firewall, provider, proxy or transport?
Use the two captures to place the loss. The table maps what you see to the cause and fix.
If the ACK reaches the PBX interface in tcpdump but Asterisk keeps retransmitting, the packet arrives but is not matched. That points to the PJSIP endpoint or identify match, an ACL, or a stateful firewall on the host such as iptables or fail2ban blocking a second source IP.
Providers sometimes send the ACK from a different IP than the one the INVITE came from. Allow all of their signalling ranges in the firewall, in identify entries (match=) and in any ACLs, not only the INVITE source.
With proxies such as Kamailio or OpenSIPS, the ACK follows the Route headers. Use record_route() and fix_nated_contact(), and check that the Record-Route hostname resolves from the caller and does not point to a private IP. Look at the ACK's Route header in the trace: that is exactly where the ACK is being sent next.
Transport matters too. If Contact has transport=tcp or tls, the ACK needs an open connection or port 5061 reachable. A large INVITE over UDP may fragment, and fragments are often dropped by firewalls. Also check that bind addresses are not tied to the wrong interface.
| Where the 200 OK goes / what the trace shows | Where the ACK is sent | Where it is lost | Fix |
|---|---|---|---|
| Contact or Record-Route has 192.168.x or 10.x | To the private address | Never reaches PBX | external_signaling_address, local_net |
| Contact public, ACK leaves the phone, absent at firewall WAN | To the public IP | SIP ALG or NAT mapping expired | Disable SIP ALG, keepalives, qualify_frequency |
| ACK arrives at firewall WAN, absent at PBX | Correct address | Firewall or port forward | Forward UDP 5060 (and 5061), allow from provider ranges |
| ACK arrives on PBX interface, 200 OK still repeats | Correct | Endpoint or identify mismatch, ACL, fail2ban | Fix identify, ACL, unban IP |
| ACK sent to different port | Wrong port | Contact port rewritten wrongly | force_rport, rewrite_contact, check bind port |
| Contact transport=tls or tcp | TCP or TLS connection | Connection closed or 5061 blocked | Open port, matching transport, or use UDP |
| Route header with unresolvable host | Fails DNS | Proxy | Fix record_route and fix_nated_contact |
What mistakes hide this problem instead of fixing it?
Raising timers or disabling session timers does not help. Timer H is part of the transaction layer, not a session timer, and extending it only delays the BYE.
Changing the RTP port range is irrelevant when the fault is SIP signalling. Audio working both ways is normal with a lost ACK, so do not conclude the problem is media.
Do not test only from the LAN. Local phones are inside local_net and never hit the NAT path. Test from each route: LAN, remote, VPN and trunk.
Leaving SIP ALG enabled on the router is a common repeat cause. Disable it on the router and any upstream modem, since it rewrites SIP headers inconsistently.
How do I confirm the fix worked?
Check the behaviour on every path, not just one.
- Place a call longer than 1 minute from a LAN phone, a remote phone and through each trunk.
- With pjsip set logger on, confirm an ACK appears right after the 200 OK and the 200 OK is sent only once.
- Check the Asterisk log for no repeated 200 OK and no BYE at +32s.
- Run pjsip show transports and confirm the external address and local_net are as configured.
Common questions
Why is it exactly 32 seconds and not 30?
The timer is 64*T1 with T1 = 500 ms, so 32 seconds. Users round it to about 30, which is why searches say 30 seconds.
Can a one-way audio problem and the 32 second drop share a cause?
Yes. Both often come from a private address advertised in SIP or SDP when NAT settings are missing. The SDP fix is external_media_address, and the SIP fix is external_signaling_address.
Does qualify or keepalive help?
Yes for phones behind NAT. Regular OPTIONS or qualify_frequency traffic keeps the UDP mapping open so that inbound requests and ACKs can pass. It does not fix a wrong Contact.
Does the problem occur with outbound or inbound calls only?
It can affect either, but it commonly affects calls where the far side has to send the ACK to Asterisk, so check the direction in the trace.