Per-app VPN on iPhone is not a phone-wide switch. It is an association between one managed app and one VPN payload, created when the app is deployed, and traffic from everything else keeps the route it had before. That is why the same phone behaves inconsistently: the work app opens a private page while Safari cannot reach the same host, or the tunnel never comes up and the app reports a timeout that looks like bad credentials. The checks run from the widest cause down, so stop at the first one that fails.

Check the payload and the app record first

The association lives in two objects, not one. The VPN payload defines the tunnel: type, server, authentication, DNS, and the provider bundle identifier when a custom client is used. The app record points at that payload, and most management consoles expose this as a per-app option on the app configuration, labelled something close to Per-App VPN. A payload with no app pointing at it routes nothing per app; it behaves like an ordinary tunnel that someone has to start by hand.

Read both objects before you touch the phone. Confirm the app configuration references the payload you are testing and not an older copy of it, since duplicated payloads with near-identical names are common after a migration and the app will happily point at the retired one. Then confirm the configuration reached the device: Settings, General, VPN & Device Management must show it as an installed profile. The VPN list there is not the test. A per-app service usually has no manual switch, so a correctly deployed configuration may never appear among startable VPNs. Absence shows in the app record and in whether the tunnel starts on the app's first request.

One condition explains a lot of tickets: this model needs the app to arrive through management. A sideloaded or personally purchased copy does not get the association, even when its bundle identifier matches. Apple’s deployment guide for VPN describes the payload model behind this (support.apple.com/guide/deployment/vpn-overview-depae3d361d0/web).

Confirm the installed app is the managed copy

Association follows the installed, managed app. If someone reinstalled it from the App Store under a personal Apple ID, replaced it with a re-signed enterprise build, or the device was re-enrolled and the app came back through a different channel, the tunnel can stay down while the app itself looks completely normal.

Test by comparison, not a single observation. In the management inventory, the app should show as managed for that device with the VPN mapping on its record. On the phone, the tunnel should come up when the app is launched and its first request goes out, not only when someone starts a separate manual configuration in Settings. If launching the app changes nothing and that manual configuration does, the app is not bound to a per-app tunnel at all.

Updates matter: one pushed through management keeps the mapping, while a user-initiated reinstall can lose it. When the complaint dates from an update, check the app record before the network.

Check what the tunnel is allowed to take

A per-app tunnel is selected by source app, so the phone’s default route still belongs to Wi-Fi or cellular. OverridePrimary is the key that changes that. When a profile sets it, the tunnel behaves like a full tunnel and every app inherits it, so everything going through the VPN becomes a profile question rather than an app failure.

On-demand rules decide persistence. OnDemandEnabled plus its rule set is what makes the tunnel come back when the app sends traffic, survive a change from Wi-Fi to cellular, or drop once the app moves to the background. A deployment that connects and then quietly dies usually has a rule matching only a probe that never fires while the app sits idle.

Then read the route side honestly. If a provider or vendor profile supplies an include list, a tunnel carrying only 10.20.0.0/16 will not carry a service in 10.30.0.0/16; that is the list doing its job, not a per-app failure. The built-in iOS payload has no include list. Without one, the split follows the provider defaults and IncludeAllNetworks, not a hidden list.

Test the app, then test what leaves it

Test with a name, not only an address. Resolving an internal host inside the managed app proves that DNS travelled through the tunnel too, because the payload decides which resolver answers and which search domains get applied. Routing can be perfect while name lookup fails, and the two symptoms point at different settings.

Then test the boundary from both sides. A personal app or Safari should reach an ordinary public page and report the carrier or home address, while the managed app reaches the private service. If both report the same public address, the tunnel is no longer per app, whatever the app record claims.

Flows that leave the app produce the confused tickets. A link that opens in Safari, a document handed off through the share sheet, or an SSO login that switches to a browser leaves the app’s process and the tunnel with it. A login rendered inside the app is usually attributed to the app, so an embedded sign-in can succeed where the same URL fails in Safari; verify that rather than assuming it. When the identity provider is only reachable through the tunnel, either keep the login inside the app or add the provider domain to the payload’s Safari domains so matching Safari traffic is captured.

Match the symptom to the layer

The failure shape tells you which check to repeat.

What you seeWhere the repair is
Tunnel never appears when the app opensApp-to-payload association, or the app is not the managed copy
Tunnel connects, internal name resolves, connection times outProvider or vendor include list missing the subnet, or a far-side firewall
Tunnel connects, internal name fails to resolveDNS servers or search domains in the payload
Every app uses the tunnelOverridePrimary set, or a full-tunnel payload reused
Worked until an update, broken sinceAssociation lost on reinstall, or the payload was replaced

Two details sit behind the middle rows: a per-app tunnel can be healthy and still miss a subnet no provider list includes, and a managed phone can hold more than one VPN configuration, so confirm which one the app is bound to rather than assuming it is the one you are reading.

Fix in this order: correct the app record so it references the live payload, reinstall the app through management, confirm the tunnel starts on the first request from the app, then repeat the name and boundary tests. If the first request cannot start a tunnel at all, stop and check the provider side, because a custom client needs its Network Extension present and its identifier matching the installed app.

Hand back three facts instead of a screenshot: which payload the app record references, whether Settings shows it as an installed profile, and what the failing request was, a name, an address, or a browser handoff. Those three answers separate a deployment mistake from a routing one, and the next person can act without repeating the diagnosis.

Sɛbɛn minnu bɛ tali kɛ