我在VPS上安装了1Panel,安装了Discourse(容器部署),使用OpenResty(容器部署)进行了反向代理。域名托管在Cloudflare,并开启了cdn小黄云。以下我写了教程,用于解决用户IP显示为来自 Cloudflare,而不是用户的浏览器IP的问题。
一、在1Panel中创建计划任务,每周下载最新的Cloudflare ip列表,并保存到Openresty的配置目录。
-
在 1Panel 左侧菜单栏点击 “计划任务”。
-
点击右上角的 “创建计划任务”。
-
按照以下参数填写(直接复制粘贴即可):
-
任务类型:选择 Shell 脚本。
-
任务名称:例如
自动更新Cloudflare的IP段。 -
执行周期:建议选 每周(例如每周六 凌晨 03:00)。
-
脚本内容:将下面这段完整的代码直接复制进去(注意:请先修改代码最上方的容器名和配置目录路径):
#!/bin/bash
# 配置区域
CONTAINER_NAME="1Panel中openresty的容器名称"
# 修改为指定的网站 proxy 目录
CONF_DIR="/opt/1panel/www/sites/www.你的网站域名/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
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 侧说明
在Discourse 的app.yml中添加 - "templates/cloudflare.template.yml" 在 Discourse 直接面向 Cloudflare 时才有效。由于中间加了 OpenResty 反向代理,Discourse 容器看到的来源 IP 其实是 Docker 网关(如 172.17.0.1 或 172.18.0.1),所以该模板里的 set_real_ip_from <CloudflareIP> 不会匹配。
但只要你按上面的步骤在 OpenResty 层还原了真实 IP,并传递了干净的 X-Forwarded-For,Discourse 后端的 Rails 就能正确识别真实用户 IP,因为 Rails 默认已经信任 172.x.x.x 这类 Docker 私有网段。
所以无需在Discourse 的app.yml中添加 - "templates/cloudflare.template.yml"。