我在一个docker-compose文件中有四个服务。vpn_img1和vpn_img2在vpn后面(如下所述配置),host_img1和host_img2不在后面。
我可以通过http://localhost:<port_num>
访问主机上的所有四个“img”服务,但只能访问本地网络上其他机器上的“host_img”映像;“vpn_img”映像超时。我得到相同的结果与其他类似的VPN图像。有人知道为什么吗?vpn服务上是否有允许访问“vpn_img”映像的任何设置?我还需要做些什么来实现这种访问吗?
此外,host_img1需要与vpn_imgs对话,但host_img2不需要。
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
字符串
1条答案
按热度按时间ecr0jaav1#
问题的关键应该是VPN服务只允许来自主机(VPN客户端正在运行)的流量:本地网络上的其他机器无法访问VPN后面的服务。
它们的网络可访问性仅限于与VPN服务相同的范围。
由于安全原因,VPN (Virtual Private Network)服务本身倾向于将网络流量限制为仅通过VPN隧道,从而使其后面的服务无法从外部访问,除非另有特别配置。
当一个容器使用另一个容器的网络堆栈时,它实际上就“隐藏”在那个服务后面。该容器的所有传入和传出网络流量都经过主服务的网络,在本例中,该网络是VPN服务。这就是为什么您可以从主机(VPN客户端正在运行的位置)访问
vpn_img1
和vpn_img2
服务,而不能从本地网络中的其他计算机访问的原因。您可以尝试使用可以从本地网络访问的反向代理,并将请求转发到VPN保护的服务。
在Docker Compose文件中为反向代理设置一个新服务。您可以使用类似Nginx或Traefik的代码。该服务不应该在VPN后面。
配置反向代理将请求转发到
vpn_img1
和vpn_img2
。对于Nginx,您可以使用proxy_pass
指令。并确保代理的端口正确转发,以便您可以从本地网络访问它。请注意,
vpn_img1
和vpn_img2
仍然在VPN后面,它们建立的任何连接都将通过它。但是,其他服务可以通过反向代理访问它们,该代理不在VPN后面。
例如,使用NGiNX:
字符串
并且,与
docker-compose.yml
文件位于同一目录的nginx.conf
文件应该是:型
nginx
服务处于bridge
网络模式,因此它可以访问本地网络,并且还能够访问vpn
服务,因为它也处于bridge
模式。proxy_pass
指令被设置为http://vpn:<port>/
,因为Nginx需要将请求发送到vpn
服务,该服务将它们转发到vpn_img
服务。<host_ip>
是运行Docker的机器的IP地址。这意味着您应该能够从本地网络中的任何机器访问
http://<host_ip>:8000/vpn_img1/
上的vpn_img1
服务和http://<host_ip>:8000/vpn_img2/
上的vpn_img2
服务。不幸的是,nginx无法启动,日志抛出
host not found in upstream "vpn" in /etc/nginx/nginx.conf:8
,这是第一个proxy_pass
命令所在的位置(如果我注解掉第一个位置块,我在第12行,下一个proxy_pass
命令中得到相同的错误)。我已经确保VPN和Nginx都有network_mode:bridge,并尝试将
vpn_img1
和vpn_img2
添加到nginx的depends_on部分。错误
host not found in upstream "vpn"
通常意味着Nginx容器无法将主机名vpn
解析为IP地址。在这种情况下,这意味着Nginx无法找到您的vpn
服务。这通常是因为Docker内部DNS服务器无法将服务名称解析为其IP地址。
network_mode: service:<name>
有点特殊,因为它将依赖服务放置在指定服务的网络堆栈中,而不是公共网络中。这就是为什么nginx
服务不能直接到达vpn
服务,即使它们都处于桥接网络模式。nginx
服务位于默认网桥网络中,而vpn
服务由于network_mode: service:vpn
而被隔离在自己的网络堆栈中。一个潜在的解决方案是创建一个自定义网络,并确保所有服务都在该网络上,如suggested in this thread:
型
nginx.conf
:型
这种方法将
vpn
、vpn_img1
、vpn_img2
和nginx
服务都放在同一个自定义网桥网络上,允许它们直接通信。这应该可以解决
host not found in upstream "vpn"
错误。现在
host_img1
和host_img2
无法找到vpn_img1
和vpn_img2
。代理似乎有了一个良好的开端:
http://<ip_addr>:8000/vpn_img1/
本身返回200,但它的所有内容和子页面返回404。host_img1
和host_img2
服务中的network_mode: host
意味着这些服务可以访问主机的网络堆栈,从而绕过Docker提供的隔离。因此,它们不是custom_network
的一部分,不能直接与vpn_img1
和vpn_img2
服务通信。从
nginx
反向代理的404错误来看,这可能是因为一些资源(如脚本,样式表,图像等)是用绝对路径请求的,而Nginx没有配置为正确处理这些请求。首先,尝试将
host_img1
和host_img2
的network_mode: host
更改为networks: - custom_network
,如果这些服务不一定需要在主机的网络堆栈中。如果由于某种原因这些服务仍然需要在主机的网络堆栈中,请考虑在
vpn_img1
和vpn_img2
容器中添加另一个网络接口以连接到custom_network
。其次,对于
nginx
404问题,您可能需要根据vpn_img1
和vpn_img2
服务的设置方式调整nginx
配置。如果这些服务返回具有绝对路径的资源(如/styles/main.css
),则需要添加另一个位置块来处理这些路径。如果可能,请考虑在vpn_img1
和vpn_img2
服务中将这些路径更改为相对路径。例如,
nginx.conf
可以是:型
即使给定位置的
/
文件也会得到404;因此/index.html
或/gettext.js
返回404。看来我得好好研究一下我的NGiNX了。有什么想法/建议吗?
这里的问题可能与您所代理的应用程序如何解释传入请求有关。
例如,对
<ip_address>:8000/vpn_img1/index.html
的请求将被转发到http://vpn_img1:1234/index.html
。现在,如果您的
vpn_img1
服务设置为希望位于根目录(/
),则它可能会尝试从绝对路径(如/styles/main.css
或/script/main.js
)加载资源。这可能会导致nginx
返回404,因为它未配置为处理对这些路径的请求。要解决此问题,可以在将请求代理到相应的服务之前,从请求URI中去掉路径前缀(
/vpn_img1
或/vpn_img2
)。另请参阅“Guide on how to use regex in Nginx location block section“。
型
在这里,正则表达式与
location
匹配,并且/vpn_img1/
或/vpn_img2/
之后的任何路径都被捕获到$1
变量中。然后,该值将用于proxy_pass
指令中。现在,对<ip_address>:8000/vpn_img1/index.html
的请求将被转发到http://vpn_img1:1234/index.html
,并且index.html
从根请求的任何资源也将被正确地代理到http://vpn_img1:1234/
。只要
vpn_img1
和vpn_img2
所服务的应用程序使用相对路径来引用应用程序中的其他资源,这种方法就应该有效。如果它们使用绝对路径(例如,使用/styles/main.css
而不是styles/main.css
),则仍可能存在问题,您需要修改应用程序以使用相对路径。我正在购买502,其中包含最新的
nginx.conf
(以及类似的):型
我无法想象这是一个 Docker 作曲的问题,但我不知道还能剩下什么。
"no resolver defined to resolve vpn_img1"
:这应该表明Nginx无法将主机名vpn_img1
解析为IP地址。这是因为Nginx不使用系统解析器,它是uses its own DNS resolution implementation。要解决这个问题,您可以在Nginx配置中显式指定DNS解析器。它可以是本地网络的DNS服务器,也可以是公共的DNS服务器,如Google的DNS服务器
8.8.8.8
。您应该将
resolver
指示词加入http
区块中,就在server
区块之前,在nginx.conf
中:型
在上面的配置中,使用
resolver 127.0.0.11
是因为Docker有一个内置的DNS服务器,它在该IP地址运行,用于为容器提供DNS解析。这应该有助于Nginx将容器名称解析为各自的IP地址。插图/故障排除:“Docker Network Nginx Resolver“的字符串。另请参阅Adriano Galello中的“如何连接Docker容器”,了解有关Docker DNS服务的更多信息。和“docker-compose internal DNS server 127.0.0.11 connection refused“(如果有问题)。
OP在评论中确认:
在
location
块中添加该解析器和rewrite /vpn_app1(.*) $1 break; proxy_set_header <hostname> "/vpn_app1/";
(根据文档)就做到了!最终的Nginx配置如下所示:
型
使用此配置时,对
/vpn_img1/...
和/vpn_img2/...
的传入请求在传递到相应的服务之前会被重写为/...
。proxy_set_header Host $host;
行确保传入HTTP请求的主机头被转发到代理服务器。