// 2026年3月26日

一个 Docker 容器搞定双 VPN 隧道自动分流

问题

公司有开发和生产两套 VPN 环境,经常需要同时连。但 VPN 客户端一次只能连一个,来回切换很烦,而且 VPN 一连上就把本机路由全改了,影响其他网络。

思路

把 VPN 隧道关进 Docker 容器里:

本机 → SOCKS5 代理(:1080) → 容器内部
                              ├── 开发 VPN 隧道 → 开发内网
                              └── 生产 VPN 隧道 → 生产内网

容器内跑两个 OpenVPN 客户端 + 一个 SOCKS5 代理(microsocks),用 Linux 路由表自动分流。

核心实现

路由分流

这是最巧妙的部分——利用 Linux 内核路由表,根据目标 IP 自动选择走哪条隧道:

# 开发环境网段走 tun0(开发 VPN)
ip route add 10.10.0.0/16 via $DEV_GATEWAY dev tun0

# 生产环境网段走 tun1(生产 VPN)
ip route add 10.20.0.0/16 via $PROD_GATEWAY dev tun1

应用层完全不需要关心路由,发给 SOCKS5 代理后内核自动选路。

DNS 同步

VPN 连接时会推送内部 DNS 服务器,需要同步到容器的 resolv.conf:

# 从 OpenVPN 的 up 脚本中获取推送的 DNS
echo "nameserver $DNS_DEV" > /etc/resolv.conf
echo "nameserver $DNS_PROD" >> /etc/resolv.conf

这样在容器内可以直接解析 db.dev.internal 这类内网域名。

Docker Compose

services:
  vpn-proxy:
    build: .
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun
    ports:
      - "1080:1080"
    volumes:
      - ./dev.ovpn:/etc/openvpn/dev.ovpn
      - ./prod.ovpn:/etc/openvpn/prod.ovpn

NET_ADMIN/dev/net/tun 是 VPN 容器的必要权限。

使用方式

本机配好 SOCKS5 代理后,所有工具都能直连内网:

# SSH 通过代理连开发服务器
ssh -o ProxyCommand="nc -x 127.0.0.1:1080 %h %p" dev-server

# Clash 中配置上游代理
# 浏览器直接访问内网地址

也可以在 Clash 里加一条规则,内网网段自动走这个 SOCKS5 代理,其他流量正常出去。

优势

  • 不污染宿主机路由表:VPN 隧道完全封装在容器内
  • 双隧道同时在线:不用来回切换
  • 一个端口搞定:所有内网访问统一走 1080 端口
  • Alpine 镜像很小:容器只有几十 MB

总结

这个方案的精髓在于把 VPN 当成”容器内部的网络基础设施”,而不是宿主机的全局网络变更。Linux 路由表的优先级机制天然支持多隧道分流,不需要任何额外的分流软件。

评论