The tunnel connects, then a lease renewal on the access link kills it, and the log blames a timeout rather than a route. Nothing in the VPN configuration changed, which is the clue: something outside it did. A DHCP event rewrote the address or the gateway, and the host route that kept the tunnel endpoint reachable now points at a next hop that no longer exists. This is an ownership problem before it is a routing problem.

Check the symptom against the half-default routes

With redirect-gateway def1, OpenVPN installs 0.0.0.0/1 and 128.0.0.0/1 rather than replacing the default route. Together those two cover the whole address space, and they beat 0.0.0.0/0 on prefix length alone. Any destination without a more specific match therefore enters the tunnel.

The endpoint needs an exception. OpenVPN adds a host route to the server address through the original access gateway before the half-defaults go in, so encapsulated packets can leave. When that exception disappears, or keeps a next hop that no longer exists, the tunnel's own outer packets match a half-default and are sent back into the tunnel. The result is a connection that dies at the next keepalive or handshake, with nothing in the log that looks like a routing error.

Confirm the shape of the table before touching anything else. ip route show should list both halves plus a host route for the server address; when the host route is missing, the rest of the investigation has an obvious starting point.

Why the half-defaults win without a metric change

A lower metric does not beat a longer prefix. The /1 routes win because the kernel matches the most specific route first, so raising a metric on the default route changes nothing about where tunnel-bound traffic goes. Chasing metrics is the most common wrong turn in this diagnosis.

Check selection with ip route get 203.0.113.10, substituting the real server address. The answer names the interface and next hop the kernel would actually use, which is more informative than reading a table and reasoning about it.

Run that command before the tunnel starts, while it is up, and after the lease event. Three answers from one command, and the divergence point becomes visible.

Take three snapshots, not one

Collect the access address, the access gateway, the endpoint destination, the selected route and any policy rules at three moments: after the access link is configured, after the VPN connects, and after the lease or carrier event. Each snapshot is a handful of commands, and they only mean something together. A single post-failure snapshot records the state rather than the transition. Write the commands into a small script so each snapshot is taken the same way.

Keep the snapshots in one file with timestamps, because the interesting question later is ordering. Did the DHCP event arrive before or after OpenVPN refreshed its route? The answer decides who has to fix it. A timestamp from the wrong clock is worse than none, so take it from the host that owns the route table.

When the endpoint is configured as a name rather than an address, resolve it in each snapshot too. A DNS change on the access link can move the endpoint without any route being touched at all.

Decide which component refreshes the exception

On a dhcpcd system, hooks run from the hook directory and from the exit hook, and manager mode differs in scope from per-interface mode. Whatever the hook does has to be idempotent, since renewals can arrive in bursts.

The reliable owner is the integration that already knows both sides: a network manager that manages the VPN connection, or a unit ordered after the access link comes up. A static route added by a hook works until the next gateway change, then fails in exactly the same way. If you do use a hook, make it read the current gateway at run time instead of hard-coding the one you saw today.

Record the owner inside the configuration. The next person debugging a reconnect needs to know that a hook, not the VPN, is responsible for the exception route.

Test the lifecycle, not just the reconnect

Force a renewal with dhcpcd -n eth0 or by releasing and renewing the lease, then check ip route get for the endpoint again. Do it twice, because the second run catches hooks that append duplicate routes. Then reboot, since persistence is a different property from correctness.

A tunnel that survives a renewal and a reboot has an owner and a working exception. One that survives only a manual restart has neither, and will fail at the next event you cannot schedule.

Winndannde jowitiiɗe heen