You connect, the tunnel interface appears, and one prefix you need is simply not in the table. The next step is usually a search for a script that adds it. That search lands on answers which paste an OpenVPN helper into a profile, and half of those answers make the situation worse rather than better, because a missing route has three possible owners and only one of them is a missing script.

Decide which owner is responsible before you write anything.

Three owners, one missing prefix

The prefix can be absent because nobody supplied it, because the profile refused it, or because it was installed somewhere you are not looking. Those are different faults and they have different fixes.

The first is easiest to check: did the server or the plugin ever offer the route? A backend that never received the prefix cannot install it, and a helper script cannot invent reachability that the peer never described. The second is profile policy, which can suppress routes the connection would otherwise take. The third is a table or rule, which can hold the route in a place the default lookup never consults.

A fourth owner is you, later: a script that adds the route at connect time but does not remove it at disconnect. That produces a prefix that outlives the tunnel, points at a dead interface, and confuses the next person to debug the machine.

Read the profile before adding anything

Start with the saved connection's own properties. Read them without dumping secrets, and use the UUID if the profile name is ambiguous.

nmcli -f vpn.service-type,ipv4.never-default,ipv4.ignore-auto-routes,ipv4.route-table,ipv4.routes connection show office

vpn.service-type tells you which backend owns the connection, and that matters because plugin data is specific to the backend. A key accepted by one plugin is not a supported instruction for another, so a snippet copied from a different client's documentation is not evidence of anything.

ipv4.ignore-auto-routes and ipv4.never-default answer different questions. The first can reject routes the connection would otherwise take automatically, and the second controls whether the profile may become the default route. A profile that ignores automatic routes and relies on nothing else will connect cleanly and install almost nothing.

ip -4 rule show
ip -4 route show table all

Those two commands settle the third possibility. Look for your prefix in every table, not just main, and check whether a policy rule sends the relevant lookup somewhere else. If the prefix is present in another table and nothing consults it, you do not have a missing route; you have a lookup that never reaches it.

What a script cannot fix

Adding a helper script gives NetworkManager's vpn.data a program to run. That is a real mechanism, and it is the wrong one for most of these cases, because the script receives control after the profile's own policy has already decided what to accept.

OpenVPN's script-security is the other recurring confusion. It is an OpenVPN setting that governs which scripts the client may execute and what it may put in their environment; level 3 permits passing credentials through the environment, which is a secret-handling decision rather than a routing fix. Pasting it into a profile whose backend is not OpenVPN, or raising it when no script needs it, adds exposure without adding a route.

Then there is the restart reflex. Restarting the NetworkManager service tears down and rebuilds every managed link, including the one you are connected through if you are working remotely. It is a disruptive action, not a harmless diagnostic, and on a server it can be the difference between a session that survives and one that does not.

The decision, in order

Ask three questions in sequence. Did the peer supply the prefix, which the backend's log or its own status output will show? If yes, is the profile configured to accept and install routes, or is it suppressing them? If the route exists somewhere, is the lookup path correct for the traffic you are testing?

Only when the first answer is yes, the second is yes and the third is correct does a supplementary script become defensible, and even then you should ask whether the backend supports the route natively. The VPN settings reference documents service-type and the plugin-specific data dictionary, which is where to start before assuming a key exists.

After an approved correction, reconnect and test the destination by address and then by name, then disconnect and reconnect again to confirm the state is repeatable. One owner, one table, and a route that disappears with the tunnel is the outcome worth having.

Related articles