Docker Sidecar VPN 更Dockerize的透明代理

大类
Util
Env
技术标签
环境增强
优先级
High
状态
Maintaining
开始日期
Aug 17, 2025
最后更新
Aug 17, 2025
Public
Public

TL;DR:

自定义下面的配置即可,注意:
  • 需要填入./clash-conf,并开启tun
  • 注意clash容器的名称不可修改,否则需同步修改下面的脚本
  • 修改command属性中的最后一条命令为相应image的CMD
  • 应用的image中需要带有ip命令(或许也可以放一个静态编译的iproute2)
  • 有可能需要配置sysctl -w net.ipv4.conf.all.rp_filter=2
version: '3.8' services: clash: image: metacubex/mihomo:v1.18.3 restart: always devices: - /dev/net/tun networks: vpn-net: volumes: - ./clash-conf:/root/.config/mihomo cap_add: - NET_ADMIN s: depends_on: - clash init: true networks: lan-net: vpn-net: cap_add: - NET_ADMIN command: | sh -euxc ' sleep 2 gw=$(getent hosts clash | awk "{ print \$1 }" || true) if [ -z "$$gw" ]; then echo "ERROR: failed to resolve clash" >&2 exit 1 fi echo "Resolved clash to $$gw" ip a ip r ip route del default || true ip route add default via $$gw exec bash -x /root/start.sh' sysctls: - "net.ipv6.conf.all.disable_ipv6=1" # Service custom properties image: XXXXXX restart: always networks: vpn-net: driver: bridge lan-net: driver: bridge
 

现有方案的缺点:

  • 方案1:在宿主机上开tun
    • 不共享netns,导致宿主机无法区分流量来源
    • 配合fwmark可以实现区分,但是由于docker没法自己自动打fwmark,维护代价太高
    • 配合固定ip也可以区分,但是这样需要自主管理docker的ip池分配,维护代价也不低
  • 方案2:network-mode: container:XXX
    • 使用这个方法共享netns,只能在XXX上设置expose
    • 多个容器共享ip地址,无法多次bind同一个端口
  • 方案3:在容器内开vpn
    • 增加镜像大小和复杂度,难以长期维护
  • 方案4:Custom Network Plugin (Network Driver)
    • yassine/soxy-driver、vincent-163/docker-transparent-socks5
    • 长期未更新(7年)、无大规模应用
    • 需要自定义network driver,可能与docker compose兼容不好
    • 使用的是redsocks,基于iptables而不是tun,在复杂网络环境下效果可能不如clash/sing-box的tun方案

原理:

  • 同时连接到2个network,一个起到compose default network的作用(lan-net),一个专门用于与vpn连接(vpn-net)
    • (或许可以只有1个network,但这样不容易debug)
  • clash启动tun,应用的service则通过command中的小脚本根据hostname解析clash并自动设置gateway
  • 这样无需配置任何固定ip段、固定ip地址,且仍然可以正常使用expose等功能