When running a VPN client on the host machine, standard Docker containers lose internet connectivity while using bridge networking. The issue manifests when trying basic network operations like ping:
# Fails when VPN is active
docker run adiazmor/docker-ubuntu-with-ping ping 8.8.8.8
# Works (but isn't ideal)
docker run --net=host adiazmor/docker-ubuntu-with-ping ping 8.8.8.8
The routing tables reveal significant changes when the VPN activates:
# Host routing table WITHOUT VPN
0.0.0.0 192.168.1.254 0.0.0.0 UG 100 0 0 enp4s0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
# Host routing table WITH VPN
0.0.0.0 192.168.226.1 0.0.0.0 UG 0 0 0 tap0
0.0.0.0 192.168.1.254 0.0.0.0 UG 100 0 0 enp4s0
The VPN client creates a new default route with higher priority (lower metric) than the original route. Docker's bridge networking relies on NAT and IP forwarding through the host's main network interface, but the VPN redirects this traffic.
Option 1: Modify VPN Routing Policies
Adjust your VPN configuration to exclude Docker networks from routing through the VPN tunnel. For IKE-based VPNs:
# Example IKEv2 config modification
s:policy-list-exclude:172.17.0.0/16
s:policy-list-exclude:172.18.0.0/16
s:policy-list-exclude:172.19.0.0/16
Option 2: Configure Docker's MTU
VPNs often use smaller MTU sizes. Set Docker's MTU to match:
# In /etc/docker/daemon.json
{
"mtu": 1380
}
Option 3: Create a Dedicated Docker Network
Establish a network with specific gateway settings:
docker network create --driver=bridge \
--subnet=172.25.0.0/16 \
--gateway=172.25.0.1 \
--opt com.docker.network.bridge.name=docker-vpn \
vpn-enabled-net
For compose-based deployments where --net=host isn't practical:
version: '3.8'
services:
app:
network_mode: bridge
networks:
vpn_net:
ipv4_address: 172.25.0.2
networks:
vpn_net:
driver: bridge
driver_opts:
com.docker.network.bridge.name: docker-vpn
ipam:
config:
- subnet: 172.25.0.0/16
gateway: 172.25.0.1
After implementing any solution, verify with:
docker run --rm --net=vpn-enabled-net alpine ping -c 4 8.8.8.8
docker run --rm alpine route -n
iptables -t nat -L -n -v
When establishing a VPN connection on your host machine, you might encounter a situation where Docker containers lose internet connectivity. This occurs because:
# Host routing table with VPN active
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.226.1 0.0.0.0 UG 0 0 0 tap0
0.0.0.0 192.168.1.254 0.0.0.0 UG 100 0 0 enp4s0
The VPN creates a new default route with higher priority (metric 0), while Docker's bridge networks remain isolated from this routing path.
A quick test reveals the problem:
docker run --rm alpine ping 8.8.8.8
# Fails when VPN is active
docker run --net=host --rm alpine ping 8.8.8.8
# Works because it bypasses Docker networking
The container's routing table shows the isolation:
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.19.0.1 0.0.0.0 UG 0 0 0 eth0
172.19.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
Option 1: Route VPN Traffic Through Docker
Add specific routes for your VPN endpoints:
sudo ip route add 78.109.86.184 via 192.168.1.254 dev enp4s0
Option 2: Configure Docker DNS Settings
Create/update your Docker daemon configuration:
# /etc/docker/daemon.json
{
"dns": ["8.8.8.8", "8.8.4.4"],
"dns-opts": ["use-vc"]
}
Option 3: Custom Bridge Network with Gateway
docker network create --driver=bridge \
--gateway=192.168.1.1 \
--subnet=192.168.1.0/24 \
my_custom_bridge
docker run --network=my_custom_bridge your_image
For persistent solutions, modify NAT rules:
sudo iptables -t nat -A POSTROUTING -o tap0 -j MASQUERADE
sudo iptables -A FORWARD -i docker0 -o tap0 -j ACCEPT
sudo iptables -A FORWARD -i tap0 -o docker0 -m state \
--state RELATED,ESTABLISHED -j ACCEPT
For compose files where --net=host isn't viable:
version: '3'
services:
app:
network_mode: "service:vpn"
depends_on:
- vpn
vpn:
image: your_vpn_image
network_mode: host
# VPN configuration here