背景
Discourse 需要能够识别最终用户的真实 IP 地址。
然而,由于始终存在一个或多个上游 Web 服务器(运行在 Discourse 容器中的 nginx),最终用户从不直接连接到 Discourse。因此,我们需要一种以可信的方式将该信息传递给 Discourse 的方法。
x-forwarded-for 头信息就是解决方案。在本主题中,我将描述正确处理该信息的具体机制,以及我们期望它是如何传播的。
模板
用于信任上游代理的各种模板(例如 cloudflare.template.yml 或 fastly.template.yml)已更新为在 outlets 中使用可预测的文件名,而不是依赖文本替换(这种方式容易出错)。
文件名
server/real-ip-header.conf
此文件包含运行在容器中的 nginx 将用作真实来源的头信息,例如:
real_ip_header x-forwarded-for;
或者在 Cloudflare 模板中设置的:
real_ip_header cf-connecting-ip;
server/real-ip-recursive.conf
如果此文件存在,它将控制“真实 IP”头信息的递归处理。如果在 Discourse 容器 前面有多个代理,则需要启用此功能。
real_ip_recursive on;
示例:
Cloudflare → 负载均衡器 → Discourse 容器(即 nginx + Discourse 本身)
在此设置下,nginx 将收到如下所示的 x-forwarded-for:
x-forwarded-for: real_end_user_ip, cloudflare_ip
来自负载均衡器 IP 的连接。
为了处理这种情况,首先 nginx 确定连接的源地址(负载均衡器 IP)是否可信(参见 set_real_ip_from),如果是,则处理 x-forwarded-for 头信息中的最后一个 IP。
由于该 IP 地址是 cloudflare_ip,nginx 需要再次执行此操作,检查 cloudflare_ip 是否可信,并使用下一个 IP 地址 real_end_user_ip。
server/set-real-ip-from-ENVIRONMENT.conf
此文件包含告诉 nginx 哪些 IP 地址可信的指令,我们可以根据需要添加尽可能多的文件和指令。
discourse_docker 中的模板会根据需要创建这些文件(例如 set-real-ip-from-cloudflare.conf),如果你有额外需求,可以自行添加。
示例:
如果你在 AWS 中运行,并且在 Discourse 容器前面有一个 ALB,你可以通过将以下内容添加到你的容器定义中(根据你的环境进行调整)来添加一个额外的文件:
run:
- file:
path: /etc/nginx/conf.d/outlets/server/set-real-ip-from-aws.conf
chmod: 644
# AWS VPC 是 10.42.0.0/16,信任来自 ALB 网络的任何连接
contents: |
set_real_ip_from 10.42.66.0/24;
set_real_ip_from 10.42.67.0/24;
- file:
path: /etc/nginx/conf.d/outlets/server/real-ip-header.conf
chmod: 644
contents: |
real_ip_header x-forwarded-for;