NetworkManager exposes one property, vpn.persistent, and people ask it to answer four different questions at once. Its upstream documentation is careful: persistence applies when the VPN service supports it and the profile enables it, and the connection is then asked to survive link changes and outages until an explicit disconnect. The same documentation also shows the property defaulting to false, which is not what most recovery plans assume. Read it as a request for an attempt rather than a promise of a result.

What the setting actually commits to

A value stored in a profile is an instruction to the manager, and the manager has to hand that instruction to a VPN plugin that knows what to do with it. If the installed plugin ignores the property, the profile still activates and the log stays quiet, which is the worst of both worlds for anyone debugging later. Nothing inside a profile can force a plugin to implement behaviour it does not have, so the only visible result is an absence.

That is why the condition in the documentation matters more than the switch. Check which plugin and release you actually have, and write the version next to the connection description so the next person does not have to rediscover it. A recovery policy built on an unimplemented flag fails exactly once in production and always at the least convenient time.

Treating the property as an attempt also sets the right expectation for testing. You are not checking whether the flag is set; you are checking whether anything happened when the link dropped. Those are different experiments, and only one of them is worth an afternoon.

Four questions that get merged into one

Activation asks what brings the VPN up in the first place. A NetworkManager profile can be tied to a base connection, a separately managed OpenVPN service owns its own startup, and adding a third launcher to that arrangement gives you two owners with different ideas about who is in charge. Decide which component owns startup before you add another trigger.

Recovery asks what happens when the link changes or disappears, which is the narrow question vpn.persistent addresses. Liveness asks whether the client can tell the far end stopped answering, and OpenVPN keepalive or restart behaviour answers that one instead; the two mechanisms are often described with the same word and implemented in different places. Test them separately, with different tools, or you will attribute one behaviour to the other.

Intent asks whether reconnection is wanted at all, and it is the question that status polling cannot answer. A deliberate stop and an outage produce the same inactive state, so anything that reconnects on absence is guessing about a human decision. Guessing is fine right up to the moment it overrides somebody.

A checklist that keeps them apart

Run the events in order rather than reading configuration and reasoning about it, and record what each one shows with a timestamp.

First, activate the intended base connection and confirm the VPN came up through the trigger you expected rather than through a mechanism you forgot was installed. Second, during an approved interruption, compare the manager's VPN events, the owning client's recovery state and a fresh request to a private resource. Third, disconnect deliberately, wait, and confirm that nothing restarts the profile behind you.

The third step is the one people skip, and it is the one that finds the real defect most often. A watchdog that polls for an active profile and reconnects when it is absent will cheerfully undo a user's intentional disconnect. From the user's chair that is not resilience; it is a machine that will not obey. Ask them before adding one.

Write the results into the same document as the connection description. A recovery policy is only as good as the last time somebody watched it fail on purpose. Timestamps make the difference visible to whoever reads the notes next.

Authentication is part of recovery

Reconnecting is not purely a networking act. If the approved flow needs a fresh challenge, a one-time code, or a secret the activation context cannot reach, no persistence setting can produce it out of nothing.

That explains a familiar pattern: the connection recovers on a machine with an unlocked keyring and fails on the same machine after a reboot. The networking layer did exactly what it was asked and the credential layer had nothing to offer.

Fix the credential workflow instead of shortening the retry interval. Faster retries against a prompt nobody can answer generate log noise and a false impression that something is being attempted.

Persistence is not a kill switch

The property tries to keep or restore the VPN relationship. It does not decide what applications may do while the VPN is down, and it blocks nothing by itself.

If the requirement is that no traffic leaves outside the tunnel, that is a separate policy with its own mechanism, its own testing and its own failure modes. Assuming persistence covers it turns a security decision into an accident.

Record both halves in the recovery notes: what the VPN attempted, and what application traffic was permitted while the attempt was under way.

Qillqakuna t'inkisqa