如何在 Apache vhost 中运行 Discourse,而非 Nginx

有人成功在 Apache 虚拟主机上部署 Discourse,而不是默认的 Nginx 吗?

看起来这些论坛上关于 Apache 的讨论大多集中在“在已运行 Apache 的主机上部署 Discourse”。在我所见的所有案例中,人们只是将 Apache 反向代理到 Nginx。明确一下:我希望运行 Discourse 的 Docker 后端容器在 Apache 中运行虚拟主机,而不是 Nginx。

具体来说,我希望在 Apache 中运行 Discourse 后端,以启用 mod_security。在 Nginx 中配置 mod_security 需要从源码编译 Nginx,这是我希望避免的复杂性。

我当前的生产服务器已经运行了多个站点(WordPress、MediaWiki 等)。我们使用 Nginx 终止 HTTPS 并进行一些基本的 DOS 速率限制 → Varnish 缓存 → 带有 mod_security 的 Apache 后端。如果可能,我希望为 Discourse 保留这种架构——即后端 Discourse Docker 容器运行带有 mod_security 的 Apache,而不是 Nginx。

有人成功在 Apache 中部署 Discourse 吗?

抱歉,我刚接触 Docker。我真的很困惑,不知道 ‘/etc/nginx/conf.d/discourse.conf’ 文件是如何被放入 Docker 容器中的。能否有人阐明一下 ‘./launcher’ 脚本生成该文件并将其放入容器的具体步骤?

编辑:等等,Discourse 是否已经在从源码编译 Nginx 了?

没有,没有人成功过。Discourse 与 nginx 紧密绑定。要将其替换为 Apache 非常困难,甚至不可能。而且,由于只有你一个人在做这件事,一旦出现问题,其他人也不会关心。

直接使用全球所有人都在使用的 Docker 容器,如果你认为这样能提升安全性,可以在其前面加上 Apache。

看起来确实如此。

看起来 /etc/nginx/conf.d/discourse.conf 文件是通过模板文件 /var/docker/templates/web.template.yml 在容器中生成的——该模板从 $home/config/nginx.sample.conf 复制文件到相应位置,然后通过 replace 的 YAML 块进行修改(这些修改会在后续模板中进一步更新,例如 templates/web.socketed.template.yml)。

我原本以为 nginx.sample.conf 文件是在 image/base/install-nginx 中从源码编译 Nginx 时直接安装到容器中的。但我在容器中找到的唯一 nginx.sample.conf 文件(位于 /var/www/discourse/config/nginx.sample.conf)已经包含了 Discourse 特有的指令。

那么 nginx.sample.conf 究竟是从哪里来的?

我可不想看到 Nginx → Varnish → Apache → Nginx 这样的架构 :slight_smile:

明确一下:你认为我是应该更新 ‘image/base/install-nginx’ 脚本,以便在 Discourse Docker 容器中从源代码编译带 mod_security 支持的 Nginx,还是应该更新容器,让 Discourse 的虚拟主机在 Apache(而不是 Nginx)后面运行?如果是前者,我修改 install-nginx 脚本会有哪些风险?这未来可能导致我的 Discourse 安装出现什么问题?

PSA:你们提议的所有操作,虽然在技术上可行,但完全不受支持。我们无法合理地为人们提出的每一种在 Web 上部署 Discourse 的组合提供支持。因此,本论坛的支持仅限于按照 discourse/docs/INSTALL-cloud.md at main · discourse/discourse · GitHub 指南进行的安装。

最终,这会在很多方面导致问题。你将不得不持续合并上游的变更,并永久维护你自己的分支。

太好了,谢谢!哇,这完全是另一个仓库。容器是如何从另一个仓库获取该文件的?是在这里吗?

$home 又是什么?

您可以阅读源代码以找到所有这些以及更多内容,地址为 discourse_docker/image/base/Dockerfile at master · discourse/discourse_docker · GitHub

我按如下方式配置了 app.yml(Discourse):
expose:
- "2045:80" # http
- "8443:443" # https

… 我的 vhost 配置如下:
<VirtualHost *myhostIP*:443>
ServerName forum.domain.org
ServerAlias forum.domain.org
...
ProxyAddHeaders Off
ProxyPass / "http://localhost:2045/"
ProxyPassReverse / "http://localhost:2045/"
</VirtualHost>

希望我没有误解您的问题 :blush:

@ledimeo 这正是 @pfaffman 的建议,我也认为在这种情况下这样做更好,以免在未来发布新版本时造成严重问题。但看起来他已经在前面使用了另一个 nginx 作为反向代理,并不希望:

话虽如此,我认为将 Apache 反向代理到 Nginx(即使最终会有这四层)至少比试图更改官方安装中 Discourse 的工作方式更具可维护性。

为此,你基本上应该把 nginx 当作 Docker 容器“黑盒”内部的一部分,无需过多关注它。

所以:nginx → varnish → apache → Discourse(包含 nginx 和 unicorn)

(除了配置它信任上游代理 IP 的情况)

因此,将 Apache 作为 Discourse 的 Nginx 反向代理绝对是一个可行的方案。

我同意,这样做的好处是未来升级会更轻松,这一点很重要。

但在架构中增加一个跳点不仅会使未来的问题排查变得更加复杂——我还担心 Apache 作为使用长轮询(long polling)的 Web 应用的反向代理时的性能表现,正如 @sam 在 2016 年的这篇帖子中指出的那样。

我通常更喜欢 Nginx 而不是 Apache,除非涉及到 mod_security。如果操作系统仓库能提供像 Apache 那样的 mod_security 支持包,那将非常理想,但目前要在 Nginx 上启用 mod_security,需要在 RHEL/CentOS 和 Debian 上从源码编译 Nginx。而在生产环境中,我尽量避免依赖从源码编译的包,这就像躲避瘟疫一样。

相关:我一直在研究 install-nginx 脚本,发现了一个小逻辑错误:本应删除 /tmp/ 中 nginx 源代码的清理行实际上没有任何作用。

不存在 /tmp/nginx/ 目录:它是 /tmp/nginx-$VERSION/(目前是 /tmp/nginx-1.17.4/,同时还有 tarball 文件 /tmp/nginx-1.17.4.tar.gz)。

我认为你应该是想写这个:

rm -fr /tmp/nginx-${VERSION}*

不幸的是,当我运行 /var/discourse/launcher destroy app && /var/discourse/launcher rebuild app 时,我更新的 /var/discourse/image/base/install-nginx 脚本似乎并未被执行。

是否有任何原因导致该 rebuild 命令不会重新执行更新后的 install-nginx 脚本?

重建后你是如何修改脚本的?通过钩子吗?

vim /var/discourse/image/base/install-nginx

重建后您还能看到您的更改吗?直接编辑镜像中的文件是行不通的。

您需要使用 hooks 从您的 app.yml 中修改文件。

您之前接触过 Docker 吗?

如果您不熟悉 Docker,这将是一条艰难的道路……

discourse_docker 包含我们基础 Docker 镜像的源代码,该镜像托管在公共 Docker 注册表中,永远不会在本地运行。这样做的全部原因是为了拥有一个可复用的镜像。

好的。其实我之前为了简化说明,在 vim 上撒了个谎。我实际上是在运行这些命令,以幂等且稳健的方式更新脚本。

cd /var/discourse/image/base
cp install-nginx install-nginx.`date "+%Y%m%d_%H%M%S"`.orig

# 在下载 nginx 源码之前,添加一段代码来检出 modsecurity nginx 模块
grep 'ModSecurity' install-nginx || sed -i 's%\(curl.*nginx\.org/download.*\)%# mod_security --maltfield\napt-get install -y libmodsecurity-dev modsecurity-crs\ncd /tmp\ngit clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git\n\n\1%' install-nginx

# 更新 configure 行,以包含上面检出的 ModSecurity 模块
sed -i '/ModSecurity/! s%^[^#]*./configure \(.*nginx.*\)%#./configure \1\n./configure \1 --add-module=/tmp/ModSecurity-nginx%' install-nginx

# 在清理部分添加一行
grep 'rm -fr /tmp/ModSecurity-nginx' install-nginx || sed -i 's%\(rm -fr.*/tmp/nginx.*\)%rm -fr /tmp/ModSecurity-nginx\n\1%' install-nginx

我应该将这些命令放在哪里,以便修改容器在启动引导时实际使用的 install-nginx 脚本?