Two VPN clients running at once do not produce a nested tunnel; they produce two tunnels and a routing argument. A nested tunnel exists when the inner client's connection to its own server is itself carried by the outer tunnel, and that is an arrangement you build on purpose. Get it right and the inner server sees the outer server's address; get it wrong and one client silently reconnects around the other. Three conditions decide whether the nesting is real or accidental.

Three conditions decide the nesting

The first is which endpoint needs which path. Name the inner server's address, name the outer server's address, and state explicitly that the inner server is reachable only through the outer tunnel. Everything else follows from that sentence, including which routes belong in which table.

The second is whether you can see the path at each layer. If you cannot ask the kernel which route a specific destination would use, you are inferring the chain from a final exit IP, which is exactly the evidence that cannot distinguish nesting from coincidence.

The third is what happens when the outer tunnel drops. The inner tunnel can stop with it, reconnect over the ordinary network, or stay blocked until the outer path returns, and all three are defensible policies. They are not the same policy, and the default behaviour of most clients is the second. A client that reconnects its endpoint over the physical network while showing a healthy connection is the most common way an intended chain quietly becomes two unrelated tunnels.

Condition one: which endpoint needs which path

ip route get 203.0.113.10 answers that question directly: it prints the route, the source address and the interface the kernel would use for that destination right now.

Run it for the inner server before the inner client starts and again after, then compare. If the answer changes from the physical interface to the outer tunnel's interface, the nesting is real at that moment. If it does not change, the inner client is connecting directly no matter what the dashboard says. Repeat for the outer server's address, which must still resolve through the physical interface, because a route that captures both endpoints recursively is the failure that takes the machine off the network entirely.

Condition two: inspect the path at each layer

Route selection is more than the main table on a modern client. Policy rules can send marked packets to a different table, a client can bind its socket to an interface, and a container or namespace has its own tables altogether. ip rule and ip route show table all are how you find out which of those is in play.

A client that sets SO_MARK on its own socket, or is configured to bind to a specific device, bypasses the default route you thought you had arranged. That is a feature rather than a bug, and it means the only reliable check is one that runs in the same namespace as the client. If the clients run in containers, run the checks inside those containers instead of on the host.

Condition three: what happens when the outer tunnel drops

Failure behaviour needs a decision, not a default. Write down what should happen to the inner tunnel when the outer one disappears, then make the clients do that.

The options are concrete. Stopping the inner client when the outer path goes away gives a clean chain and an obvious outage. Letting it reconnect directly gives availability and silently removes the property the chain was built for. Blocking until the outer path returns is the strictest and the most annoying to operate, because every outer flap becomes a visible incident.

Test all three with harmless traffic and a deliberate outer failure, because reading the configuration will not tell you which one you have. Kill the outer tunnel, watch what the inner client does, and check the route again while it is down. Then bring the outer tunnel back and confirm the chain re-forms rather than leaving the inner client on the direct path it chose in the meantime.

What the chain does not give you

Extra layers add endpoints, keys and failure modes; they do not add an anonymity guarantee, and they do not make the outer operator unable to see that a tunnel exists. Any claim about what nesting protects has to name the observer it protects against.

The deliverable is a short document rather than a working connection: which endpoint uses which path, what happens on an outer failure, and the three commands that show the current state. The strongSwan forwarding documentation is a useful reference for how tunnel traffic is forwarded between interfaces on a Linux host. Re-run the checks after every client upgrade, because the defaults that produced your chain are not a contract. A nested tunnel you cannot inspect is a rumour with a status light.

Erthyglow kevrennek