解决1Panel部署的Discourse,所有用户ip显示为来自 Cloudflare,而不是用户的浏览器真实IP的问题

我在VPS上安装了1Panel,安装了Discourse(容器部署),使用OpenResty(容器部署)进行了反向代理。域名托管在Cloudflare,并开启了cdn小黄云,以下是解决用户IP显示为来自 Cloudflare,而不是用户的浏览器IP的问题。

一、在1Panel中创建计划任务,每周下载最新的Cloudflare ip列表,并保存到Openresty的配置目录。

  1. 在 1Panel 左侧菜单栏点击 “计划任务”

  2. 点击右上角的 “创建计划任务”

  3. 按照以下参数填写(直接复制粘贴即可):

  • 任务类型:选择 Shell 脚本

  • 任务名称:例如 自动更新Cloudflare的IP段

  • 执行周期:建议选 每周(例如每周六 凌晨 03:00)。

  • 脚本内容:将下面这段完整的代码直接复制进去(注意:请先修改代码最上方的容器名和配置目录路径):

#!/bin/bash
# 配置区域
CONTAINER_NAME="1Panel中openresty的容器名称"
# 修改为指定的网站 proxy 目录
CONF_DIR="/opt/1panel/www/sites/www.你的网站域名.club/proxy"

echo "[$(date)] 开始从 Cloudflare 官方拉取最新 IP 段..."
TEMP_DIR=$(mktemp -d)

# 拉取并转换 IP 列表为 Nginx 识别格式
curl -fsS https://www.cloudflare.com/ips-v4 | sed 's/.*/set_real_ip_from &;/' > $TEMP_DIR/cf-ips-v4.conf
curl -fsS https://www.cloudflare.com/ips-v6 | sed 's/.*/set_real_ip_from &;/' > $TEMP_DIR/cf-ips-v6.conf

# 检查并移动文件
if [[ -s $TEMP_DIR/cf-ips-v4.conf ]] && [[ -s $TEMP_DIR/cf-ips-v6.conf ]]; then
    mv $TEMP_DIR/cf-ips-v4.conf $CONF_DIR/
    mv $TEMP_DIR/cf-ips-v6.conf $CONF_DIR/
    echo "[$(date)] 配置文件已成功更新到 $CONF_DIR。"
else
    echo "[$(date)] 错误:拉取 Cloudflare IP 失败!"
    rm -rf $TEMP_DIR
    exit 1
fi
rm -rf $TEMP_DIR

# 测试并重载 Nginx
echo "[$(date)] 正在进行 Nginx 配置测试..."
if docker exec $CONTAINER_NAME nginx -t; then
    docker exec $CONTAINER_NAME nginx -s reload
    echo "[$(date)] 成功!OpenResty 配置重载完成。"
else
    echo "[$(date)] 失败!Nginx 配置测试未通过。"
    exit 1
fi

任务创建好后,不需要等到周六,你可以立刻测试:在"计划任务"列表中找到刚才创建的任务。

点击右侧的 “报告” 按钮。查看弹出的日志窗口。如果最后几行显示 成功!OpenResty 配置重载完成,就说明整个流程在 1Panel 内部已经完美跑通了!

二、OpenResty 补充 realip 配置

在宿主机 /opt/1panel/www/sites/www.你的网站域名/proxy/ 目录下新建一个文件(文件名任意,以 .conf 结尾即可,会被主配置的 include *.conf 自动加载):realip.conf

# 使用容器内的路径
include /www/sites/www.你的网站域名/proxy/cf-ips-v4.conf;
include /www/sites/www.你的网站域名/proxy/cf-ips-v6.conf;

real_ip_header CF-Connecting-IP;
real_ip_recursive on;

三、重载 OpenResty

docker exec 1Panel中openresty的容器名称 nginx -t
docker exec 1Panel中openresty的容器名称 nginx -s reload

四、验证 OpenResty 是否已获取真实 IP

查看 OpenResty 的 access log:

tail -f /opt/1panel/www/sites/www.你的网站域名/log/access.log

如果配置正确,日志中的第一个 IP 应该变成你的真实公网 IP,而不是 Cloudflare 的 173.245.x.x 等段。

五、Discourse 侧

编辑app.yml,在run:代码块内添加以下内容:

  #docker 部署discourse后,需要添加以下三段,确保传递论坛用户真实IP
  - file:
      path: /etc/nginx/conf.d/outlets/server/set-real-ip-from-docker.conf
      chmod: 644
      contents: |
        set_real_ip_from 172.16.0.0/12;
        set_real_ip_from 127.0.0.1;
  
  - file:
      path: /etc/nginx/conf.d/outlets/server/real-ip-header.conf
      chmod: 644
      contents: |
        real_ip_header x-forwarded-for;
  
  - file:
      path: /etc/nginx/conf.d/outlets/server/real-ip-recursive.conf
      chmod: 644
      contents: |
        real_ip_recursive on;

这样 Discourse 内置 Nginx 会:

  1. 信任 Docker 网段(172.16.0.0/12
  2. x-forwarded-for 读取真实 IP
  3. 递归解析多层代理

六、备注说明

在Discourse 的app.yml中添加 - "templates/cloudflare.template.yml"Discourse 直接面向 Cloudflare 时才有效。由于中间加了 OpenResty 反向代理,Discourse 容器看到的来源 IP 其实是 Docker 网关(如 172.17.0.1172.18.0.1),所以该模板里的 set_real_ip_from <CloudflareIP> 不会匹配。

所以无需在Discourse 的app.yml中添加 - "templates/cloudflare.template.yml"


2026-07-03更新

2 个赞

参照

处理终端用户真实IP的“信任链” - 文档 / 自我托管 - Discourse Meta

将主题帖进行更新。