在 Docker 中运行 VPN 容器,本质是利用 Linux 的网络命名空间将 VPN 客户端进程与宿主机网络栈隔离,再通过特定的路由规则把指定流量导入隧道。这种方式既能让某个应用独享加密链路,又不会影响宿主机自身的出网能力。理解这套机制,比直接照搬 docker run 命令更重要。

VPN 容器的网络隔离底层原理
Docker 默认为每个容器创建独立的网络命名空间,容器内的网卡、路由表和 iptables 规则都与宿主机分离。当我们在容器中启动 OpenVPN 或 WireGuard 客户端时,VPN 进程会在容器命名空间内创建虚拟网卡(如 tun0),并修改容器内部的默认路由指向该网卡。由于宿主机拥有独立的命名空间,它看不到容器里的 tun0,也不会自动把流量转发过去,这就天然形成了第一层隔离。
但这种隔离也带来一个问题:如果容器使用默认的 bridge 模式,它只能通过 docker0 网桥访问外网,而 VPN 客户端修改的默认路由可能导致容器无法访问宿主机上的其他容器。要解决这个问题,通常需要给容器添加 NET_ADMIN 能力,并允许操作路由。在启动命令中加入 --cap-add=NET_ADMIN 后,容器才有权限修改自身的路由表与 iptables。同时,某些 VPN 客户端需要访问 /dev/net/tun 设备,必须通过 --device=/dev/net/tun 映射进容器。
从实践角度看,独立命名空间方案比在宿主机直接装 VPN 更利于排错。当 VPN 容器被停止,其命名空间随之销毁,宿主机上不会留下半截路由或残留的 iptables 规则。而如果直接在宿主机运行 VPN 客户端,异常退出常常导致默认路由丢失或 DNS 配置污染,恢复起来更麻烦。
host 网络模式与桥接模式的实战对比
使用 --network=host 运行 VPN 容器,意味着容器直接共享宿主机的网络命名空间。此时 VPN 客户端修改的默认路由会直接作用在宿主机上,所有宿主机的流量都会走 VPN。这种模式的优势是配置简单、网络性能高,没有桥接层的 NAT 开销;缺点是隔离性极差,一旦 VPN 断开,宿主机可能瞬间失联,且无法做到“仅某应用走 VPN”的精细控制。
相对地,桥接模式(默认 bridge 或自定义桥接网络)下,VPN 容器拥有独立 IP,仅自身流量走隧道。若想让其他容器通过它联网,还需手动配置容器间的路由或使用 privileged 模式做转发。下面是一段 docker-compose 中自定义桥接并开启 VPN 的典型配置,展示了如何通过 sysctls 关闭反向过滤以避免隧道包被丢弃:
version: '3'
services:
vpn:
image: dperson/openvpn-client
container_name: vpn
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
sysctls:
- net.ipv4.conf.all.rp_filter=2
- net.ipv4.conf.default.rp_filter=2
environment:
- VPN_USERNAME=user
- VPN_PASSWORD=pass
restart: unless-stopped
上述配置中,rp_filter 设为 2 是宽松模式,允许非对称路由,这对许多 VPN 隧道是必要的。如果保留默认的严格过滤,从隧道回来的包因源地址不在出口网卡上而被内核丢弃,表现就是能连上 VPN 却无法访问任何内网资源。通过这种细调,桥接模式下的 VPN 容器稳定性可接近 host 模式,却保留了隔离能力。
DNS 泄漏防护与容器间互访规划
即便流量走了 VPN,若容器使用的 DNS 服务器仍是宿主机分配的公有 DNS,查询请求就可能绕过隧道,造成 DNS 泄漏。在 VPN 容器内,应当显式将 /etc/resolv.conf 指向 VPN 服务商提供的内网 DNS 或公共加密 DNS。可以在启动脚本中用 echo "nameserver 10.8.0.1" > /etc/resolv.conf 覆盖,或者在 compose 文件中用 dns 字段指定。
另外,当多个业务容器需要经 VPN 容器出网时,要避免网段冲突。例如 VPN 内网分配的是 172.17.0.0/16,而 Docker 默认桥接也是该段,就会引发路由混乱。此时应创建自定义桥接并指定不同子网,如 10.20.0.0/16,并在 VPN 容器内配置 SNAT 规则。下面代码演示了在 VPN 容器中开启 IP 转发并做 MASQUERADE:
# 允许 IPv4 转发 sysctl -w net.ipv4.ip_forward=1 # 对来自其他容器的流量做源地址转换 iptables -t nat -A POSTROUTING -s 10.20.0.0/16 -o tun0 -j MASQUERADE # 允许桥接网段访问隧道 iptables -A FORWARD -s 10.20.0.0/16 -o tun0 -j ACCEPT
完成这些设定后,业务容器只需把默认网关指向 VPN 容器的 IP,即可安全复用隧道。这种架构下,即使 VPN 意外中断,业务容器因无法经 tun0 出站而自动断网,不会出现明文泄漏到公网的情况,比全局 host 模式更安全可控。日常运维中,配合健康检查定时重启 VPN 容器,能进一步降低长连接掉线带来的业务影响。
DockerVPNnetwork_isolation修改时间:2026-08-13 13:12:38