UFW也会限制Discourse吗?

Discourse 如何绕过 UFW?我只启用了 22 端口,所以所有其他端口都应该关闭。但论坛还是可以正常工作。这是怎么回事?

DigitalOcean 虚拟机,但这应该不重要。并且不是一键安装,而是官方方式。

这不是纯粹的支持问题,但我们这里没有一个名为“新手愚蠢的基础问题”的类别 :wink:

7 个赞

那么,如果你运行 ufw status verbose,你只会看到 sshd?

1 个赞

没错。并且 UFW 已启用。

1 个赞

运行 ufw status verbose 时,默认列出了什么?

对于我认为您想要的,我应该看到这个:
默认值:拒绝(入站),允许(出站),禁用(路由)

根据您描述的行为,我应该看到这个:
默认值:允许(入站),允许(出站),禁用(路由)

1 个赞

您是否尝试过在隐身窗口或不同的浏览器中打开论坛?缓存的版本很容易被欺骗。我自己也曾被欺骗过,另一位开发人员告诉我暂存网站看起来不错,但实际上根本没有运行。

1 个赞

只有 22/tcp (OpenSSH) ALLOW IN Anywhere,这本应如此。这两件事我一直都做:允许 OpenSSH 并启用 UFW。

我只在需要时才打开端口,例如安装 Nginx 时。但由于该 VPS 仅用于 Discourse,我没有做其他任何事情——我完全忘记了 UFW。

那不可能是原因。那个论坛已经运行了好几个星期了。

当我将 Nginx/Varnish 连接到该 VPS 并需要打开另一个端口时,我才意识到这种情况——我发现唯一打开的是端口 22。

编辑:
我怎么能发送电子邮件?端口 587 也没有打开 :flushed_face:

这真的很奇怪。

1 个赞

我不清楚你是在说默认设置是拒绝还是不是。我之所以专门问“Default”这一行,是因为有可能同时设置默认允许和允许特定端口,尽管在那种情况下后者不会改变任何东西。

如果是由其他人设置的 Discourse,那个人是否有可能将默认设置更改为允许,而不是允许 HTTP/HTTPS 端口?

我假设这是在其他地方的 SMTP,你的 Discourse 服务器使用端口 587 连接到该 SMTP 服务器。默认情况下,所有端口的出站连接都允许,所以除非你明确更改出站策略,否则 UFW 不会妨碍发送电子邮件。

4 个赞

我的错 :man_facepalming:

Default: deny (incoming), allow (outgoing), deny (routed)

不。但是 allow (outgoing) 是否允许任何出站流量?如果允许,那么我们就回到了“我们这里没有一个名为初学者愚蠢的基本问题的类别”并且我学到了新东西。

编辑:

我仍然很困惑——但是 deny (incoming) 是怎么回事?

2 个赞

我发现了这个:

2 个赞

简而言之,Discourse 无法绕过您的防火墙规则,而关于 os 的愚蠢问题应该去 Stack Exchange 之类的地方提问。(请不要认为我无礼。答案就在那里。自从最早的版本开始运行 Linux 以来,我仍然会去这些地方问我所有愚蠢的问题。我仍然有这些问题!)

3 个赞

我知道那个地方 :wink: 信号/噪音比太高了。嗯,那是一个不公平的描述,但我的意思是,很难从中找到相关的东西。它太庞大了。

2 个赞

这是一个非常好的问题,我很惊讶其他人还没有问过。答案很复杂,但到目前为止,关于这个话题的回答语气都很轻蔑,而没有回答问题。

并不是 Discourse 在绕过 ufw,而是 docker 通过添加规则来绕过 ufw,这些规则使得 docker 容器的任何暴露端口都能正常工作,尽管存在 ufw

发生了什么?

发往容器的入站数据包会命中 FORWARD 表,而不是人们可能期望的 INPUT 表。

安装 docker 之前

Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ufw-before-logging-forward  all  --  any    any     anywhere             anywhere            
    0     0 ufw-before-forward  all  --  any    any     anywhere             anywhere            
    0     0 ufw-after-forward  all  --  any    any     anywhere             anywhere            
    0     0 ufw-after-logging-forward  all  --  any    any     anywhere             anywhere            
    0     0 ufw-reject-forward  all  --  any    any     anywhere             anywhere            
    0     0 ufw-track-forward  all  --  any    any     anywhere             anywhere

安装 docker 之后

Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    8   416 DOCKER-USER  all  --  any    any     anywhere             anywhere            
    8   416 DOCKER-ISOLATION-STAGE-1  all  --  any    any     anywhere             anywhere            
    0     0 ACCEPT     all  --  any    docker0  anywhere             anywhere             ctstate RELATED,ESTABLISHED
    4   256 DOCKER     all  --  any    docker0  anywhere             anywhere            
    4   160 ACCEPT     all  --  docker0 !docker0  anywhere             anywhere            
    0     0 ACCEPT     all  --  docker0 docker0  anywhere             anywhere            
    0     0 ufw-before-logging-forward  all  --  any    any     anywhere             anywhere            
    0     0 ufw-before-forward  all  --  any    any     anywhere             anywhere            
    0     0 ufw-after-forward  all  --  any    any     anywhere             anywhere            
    0     0 ufw-after-logging-forward  all  --  any    any     anywhere             anywhere            
    0     0 ufw-reject-forward  all  --  any    any     anywhere             anywhere            
    0     0 ufw-track-forward  all  --  any    any     anywhere             anywhere

数据包命中 forward 表的原因是 docker 添加到 nat 表的规则:

Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  210 12734 DOCKER     all  --  any    any     anywhere             anywhere             ADDRTYPE match dst-type LOCAL

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 RETURN     all  --  docker0 any     anywhere             anywhere            
    0     0 DNAT       tcp  --  !docker0 any     anywhere             anywhere             tcp dpt:https to:172.17.0.2:443
  107  6848 DNAT       tcp  --  !docker0 any     anywhere             anywhere             tcp dpt:http to:172.17.0.2:80

nat/PREROUTING 在决定是发送数据包通过 INPUT 还是 FORWARD 之前就被处理了。

最终问题在于系统上有两个服务在修改防火墙规则。ufw 对这一切一无所知,所以它只能报告它配置了什么。

解决方案

重新配置防火墙,将发往 docker 的流量也通过 ufw 链:

我使用他们工作的一个轻微改编版本,在启用 ufw 之前进行设置:

# 盗用自 https://github.com/chaifeng/ufw-docker - 看起来很合理
# 将转发添加到 ufw-user-input 允许连接到
# 我们明确打开的转发端口
cat <<EOUFW >> /etc/ufw/after.rules
# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-user-input - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16

-A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN

-A DOCKER-USER -j ufw-user-forward
-A DOCKER-USER -j ufw-user-input

-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16

-A DOCKER-USER -j RETURN
COMMIT
# END UFW AND DOCKER
EOUFW
20 个赞

谢谢!这是一个完整的解释。

4 个赞

欢迎,我就是这样做的 :smiley:

6 个赞

此主题已解决,但它暴露了我设置的一个小问题。如果将来有人搜索类似内容,我会解释一下。

我有一个 VPS,Nginx 负责处理我所有网站(有很多奇怪的英语用法 ;))的 SSL 和其他一些事务。Nginx 将请求发送到 Varnish。对于 Discourse 来说,它是一个无用的反向代理,但它会进行一些过滤。Varnish 通过 83 端口将请求发送到另一个运行 Discourse 的 VPS。两个 VPS 都监听相同的端口,并且只允许这两个 IP 访问。我一直很满意——直到现在。

我尝试了使用 443 端口会发生什么 curl -I https://forum.example.tld:443。它运行得很好,因为 Discourse 端仍然有一个有效的 SSL 证书(我几周前做的更改)。

@supermathie 的回答解释了为什么会发生这种情况以及如何修复它。当然,据我所知,这根本不存在安全问题,但它确实很烦人 :squinting_face_with_tongue:

2 个赞

哇。这真是太疯狂了!谢谢。

我猜之所以没人问,是因为很少有人安装 Discourse 后又希望它工作,所以当 Docker 在你已经配置了防火墙但它本不应该工作的情况下让它工作时,大多数人都不抱怨。:wink:

这是一个非常有趣的问题,但它似乎有点晦涩难懂,而且这不是 Discourse 的问题,而是 Docker 的怪癖。问题归结为“我该如何配置我的防火墙来阻止 Discourse 工作?”我会努力记住那个 prerouting 的东西。

如果我知道答案,我就不会那么不友好了!:wink: 感谢你在这件事上力挽狂澜!

6 个赞

我当然不是想不礼貌,而是想解决问题……不过显然我对 Docker 的运作方式一无所知。这些信息都非常有价值,感谢您的回答!

如果 OP 或其他人能够更改它,那么更改标记的解决方案可能会有价值。

虽然这更多是 Docker 的问题,但我可以看到一些由此产生的 Discourse 的假设情况。例如,我可能有一个可以从外部访问的办公室服务器,但我想配置 UFW 将 Discourse 限制为只能从办公室内部访问。Docker 的添加会阻止这种设置。

不过在这种特定情况下,我会在硬件/虚拟机管理程序防火墙上进行设置,而不是在主机上的 UFW 上进行设置。

5 个赞

我刚来到你发现的同一个git仓库,正在研究一个ufw/docker问题,这让我想起了这个话题。

你具体改了什么(我的意思是,我能看到添加的行,但这是什么意思?),这些改动是专门针对Discourse的吗?

我使用了仓库中的默认代码,之后我的UFW问题似乎得到了解决。

编辑:当我使用你修改过的代码时,第一次执行ufw reload时,我得到以下错误:

错误:无法加载日志规则

1 个赞

实际上,过了一会儿我才弄明白,并编写了这个 bash 脚本来完成 Discourse 安装的任务。

它会重置你的防火墙,安装 ufw-docker-util(该工具会编辑 after.rules),然后将端口 443 和 80 添加到你的允许列表中。搞定。

它还允许来自任何 IP 的端口 22,以确保你不会被锁定。在一切正常工作后,再次保护端口 22。

编辑:脚本确实有效,但在使用它之后重建 Discourse 会失败:fatal: unable to access 'https://github.com/discourse/discourse.git/': Could not resolve host: github.com - 因此,除非你知道如何解决这个问题,否则请勿使用该脚本。

编辑 2:在 Ubuntu 上有效,但在 CentOS 上无效!

3 个赞

上次我写 bash 脚本时,将所有目录的所有者更改为 www-data:www-data — 所以对我来说,像这样的工作能让生活轻松一点 :wink:

但总的来说——我希望看到 docker 完全遵循 UFW/iptables。仅仅因为我通过 ipables 使用 GeoIP 阻止(是的,我知道——UFW 只是 iptables 的极简 UI)。

当然,我们不再使用 Discourse 了,但在这里我们可以看到为什么编码人员和最终用户总是不能很好地理解对方:编码人员将世界视为逻辑块和 if/then/else 结构,而最终用户将其视为完整的上下文。意思是——因为我使用 Discourse,即使它在 docker 中运行,从我的角度来看,是 Discourse 不遵守我的规则 :rofl:

这应该放在 Praise 里,但我几周前更改了论坛的 url。我吸引了世界上所有的脚本小子和无用的搜索引擎机器人来访问。我在 DigitalOcean 的 2 GB/1 vcpu VPS 上每小时有 3000 个不同的用户代理,而 Discourse 根本不在乎。任何 WordPress 安装在这种类型的 ddos 冲击下都会变慢/崩溃。

所以,我不需要强迫 discourse(嗯,docker)遵循 Fail2ban 的禁令和我的规则——但我非常讨厌那些机器人。

3 个赞