我正在尝试在带有 nginx 反向代理的 docker 容器中设置一个简单的 Web 应用程序(不是在容器中,而是在主机上)。
这是我运行容器的方式:
docker run -d --name mywebapp -v /webapp/:/data/ --restart unless-stopped -p 5665:80 mywebapp/server:latest
Web 应用程序侦听容器内的端口
80
,我将其转发到 5665
主机端口。
nginx反向代理监听端口
5666
并将请求转发到转发的容器端口5665
。
netstat -lntup
输出(仅相关行):
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:5666 0.0.0.0:* LISTEN 29369/nginx: master
tcp 0 0 0.0.0.0:5665 0.0.0.0:* LISTEN 151974/docker-proxy
我想配置防火墙阻止除
5666
端口之外的所有外部连接。
这是我的
nftables
规则(精确复制,没有删除任何内容):
define IIFNAME = "ens3";
table inet filter {
chain input {
type filter hook input priority filter
policy drop
ct state invalid drop comment "early drop of invalid connections"
ct state {established, related} accept comment "allow tracked connections"
iifname lo accept comment "allow from loopback"
ip protocol icmp accept comment "allow icmp"
meta l4proto ipv6-icmp accept comment "allow icmp v6"
tcp dport ssh accept comment "allow sshd"
tcp dport 5666 accept comment "webserver";
pkttype host limit rate 5/second counter reject with icmpx type admin-prohibited
counter
}
chain forward {
type filter hook forward priority filter
policy drop
iifname "docker0" oifname $IIFNAME accept;
iifname $IIFNAME oifname "docker0" accept;
}
我可以连接到端口
5666
,这是预期和期望的。
然而,问题是,尽管与 5665
端口的连接被阻止(至少我是这么认为的),我仍然可以连接到 5665
端口,绕过 nginx 反向代理。
经过一番尝试和错误,我发现问题出在“前向”链规则上,即:
iifname "docker0" oifname $IIFNAME accept;
iifname $IIFNAME oifname "docker0" accept;
删除这些规则可以解决此问题,但也会阻止容器访问互联网。
我的两个问题:
为什么“转发”规则很重要?我认为“转发”规则仅适用于数据包应该由另一台机器(或容器)接收时。然而,
5665
端口正在通过docker-proxy
监听当前主机端口。即使数据被“转发”到容器,它也不是由内核转发的,而是由用户空间应用程序转发的 - docker-proxy
,所以我希望内核使用 INPUT
链而不是 FORWARD
链。然而,似乎FORWARD
规则确实很重要。
(也许有了上一个问题的答案,这个问题的答案就很清楚了,但我还是会问它) 如何阻止从外部(从
5665
接口)对转发的 ens3
端口的访问,同时允许容器访问互联网(即通过主机上的 ens3
接口发出请求)?
Docker 使用防火墙来路由流量,因此使用防火墙来限制访问可能会造成混乱。
一个更简单的解决方案是使用
... -p 127.0.0.1:5665:80
将 docker 显式绑定到本地主机接口。 默认情况下,如果没有地址,docker 将监听所有接口,但在这种情况下你不希望这样。