You put route-nopull in a client profile to stop the tunnel from swallowing your default route, and now the office subnet is unreachable while the client still says connected. Both observations are true, and nothing has failed. The flag tells the client to skip the routes and DHCP entries the server pushes, which is a narrower instruction than most people expect when they add it. What remains is a working tunnel with no opinion about which destinations should use it.

That gap is the whole decision this article is about. Either the server describes the network, or the client does, and the flag hands that job to the client without doing any of it for you.

What the flag switches off at connect time

A pulling OpenVPN client normally takes a bundle from the server after authentication: routes, a redirect of the default gateway, DNS servers, and a few tuning directives. With route-nopull in force the client still accepts the session, still verifies certificates, still negotiates ciphers and keepalives, and still brings the interface up. What it drops is the application of pushed route lines and pushed dhcp-option lines, DNS included.

The confusion comes from a green indicator sitting next to a dead application. The tunnel exists; the mapping from destinations to that tunnel does not. Nothing in the client status panel distinguishes "connected and routing" from "connected and inert", because from the tunnel's point of view both are the same state.

Why a live tunnel can still route nothing

The interface appears with its own address and, on a point-to-point link, often nothing more specific than a host route to the peer. A private subnet becomes reachable only when some route points at that interface with the right prefix, and with the push disabled that route never arrives. The downloaded profile usually cannot help either, since it was written on the assumption that the server would supply exactly this information. That is why the interface can look healthy while the subnet stays dark.

Reading the profile therefore proves very little. Read the running state instead, on the connected machine:

ip addr show tun0
ip route show dev tun0
ip route get 10.20.5.10

An address with no subnet route in the second command is the signature of this problem. The third command then answers the question users actually care about, because it reports the interface the kernel would pick for a specific destination rather than the list you hoped it would use. If it answers through your physical link, the tunnel is not in the path at all.

Name resolution fails for a related reason rather than a separate one. Pushed dhcp-option DNS entries are skipped by the same flag, so queries for internal hosts go to whatever resolver the local network provided. That resolver has no zone for the office, so the query fails or returns a public answer, and the failure looks like a server problem when it is a client configuration problem. Testing an address before a name is what separates the two.

Picking between the flag and a prefix filter

The two options solve different shapes of the same complaint, and picking badly is what produces the connected-but-useless state. One replaces the pushed policy wholesale, while the other edits it by prefix. The table gives the short version, and the paragraph after it covers the part that catches people out.

SettingWhat the client keepsReasonable when
no optionevery pushed route and DHCP entrythe server's view of the network is correct
route-nopullthe session, none of the pushed routing or DNSyou will write the full local policy yourself
pull-filtereverything except lines matching your prefixesthe push is nearly right and one or two lines are wrong

pull-filter is a prefix matcher with three verbs, so it can accept a family of lines, ignore them silently, or reject the connection outright when a prefix appears. That last behaviour is the one worth knowing about: a reject rule turns a policy disagreement into a failed handshake rather than a quiet omission. The OpenVPN 2.6 manual lists the accepted prefixes and the exact semantics of each verb.

A common middle path is to reject redirect-gateway alone and let the office routes and DNS arrive as intended. That keeps the push working for the parts the server understands better than you do, while preventing the one line that would take over your default route.

Adding routes and a resolver by hand

If you keep the flag, the profile has to say what the server would have said. Client-side route directives are applied after the connection is established, so they work alongside the flag rather than being blocked by it. Put them in the profile, not in an interactive command line, or the next reconnect will not reproduce the working state.

route-nopull
route 10.20.0.0 255.255.0.0
dhcp-option DNS 10.20.0.53

The DNS line sits in an awkward position: it is a client-side directive, but some clients apply it only through the platform's DNS integration, which may overwrite it when the link changes. On a systemd host, setting the resolver on the tunnel interface directly is more predictable than hoping the client wins the priority contest:

resolvectl dns tun0 10.20.0.53
resolvectl domain tun0 ~corp.example.com

The routing domain matters as much as the address. Without it, queries for public names may also be sent to the internal resolver, and any internal resolver that refuses recursion will break browsing while leaving the private zone working. With it, only names under that suffix are routed to the tunnel resolver and everything else follows the physical link.

Checking the result: address, name, and the outside path

Three tests separate the possible failures. Fetch the private address by IP, then the same host by name, then an ordinary public site. A working IP with a failing name points at the resolver; a failing IP with a working name points at routing; both failing usually means the tunnel is not in the path.

Then look outward rather than inward. The tunnel endpoint's own route has to survive the change, and any failure blocking has to be scoped to the tunnel without capturing the endpoint. A client that keeps browsing after the tunnel drops is a policy problem, not a routing one, and it will not show up in any of the three tests above.

Write the final list into the profile's documentation: the routes, the resolver, the domains, and the reason each exists. A reconnect that reproduces the same table is the only evidence that the local policy is complete. If applications still fail with the tunnel up and all three tests passing, the next place to look is the connected-but-offline class of problems rather than certificates that have already verified.

Ũhoro ũhĩtĩte