Docker Compose中VPN后端镜像无法在局域网访问的问题
我有四个Docker服务:vpn_img1和vpn_img2依托VPN服务部署,host_img1和host_img2直接使用主机网络。目前在主机上能通过http://localhost:<port_num>访问所有四个服务,但局域网内其他机器只能访问host_img系列,vpn_img系列会超时,换其他VPN镜像也存在同样问题。另外host_img1需要和vpn_imgs通信,host_img2不需要。
我的docker-compose配置如下:
version: "3.4" services: vpn: container_name: vpn image: ghcr.io/bubuntux/nordlynx restart: unless-stopped cap_add: - NET_ADMIN environment: - PRIVATE_KEY=xxx - QUERY=filters\[country_id\]=228 - NET_LOCAL=192.168.1.0/24 # - ALLOWED_IPS=192.168.0.0/24 ports: - 1234:1234 # vpn_img1 - 2345:2345 # vpn_img2 sysctls: - net.ipv6.conf.all.disable_ipv6=1 vpn_img1: container_name: vpn_img1 image: vpn_img1 restart: unless-stopped network_mode: service:vpn # run on the vpn network depends_on: - vpn vpn_img2: container_name: vpn_img2 image: vpn_img2 restart: unless-stopped network_mode: service:vpn # run on the vpn network depends_on: - vpn host_img1: container_name: host_img1 image: host_img1 restart: unless-stopped network_mode: host host_img2: container_name: host_img2 image: host_img2 restart: unless-stopped network_mode: host
原因分析
- VPN容器的默认路由规则会把所有出站流量导向VPN隧道,包括局域网请求的响应流量。当局域网机器访问主机映射的1234/2345端口时,请求能抵达VPN容器,但响应流量会被强制发往VPN隧道,无法回到局域网,最终导致超时。
- 你配置的
NET_LOCAL=192.168.1.0/24仅能让VPN容器主动访问局域网,无法解决局域网反向访问VPN容器服务的路由问题。
解决方法
1. 调整VPN容器路由,放行局域网响应流量
针对bubuntux/nordlynx这类VPN镜像,可通过ALLOWED_IPS环境变量指定不走VPN隧道的IP段,让局域网响应流量正常返回。
修改vpn服务的环境变量:
environment: - PRIVATE_KEY=xxx - QUERY=filters\[country_id\]=228 - NET_LOCAL=192.168.1.0/24 - ALLOWED_IPS=0.0.0.0/0,192.168.1.0/24
这里0.0.0.0/0保证常规出站流量走VPN,192.168.1.0/24会被优先匹配,局域网相关流量直接走主机本地网络,不进入VPN隧道。
2. 确保主机防火墙允许端口转发
检查主机防火墙(如ufw、iptables)是否开放1234、2345端口的入站流量,同时启用IP转发:
- 若用ufw:
sudo ufw allow 1234/tcp sudo ufw allow 2345/tcp sudo ufw allow in on docker0 to any port 1234,2345 sudo sysctl -w net.ipv4.ip_forward=1 - 若用iptables:
sudo iptables -A INPUT -p tcp --dport 1234 -j ACCEPT sudo iptables -A INPUT -p tcp --dport 2345 -j ACCEPT sudo iptables -A FORWARD -i eth0 -o docker0 -p tcp --dport 1234 -j ACCEPT sudo iptables -A FORWARD -i eth0 -o docker0 -p tcp --dport 2345 -j ACCEPT
3. 实现host_img1与vpn_imgs的通信
因为host_img1用network_mode: host,vpn_img1/2共享vpn容器网络,可通过两种方式实现通信:
方式一:在vpn容器的ports配置中指定主机的局域网IP,让host_img1直接访问该IP的对应端口:
ports: - 192.168.1.xxx:1234:1234 - 192.168.1.xxx:2345:2345之后host_img1可通过
http://192.168.1.xxx:1234访问vpn_img1。方式二:创建自定义Docker网络,让vpn容器和host_img1加入该网络(host_img1不再使用
network_mode: host),通过容器名互相访问:version: "3.4" networks: local_net: driver: bridge ipam: config: - subnet: 172.20.0.0/16 services: vpn: # 保留原有其他配置 networks: - local_net ports: - 1234:1234 - 2345:2345 vpn_img1: # 保留原有其他配置 network_mode: service:vpn # 继续共享vpn网络 vpn_img2: # 保留原有其他配置 host_img1: container_name: host_img1 image: host_img1 restart: unless-stopped networks: - local_net host_img2: # 保持network_mode: host不变此时host_img1可通过
vpn:1234访问vpn_img1服务。
内容的提问来源于stack exchange,提问作者taynaron

