Windows Containers and VPN: Why Local Networking Breaks
A Windows container rides the host's route table, so a VPN that blocks the local subnet takes the container prefix with it. Linux mode takes another path.
On one laptop, with one VPN client connected, Linux containers keep talking to each other and Windows containers stop. The image is not the variable; the path the packets take into the host is. Windows containers on the default network borrow the host's route table and translation, so a policy that changes host routing changes them too. Confirm that with a route lookup before reinstalling anything.
Where a Windows container's packets enter the host
A container on the default nat network gets an address from a Host Networking Service prefix, usually somewhere inside 172.16.0.0/12, and reaches the host through a virtual adapter. The host owns the route for that prefix and translates traffic toward whichever adapter is current. There is no separate virtual machine in the middle of that path.
That design is what makes the failure mechanical. When the container sends a packet, the host performs a route lookup for the container prefix. Whatever route wins is where the packet goes, and the container has no opinion about it.
What the VPN client changes about that path
A corporate client often installs a broad set of routes and a filter that denies access to the local subnet while the tunnel is up. The intent is defensive: a compromised local network should not reach a protected machine. The side effect is that the host's route to the container prefix is no longer the local NAT network.
Instead, the lookup matches the tunnel and the packet is handed to the gateway, which has never heard of that container address. Ping fails, the application times out, and the container looks broken while the VPN icon glows. Check the host's table while connected and the competing route is visible.
| Container mode | Outbound path | Typical result behind the VPN |
|---|---|---|
| Windows, default nat | Host routes and translates container traffic | Container prefix follows the tunnel and fails |
| Windows, transparent | Container sits on the physical link | Depends on the local subnet being allowed |
| Linux engine on Docker Desktop | VM egress proxied by a host process | Often keeps working |
Why Linux containers behave differently
The Linux engine runs containers inside a lightweight virtual machine, and outbound connections from that machine are opened by a host-side proxy on the container's behalf. The host initiates the socket, so the VPN's rule about the container prefix does not apply to it in the same way, and the workload keeps reaching the network.
That difference also explains why Linux recipes do not port. A Linux container that needs its own tunnel is given a TUN device plus the NET_ADMIN capability. Windows containers expose no interface as a device, so that pattern has no equivalent on that side.
Prove the route, then choose a design
Collect evidence from the host, not from the container, because the host performs the lookup:
docker network inspect nat --format "{{range .IPAM.Config}}{{.Subnet}}{{end}}"
route print -4
Get-NetRoute -AddressFamily IPv4 | Where-Object DestinationPrefix -like "172.16.*"
Run the route output once before the VPN connects and once after. If the container prefix points at the tunnel adapter in the second output, the diagnosis is complete and restarting containers will not help.
The first option is a policy decision: ask the network owner whether local LAN access can be allowed for this device. Several corporate clients expose that as a setting, but it weakens a deliberate boundary. Ask for it as a documented exception with an owner and a review date. A per-device toggle that nobody revisits is how a defensive policy quietly disappears.
Where the policy must stand, move the workload instead of fighting the route. A transparent network with an explicit subnet and gateway puts containers on the local link, a Linux workload runs behind the VM proxy, and a separate virtual machine with its own client keeps its own policy. Pick one deliberately and test it from inside the container, because that is where the user's request originates.