Installing a second VPN client to reach one customer network is the usual way this starts, and the first tunnel goes dark while both clients report success. Each client installed a default route, the second one was more specific, and the kernel now follows it for everything except the first tunnel's own outer connection. Nothing crashed and no profile is wrong. One route replaced another, and the fix is to decide which tunnel should own the default.

The symptom: the second client wins quietly

OpenVPN's redirect-gateway def1 does not overwrite 0.0.0.0/0. It adds 0.0.0.0/1 and 128.0.0.0/1: between them they span every IPv4 address, and each prefix beats a plain default on length. The original default stays in the table and stops being used for ordinary traffic, and a host route to the VPN server keeps the tunnel from capturing its own outer packets. Both clients do this, and the second one simply installs its pair later.

That is why the first tunnel looks dead rather than disconnected. Its interface is up, its control channel is alive, and no application traffic reaches it any more. The reverse complaint traces to the same missing push: a phone that connects but sends nothing is usually talking to a server that never advertised redirect-gateway, so the device keeps its own default and reaches only the pool.

Take a routing snapshot before and after the second client connects. The two half routes appearing in the table are the whole change, and they explain both complaints. Nothing else in the table needs to move for the symptom to appear. That is also why removing the second client restores the first one instantly.

Read which tunnel actually wins

Do not infer the winner from the order the clients started or from the icon in the tray. Ask the kernel which route it would use for a destination outside both private networks, and read the interface that comes back.

ip route show
ip route get 198.51.100.24
route print -4
Find-NetRoute -RemoteIPAddress 198.51.100.24

The first two are the Linux answer and the last two are the Windows equivalent. Run them while both tunnels are up, then disconnect one and run them again. The difference between the two outputs is the fact you need before choosing a fix, and it takes less time than reading either client's log.

Record the result, including the interface name and the prefix that matched. A ticket that says the second VPN broke the first is a description of the symptom, not a routing statement anyone can act on. The lookup turns it into a fact the next engineer can reproduce in one command.

Windows: stop one profile owning the default

Windows keeps stored profiles, and the built-in client lets one depend on another so the first comes up automatically when the second dials. Whichever profile connected most recently tends to keep the default, so the practical owner is the last dial rather than the first. Give each profile its own pushed routes and turn split tunneling on for the one that should not own the default.

Set-VpnConnection -Name "Contoso" -SplitTunneling $true
rasdial Contoso

Split tunneling changes that: only server-pushed prefixes land in the table, which leaves the first tunnel holding the default. The design still fails if both servers push a default route, because then the last connection wins and no client-side setting changes that. Fix the server-side push or accept one owner.

App-triggered profiles are a different feature and worth knowing about: a Windows profile can start when a named executable launches, with traffic filters deciding what it carries. That is a profile setting rather than a firewall rule, and it solves a different problem from the default-route conflict.

Linux: keep the second tunnel out of the main table

Running two openvpn --config instances on one machine puts both clients in the same table, and three options separate them with increasing isolation. The lightest is to stop the second client editing the table at all, using route-nopull with explicit routes, or a route-up script that installs only what you intend. Then the second tunnel carries exactly the prefixes you name and nothing else. Then you decide which prefixes go where instead of discovering it afterwards.

Policy routing is the middle option. A rule selects a separate table for one source address or firewall mark, and that table carries the routes for the second tunnel. Reverse-path filtering is the trap here, because a reply that arrives on a different interface than the table would choose gets dropped, so check the rp_filter setting before concluding the tunnel is broken.

ip rule add from 10.44.7.0/24 table 100
ip route add default dev tun1 table 100
sysctl net.ipv4.conf.all.rp_filter

Network namespaces are the heaviest option and the cleanest. Start the second client inside ip netns, give it a veth pair, and enter that namespace to use it. Interference disappears because each namespace owns its own tables instead of sharing one, which is worth the extra setup when both tunnels must stay up for weeks.

Per-application, and chaining as a separate problem

Sometimes only one program should use the second tunnel. On Linux, policy routing by user, cgroup or port reaches that result, and a single destination can be pinned to an interface without touching the default at all. An application that pins its socket to one interface never consults the routing table at all, so a launcher can keep using the physical adapter until an address is chosen inside its own settings.

Chaining is a different operation from running two tunnels side by side. Chaining A over B means the inner server's address has to be reachable from inside the outer tunnel. The outer client also must not mistake the inner client's encrypted packets for a leak. One client inside a virtual machine is the blunt but reliable version; both on one host needs the routing work above plus an outer path toward the inner server that never enters the inner tunnel.

Write down the default owner, the prefix list each tunnel carries, and the DNS path. Those three facts turn the next incident into a lookup instead of an investigation.

འབྲེལ་བའི་རྩོམ་ཡིག