大家好
我已经仔细阅读了文档,并查阅了已发布的配置设置和建议,尝试针对我的特殊情况进行了调整。
对于看似非常简单的事情,令人难以置信的是,所有提出的解决方案都未能奏效,这让人感到极度沮丧。
我们的环境:
- 我们运行的是 AWS EC2 实例,具体为 AWS Linux 2 AMI;
- 已安装并配置了 Apache2;
- 该实例属于 AWS 目标组,并由我们的 AWS 负载均衡器引用;
- 我们的 SSL/TLS 证书由 AWS 提供,并与负载均衡器关联;
- 我们的域名提供商是
name.com; - 在我们的设置中,多个子域名通过 CNAME 记录进行路由,全部指向 AWS 负载均衡器,后者再将流量分发到 EC2 实例;
- 所有通过负载均衡器路由并面向网页用户的流量都是安全的;
- 在我们的服务器上,我们运行三个独立的 Node.js Express 应用程序;
- 端口在 Express 服务器设置中定义,目前为 3000、4000 和 5000 端口;
- Apache 根据子域名将流量路由到相应的 Web 应用,例如:
<VirtualHost *:80>
ServerName subdomain.domain.io
ProxyPreserveHost On
ProxyPass "/" "http://localhost:4000/"
ProxyPassReverse "/" "http://localhost:4000/"
</VirtualHost>
-
虽然不太相关,但我们使用 PM2 来管理 Express 应用,以便它们在服务器重启时自动启动。
-
在同一台服务器上,我们还安装了 Docker;
-
随后,我们根据 app.yaml 文件安装了 Discourse(参考了 Run other websites on the same machine as Discourse - #182 by angus 作为指导)。
当前状态:
- Docker 正在运行;
- Discourse 应用(容器)正在运行;
- 所有 Express 应用都在运行,并且已被 Apache 正确路由。
注意事项:
- 我最初尝试按照文档说明在不暴露端口的情况下构建应用,但未能成功;随后我尝试将 8000 端口通过 HTTP 的 80 端口暴露出来;
- 根据我的简单理解,Docker 就像一栋房子,而各种容器则是其中的房间。Docker 决定了应用的访问方式,即访问哪个“房间”。我暴露 8000 端口的想法是,既然 8000 端口已暴露,我就可以像其他 Express 应用一样引用该端口。但这种方法并不奏效。以下是我在 Apache 中尝试的配置示例:
# FAQ(DISCOURSE 路由)
<VirtualHost *:80>
ServerName discourse.domain.io
ProxyPreserveHost On
ProxyPass "/" "http://localhost:8000/"
ProxyPassReverse "/" "http://localhost:8000/"
</VirtualHost>
- 一个简单的测试是尝试在服务器上通过浏览器访问 localhost:8000。该服务器是安装了 Chromium 的 AWS 实例。localhost:8000 无法解析这一事实表明存在问题,说明我的理解中缺少某些关键内容。我的 Web 应用能够在 Express 设置中指定的端口上运行并可访问,我原本以为 Docker 容器也应如此。
补充说明:
- 我意识到一种可能的解决方案是在 Apache 和 Docker 之前部署 NGINX,将来自
discourse.domain.io的流量路由到本地服务器的 8000 端口(即 Docker 容器暴露的端口),同时将*.domain.io的其他所有流量路由到 Apache 的 9000 端口,然后修改虚拟主机配置,将来自 9000 端口的流量路由到相应的应用,例如:
# EXPRESS 应用在 Apache 中的路由
<VirtualHost *:9000>
ServerName other_sub_domains.domain.io
ProxyPreserveHost On
ProxyPass "/" "http://localhost:4000/"
ProxyPassReverse "/" "http://localhost:4000/"
</VirtualHost>
- 但在我看来,这完全没有必要。如果域名
discourse.domain.io已路由到 Apache,而 Apache 接收到请求后尝试将其路由,那么只需将其指向 Docker 容器暴露的端口即可。 - 此外,如果服务器本机的 localhost:8000 都无法解析,那么上述方案也无法奏效。
目前,当我尝试访问我的 Discourse Docker 容器时,Chrome 浏览器会返回 502 错误。(见上方截图)。
app.yml 文件摘录:
## 这是 Discourse Docker 容器的独立一体化模板
##
## 修改此文件后,您必须重新构建
## /var/discourse/launcher rebuild app
##
## 编辑时请务必非常小心!
## YAML 文件对空格或对齐错误极其敏感!
## 请访问 http://www.yamllint.com/ 验证此文件
templates:
- "templates/postgres.template.yml"
- "templates/redis.template.yml"
- "templates/web.template.yml"
- "templates/web.ratelimited.template.yml"
- "templates/web.socketed.template.yml"
## 如果您想添加 Lets Encrypt(https),请取消注释以下两行
#- "templates/web.ssl.template.yml"
#- "templates/web.letsencrypt.ssl.template.yml"
## 此容器应暴露哪些 TCP/IP 端口?
## 如果您希望 Discourse 与 Apache 或 nginx 等其他 Web 服务器共享端口,
## 请参阅 https://meta.discourse.org/t/17247 获取详细信息
expose:
- "8000:80" # http
#- "443:443" # https
params:
db_default_text_search_config: "pg_catalog.english"
## 将 db_shared_buffers 设置为总内存的最大 25%。
## 将由 bootstrap 根据检测到的 RAM 自动设置,您也可以覆盖
#db_shared_buffers: "256MB"
## 可能改善排序性能,但会增加每个连接的内存使用量
#db_work_mem: "40MB"
## 此容器应使用哪个 Git 版本?(默认:tests-passed)
#version: tests-passed
env:
LC_ALL: en_US.UTF-8
LANG: en_US.UTF-8
LANGUAGE: en_US.UTF-8
# DISCOURSE_DEFAULT_LOCALE: en
## 支持的并发 Web 请求数量?取决于内存和 CPU 核心数。
## 将由 bootstrap 根据检测到的 CPU 自动设置,您也可以覆盖
#UNICORN_WORKERS: 3
## TODO: 此 Discourse 实例将响应的域名
## 必填。Discourse 无法仅使用 IP 地址运行。
DISCOURSE_HOSTNAME: 'discourse.domain.io'
## 如果您希望容器以与上述相同的主机名(-h 选项)启动,请取消注释
#DOCKER_USE_HOSTNAME: true
## TODO: 初始注册时将设为管理员和开发者的逗号分隔邮箱列表
## 示例:'user1@example.com,user2@example.com'
DISCOURSE_DEVELOPER_EMAILS: 'user@domain.io'
## TODO: 用于验证新账户和发送通知的 SMTP 邮件服务器
# SMTP 地址、用户名和密码为必填项
# 警告:SMTP 密码中的 '#' 字符可能导致问题!
DISCOURSE_SMTP_ADDRESS: email-smtp.us-east-1.amazonaws.com
DISCOURSE_SMTP_PORT: 587
DISCOURSE_SMTP_USER_NAME: ******
DISCOURSE_SMTP_PASSWORD: ******
#DISCOURSE_SMTP_ENABLE_START_TLS: true # (可选,默认为 true)
#DISCOURSE_SMTP_DOMAIN: ****** # (某些提供商要求)
#DISCOURSE_NOTIFICATION_EMAIL: ****** # (发送通知的地址)
## 如果您添加了 Lets Encrypt 模板,请取消注释以下行以获取免费 SSL 证书
#LETSENCRYPT_ACCOUNT_EMAIL: me@example.com
## 此 Discourse 实例的 HTTP 或 HTTPS CDN 地址(配置为拉取)
## 请参阅 https://meta.discourse.org/t/14857 获取详细信息
#DISCOURSE_CDN_URL: https://discourse-cdn.example.com
## Maxmind 地理位置 IP 地址查询密钥
## 请参阅 https://meta.discourse.org/t/-/137387/23 获取详细信息
#DISCOURSE_MAXMIND_LICENSE_KEY: 1234567890123456
## Docker 容器是无状态的;所有数据都存储在 /shared 中
volumes:
- volume:
host: /var/discourse/shared/standalone
guest: /shared
- volume:
host: /var/discourse/shared/standalone/log/var-log
guest: /var/log
## 插件请放在此处
## 请参阅 https://meta.discourse.org/t/19157 获取详细信息
hooks:
after_code:
- exec:
cd: $home/plugins
cmd:
- git clone https://github.com/discourse/docker_manager.git
## 构建后运行的任何自定义命令
run:
- exec: echo "开始自定义命令"
## 如果您想设置首次注册的“发件人”邮箱地址,请取消注释并修改:
## 获取首次注册邮件后,请重新注释该行。只需运行一次。
#- exec: rails r "SiteSetting.notification_email='info@unconfigured.discourse.org'"
- exec: echo "结束自定义命令"
我的域名、邮箱地址和邮箱配置都是正确的。如前所述,我不需要 SSL/TLS 配置。
请求:
- NGINX 方案是否是唯一能让此设置正常运行的方法?如果是,是否有更清晰的说明可供参考?我目前无法为了运行 Discourse 而从头开始重建服务器,且没有成功保证。
- 在 Discourse behind reverse proxy and https - #2 by itsbhanusharma 中,@Dark Matter 提供了一个 Apache2 解决方案,但我认为该方案并未考虑 Node.js Express 环境,而且由于我的 localhost:8000 无法解析,我不确定该方案是否可行:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
ServerName discourse.example.com
DocumentRoot /website/discourse
RewriteEngine On
ProxyPreserveHost On
ProxyRequests Off
ProxyPass / unix:/var/discourse/shared/socket-only/nginx.http.sock|http://localhost/
ProxyPassReverse / unix:/var/discourse/shared/socket-only/nginx.http.sock|http://localhost/
ErrorLog /var/log/apache2/discourse.error.log
LogLevel warn
CustomLog /var/log/apache2/discourse.access.log combined
RewriteCond %{SERVER_NAME} =discourse.example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
- 问题是否出在我的 Discourse 配置上?或者问题可能在于我的 Apache 路由(我怀疑)?还是我遗漏了某些更基础的内容?
- 我认为解决这个问题将对未来的许多用户有所帮助。
- 最佳方案是在服务器本地直接路由到 Discourse。
- 其次是通过 URL 进行路由。
此致
马修·卢卡斯



