On a supervised iPhone with a managed Always On profile, the phone holds a tunnel for each active IP interface, so cellular and Wi-Fi each get their own. The server then lists two IKE security associations for one device, often sharing one virtual address, and the first instinct is to call it a rekey loop and start changing timers. That instinct is usually wrong. Work through the steps below in the order the evidence appears on the server, and leave the phone settings alone until the server tells you which case you have.

Start with the two rows the server already has

List the associations with swanctl --list-sas and read four fields across both entries: the remote address, the authenticated identity, the assigned virtual IP, and the creation time. Two different outer addresses with one identity and one virtual IP is the shape that started this question, and it is worth writing down before any change. Then check the child associations attached to each, because the traffic selectors decide whether a destination lookup could ever tell the two tunnels apart. A pair that appears and disappears within seconds is a different animal from a pair that both live for hours.

Sort the list by creation time before drawing a conclusion. Adjacency in the output means nothing, and a tabular listing invites exactly that mistake.

Decide which overlap you are looking at

IKEv2 rekeying and make-before-break reauthentication create a short overlap on purpose, establishing the new association before deleting the old one. Timestamps settle the case, because an old SA that disappears a second or two after the new one appears is renewal doing its job. Independent interface tunnels never look like that, since each persists while its interface stays up and deleting one does not follow from creating the other.

Apple's managed Always On behaviour is per interface, which is why a supervised device can legitimately look busier than a hand-configured profile. A provider app's auto-connect toggle does not imply the same thing, and neither does an ordinary on-demand rule. The Apple deployment overview describes the per-interface model; compare your two rows against it before assuming a loop. Both shapes also draw from the same server-side pool, so the overlap is your only early signal.

See why one virtual address for two tunnels breaks replies

A reply to the phone is addressed to the inner address, and the kernel picks an outbound tunnel by destination and policy, not by the interface the phone used. Two concurrent associations holding the same virtual IP with coinciding policies leave the routing decision with no way to say which session a reply belongs to. Some replies take the wrong tunnel, and the phone shows a connection that works one way or dies when Wi-Fi comes up. Two command outputs prove the state: swanctl --list-sas showing the same virtual IP on both SAs, and ip xfrm policy showing two identical selectors.

That pair of outputs is also what you paste into the change record. Neither one alone is convincing, because either can look plausible on its own.

This is server-side addressing and policy, not phone misbehaviour, and no client setting separates two identical inner addresses. The pool handed out the same value twice and the policy installer accepted it. Read the result from the server's side before blaming the client.

Change the pool or the concurrency model, not the rekey timer

In swanctl configuration, uniqueness is an explicit policy on the connection: unique = replace removes an older connection when a new one establishes, and unique = keep rejects the newcomer. Both values act when a connection is set up, not on the child SAs inside it.

connections {
  ios-alwayson {
    unique = replace
  }
}

Neither value is neutral for a per-interface client. keep restores a tidy status screen by refusing the second tunnel and breaks the managed design, while replace tears the older tunnel down and is the same compromise pointing the other way. If both tunnels are genuinely needed, the pool backend has to issue distinct leases for one identity, and its lease key has to distinguish the requests. A static identity-to-address table will happily return the same address twice and reproduce the original problem with more configuration. Check how the backend keys leases before adding a second static mapping.

Test the transitions you actually ship

Walk out of Wi-Fi range with a session active, then walk back in, and check that replies arrive in both directions. Do it twice, because the second transition is where a stale policy usually shows up. Test with a service that answers on the connection you opened, and repeat the walk-out while the tunnel carries traffic rather than sitting idle. A phone that can send but not receive looks healthy in a handshake log and broken in a browser.

A status screen reduced to one row is not evidence of a working design, only evidence that one tunnel is gone. Both directions have to work before a transition passes. Write down what you observed, together with the two outputs from the overlap check, so the next engineer can compare instead of repeating the walk.

Artitgels cun il medem tema