CrowdSec Cloudflare 配置实战:让 Nginx 获取真实访客 IP,并通过 Cloudflare API 自动封禁暴力攻击
如果网站套上 Cloudflare 后,你在 Nginx 日志里看到的全是 172.70.x.x、104.16.x.x 等 Cloudflare 节点地址,那么后端安全系统实际上已经“失明”了。
攻击者可以不断尝试登录、扫描漏洞,CrowdSec 却可能把所有请求都归到 Cloudflare 节点名下。更危险的是,如果直接信任客户端提交的 X-Forwarded-For,攻击者还可以伪造 IP,让封禁机制误伤其他用户。
本文将搭建一条完整、可执行的防护链路:
Cloudflare 代理流量 → Nginx 恢复真实访客 IP → CrowdSec 分析日志 → Cloudflare API 在边缘封禁攻击者
最终效果是:攻击 IP 在 Cloudflare 边缘就会被拦截,请求不再进入源站,从而降低服务器连接数、带宽和应用层压力。
本文以 2026 年 9 月的常见部署方式为背景。CrowdSec、Cloudflare API 权限名称及套餐配额可能变化,生产部署前请同时复核官方文档和当前版本生成的示例配置。
一、为什么仅在源站封 IP 还不够
传统 Fail2ban 或本机防火墙通常在源站执行封禁:
攻击者
↓
Cloudflare
↓
源站防火墙拦截
这种方式虽然能保护应用,但攻击流量已经经过 Cloudflare 到达服务器,依然会占用:
- 源站网络带宽;
- TCP/TLS 连接资源;
- Nginx 工作连接;
- Cloudflare 到源站的回源额度;
- 日志和安全系统处理能力。
把 CrowdSec 的封禁决定同步到 Cloudflare 后,链路会变成:
攻击者
↓
Cloudflare 边缘节点直接拦截
✕
不再回源
这就是 Cloudflare API 自动封禁的核心价值:CrowdSec 负责检测和决策,Cloudflare 负责在全球边缘执行拦截。
二、整个方案的工作原理
完整数据流如下:
访客真实 IP:198.51.100.23
│
▼
Cloudflare 边缘节点
│
│ CF-Connecting-IP: 198.51.100.23
▼
Nginx Real IP 模块
│
│ 将 $remote_addr 恢复为 198.51.100.23
▼
Nginx access.log
│
▼
CrowdSec 解析器与检测场景
│
│ 生成封禁 decision
▼
Cloudflare Bouncer
│
│ 调用 Cloudflare API
▼
Cloudflare IP List / WAF 规则
这里有三个必须同时成立的安全条件:
- Nginx 只信任 Cloudflare 官方 IP 段传来的真实 IP 请求头。
- 源站 80/443 端口应尽量只允许 Cloudflare 节点访问。
- Nginx 日志必须把恢复后的
$remote_addr写进去。
缺少任何一步,最终封禁都有可能失效或被伪造。
三、准备工作与环境依赖
本文假设使用以下环境:
- 一台 Linux 服务器,示例以 Debian/Ubuntu 为主;
- 域名已经接入 Cloudflare;
- DNS 记录开启了橙色云朵代理;
- Nginx 位于源站或宿主机;
- Docker Engine 和 Docker Compose Plugin 已安装;
- 拥有 Cloudflare Zone ID、Account ID;
- 能创建 Cloudflare API Token;
- 服务器时间和时区正常。
确认 Docker 环境:
docker --version
docker compose version
确认 Nginx 编译时包含 Real IP 模块:
nginx -V 2>&1 | grep -o 'http_realip_module'
如果输出:
http_realip_module
说明可以继续。
大多数发行版官方 Nginx 包都已包含该模块。如果使用自行编译的 Nginx,需要添加:
--with-http_realip_module
建议先备份配置
sudo cp -a /etc/nginx /etc/nginx.backup-$(date +%F-%H%M%S)
同时确认当前日志位置:
sudo nginx -T 2>/dev/null | grep -E 'access_log|log_format'
本文默认日志为:
/var/log/nginx/access.log
如果你的 Nginx 运行在容器中,则需要把同一个日志卷以只读方式挂载给 CrowdSec。
四、让 Nginx 安全获取 Cloudflare 后的真实 IP
4.1 为什么不能直接信任 X-Forwarded-For
下面这种配置非常危险:
real_ip_header X-Forwarded-For;
set_real_ip_from 0.0.0.0/0;
它等于告诉 Nginx:
无论请求来自哪里,都无条件相信对方声明的客户端 IP。
攻击者可以绕过 Cloudflare,直接访问源站并发送:
X-Forwarded-For: 8.8.8.8
这样日志和 CrowdSec 看到的来源就可能变成伪造地址。
正确做法是:
- 只信任 Cloudflare 官方公布的 IPv4/IPv6 网段;
- 使用 Cloudflare 提供的
CF-Connecting-IP; - 最好同时在网络层禁止外部绕过 Cloudflare 访问源站。
4.2 自动生成 Cloudflare可信代理配置
创建配置目录:
sudo install -d -m 0755 /etc/nginx/snippets
下载 Cloudflare 官方 IP 段:
curl -fsSL https://www.cloudflare.com/ips-v4 -o /tmp/cloudflare-ips-v4.txt
curl -fsSL https://www.cloudflare.com/ips-v6 -o /tmp/cloudflare-ips-v6.txt
先确认文件不是空的:
test -s /tmp/cloudflare-ips-v4.txt
test -s /tmp/cloudflare-ips-v6.txt
生成 Nginx 配置:
{
echo "# Generated from Cloudflare official IP ranges"
echo "# Updated at: $(date -u +'%Y-%m-%dT%H:%M:%SZ')"
awk 'NF {print "set_real_ip_from " $1 ";"}' /tmp/cloudflare-ips-v4.txt
awk 'NF {print "set_real_ip_from " $1 ";"}' /tmp/cloudflare-ips-v6.txt
echo "real_ip_header CF-Connecting-IP;"
echo "real_ip_recursive on;"
} | sudo tee /etc/nginx/snippets/cloudflare-real-ip.conf >/dev/null
查看结果:
sudo cat /etc/nginx/snippets/cloudflare-real-ip.conf
内容应该类似:
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
# 此处还会有其他 IPv4 和 IPv6 网段
real_ip_header CF-Connecting-IP;
real_ip_recursive on;
不要只复制上面两个示例网段。 Cloudflare 会维护和调整完整列表,应以官方地址为准:
https://www.cloudflare.com/ips-v4https://www.cloudflare.com/ips-v6
4.3 在 Nginx 的 http 块中加载配置
编辑 /etc/nginx/nginx.conf:
sudo nano /etc/nginx/nginx.conf
在 http {} 内添加:
http {
include /etc/nginx/snippets/cloudflare-real-ip.conf;
# 其他配置
}
不要把它放进一个只服务于其他域名的无关 server {} 中。如果整台服务器的所有网站都通过 Cloudflare,放在 http {} 最直观。
4.4 配置包含真实访客 IP 的 Nginx 日志
在 http {} 中定义日志格式:
log_format crowdsec_combined
'$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'host="$host" '
'cf_ray="$http_cf_ray" '
'proxy_peer="$realip_remote_addr"';
然后在对应的网站 server {} 中使用:
server {
listen 443 ssl http2;
server_name example.com;
access_log /var/log/nginx/access.log crowdsec_combined;
# 其他站点配置
}
几个变量的含义如下:
| 变量 | 含义 |
|---|---|
$remote_addr |
Real IP 模块处理后的真实访客 IP |
$realip_remote_addr |
修改前的连接来源,通常是 Cloudflare 节点 IP |
$http_cf_ray |
Cloudflare 为请求生成的 Ray ID,可用于排错 |
$http_cf_connecting_ip |
原始请求头内容,不建议直接作为日志首字段 |
CrowdSec 的 Nginx 解析器通常从日志开头读取来源 IP,因此这里最关键的是:
'$remote_addr ...'
4.5 检查并重载 Nginx
sudo nginx -t
sudo systemctl reload nginx
如果使用容器化 Nginx,则执行对应容器内的测试和重载命令,例如:
docker exec nginx nginx -t
docker exec nginx nginx -s reload
访问网站后查看日志:
sudo tail -f /var/log/nginx/access.log
正确结果应类似:
198.51.100.23 - - [10/Sep/2026:12:30:21 +0800] "GET / HTTP/2.0" 200 ...
并且末尾的代理节点字段类似:
proxy_peer="172.70.92.10"
这说明:
$remote_addr已经是访客 IP;$realip_remote_addr仍保留 Cloudflare 节点 IP;- CrowdSec 可以根据真实访客 IP 进行聚合和封禁。
五、必须阻止攻击者绕过 Cloudflare 直连源站
恢复真实 IP 并不代表源站已经安全。
如果攻击者知道服务器公网 IP,仍可能直接访问源站。此时他可以:
- 绕过 Cloudflare WAF;
- 绕过 Cloudflare Rate Limiting;
- 绕过边缘封禁;
- 直接消耗源站带宽;
- 测试是否存在未代理的虚拟主机。
5.1 使用云防火墙或安全组限制 80/443
最推荐在云厂商安全组中配置:
- SSH 端口只允许管理员固定 IP;
- 80/443 只允许 Cloudflare 官方 IPv4 和 IPv6 网段;
- 拒绝其他互联网来源访问 Web 端口。
如果使用 UFW,必须先保留 SSH,防止把自己锁在服务器外:
sudo ufw allow from YOUR_ADMIN_IP to any port 22 proto tcp
然后根据 Cloudflare 官方列表逐条允许 80/443。可以使用下面的脚本生成规则:
while read -r cidr; do
sudo ufw allow from "$cidr" to any port 80 proto tcp
sudo ufw allow from "$cidr" to any port 443 proto tcp
done < /tmp/cloudflare-ips-v4.txt
while read -r cidr; do
sudo ufw allow from "$cidr" to any port 80 proto tcp
sudo ufw allow from "$cidr" to any port 443 proto tcp
done < /tmp/cloudflare-ips-v6.txt
确认规则无误后,再拒绝其他来源:
sudo ufw deny 80/tcp
sudo ufw deny 443/tcp
sudo ufw enable
sudo ufw status numbered
如果 Nginx 通过 Docker 的
ports:暴露端口,Docker 的 iptables/nftables 转发规则可能绕过部分 UFW 行为。此时优先使用云安全组,或者在 Docker 的DOCKER-USER链中实施限制。
5.2 进一步启用 Authenticated Origin Pulls
Cloudflare Authenticated Origin Pulls 可以让源站验证连接确实来自持有对应客户端证书的 Cloudflare 节点。
它不能替代网络层访问控制,但可以作为第二道验证。启用前应确认:
- Nginx 客户端证书验证配置正确;
- Cloudflare 控制台对应功能已开启;
- 已准备回滚通道;
- 不会影响健康检查或其他合法回源服务。
5.3 避免源站 IP 泄漏
常见泄漏入口包括:
- 同一台服务器上的未代理子域名;
- 邮件服务器 DNS 记录;
- 历史 DNS 数据;
- Git 仓库中的配置;
- 错误页面或监控平台;
- 直接暴露的对象存储、面板和 API。
如果源站 IP 已长期暴露且频繁被绕过,最彻底的办法通常是更换源站公网 IP,并在上线前完成 Cloudflare-only 防火墙限制。
六、使用 Docker 部署 CrowdSec
6.1 创建项目目录
sudo mkdir -p /opt/crowdsec
sudo chown -R "$USER":"$USER" /opt/crowdsec
cd /opt/crowdsec
创建 acquis.yaml:
cat > acquis.yaml <<'EOF'
filenames:
- /var/log/nginx/access.log
labels:
type: nginx
EOF
这里的 type: nginx 非常重要,它告诉 CrowdSec 使用 Nginx 相关解析链。
6.2 编写 Docker Compose 文件
创建 compose.yaml:
services:
crowdsec:
image: crowdsecurity/crowdsec:${CROWDSEC_VERSION:-latest}
container_name: crowdsec
restart: unless-stopped
environment:
COLLECTIONS: "crowdsecurity/nginx"
TZ: "Asia/Shanghai"
volumes:
# CrowdSec 持久化数据库
- crowdsec-db:/var/lib/crowdsec/data
# CrowdSec 配置与 Hub 数据
- crowdsec-config:/etc/crowdsec
# 日志采集配置
- ./acquis.yaml:/etc/crowdsec/acquis.yaml:ro
# 只读挂载宿主机 Nginx 日志
- /var/log/nginx:/var/log/nginx:ro
ports:
# 仅供本机 Cloudflare Bouncer 连接 LAPI
- "127.0.0.1:8080:8080"
security_opt:
- no-new-privileges:true
volumes:
crowdsec-db:
crowdsec-config:
启动服务:
docker compose up -d
查看启动日志:
docker compose logs -f crowdsec
生产环境不建议长期使用漂移的 latest 标签。确认部署稳定后,应将 CROWDSEC_VERSION 固定为已经测试过的版本或镜像摘要。
例如创建 .env:
cat > .env <<'EOF'
CROWDSEC_VERSION=请替换为你已验证的版本号
EOF
具体版本应从 CrowdSec 官方镜像仓库或发行说明中确认,不要盲目照抄过时教程里的版本号。
6.3 检查 Nginx Collection
docker compose exec crowdsec cscli collections list
确认 crowdsecurity/nginx 已启用。
如未安装,可执行:
docker compose exec crowdsec cscli collections install crowdsecurity/nginx
docker compose restart crowdsec
检查解析器和检测场景:
docker compose exec crowdsec cscli parsers list
docker compose exec crowdsec cscli scenarios list
6.4 检查 CrowdSec 是否正在读取日志
docker compose exec crowdsec cscli metrics
重点观察:
- Acquisition Metrics;
- Parser Metrics;
- Nginx 日志读取行数;
- Parsed 和 Unparsed 数量;
- Scenario Metrics。
也可以查看 CrowdSec 日志:
docker compose logs --tail=200 crowdsec
如果访问网站后 Acquisition 的读取数量仍为零,通常是日志路径、挂载路径或权限配置错误。
七、理解“网站暴力破解防护”的检测边界
安装 Nginx Collection 并不等于 CrowdSec 能自动理解所有网站的业务登录逻辑。
CrowdSec 最容易识别的是:
- 大量 401、403、404;
- 常见漏洞探测;
- 恶意 User-Agent;
- 敏感路径扫描;
- 高频访问异常;
- 已知攻击行为模式。
但许多网站登录失败时仍返回:
HTTP/1.1 200 OK
仅在 HTML 或 JSON 中提示“密码错误”。对 Nginx 日志来说,成功登录和失败登录可能都是:
POST /login 200
CrowdSec 无法仅凭默认 access log 判断哪个请求失败。
更可靠的处理方式
按照优先级,可选择:
- 让应用把登录失败写入结构化安全日志;
- 使用对应应用的 CrowdSec Collection;
- 让失败登录返回明确的 401 或 403;
- 针对固定登录路径编写本地 Scenario;
- 同时使用 Cloudflare Rate Limiting 和 Turnstile。
WordPress、Nextcloud、面板程序、SSH、邮件服务等应优先查找 CrowdSec Hub 中是否存在适配的 Collection:
docker compose exec crowdsec cscli hub list
搜索相关组件:
docker compose exec crowdsec cscli hub list | grep -i wordpress
docker compose exec crowdsec cscli hub list | grep -i ssh
安装前请使用当前版本的 cscli hub list 确认真实存在的组件名称,不要根据旧博客凭空安装。
八、创建 Cloudflare API Token
Cloudflare Bouncer 需要调用 API,把 CrowdSec 决策同步为 Cloudflare 边缘规则或 IP 列表。
8.1 获取 Account ID 和 Zone ID
登录 Cloudflare 控制台,进入对应域名。通常可以在域名概览页找到:
- Account ID
- Zone ID
不要混淆两者:
- Account ID 标识 Cloudflare 账户;
- Zone ID 标识具体域名区域。
8.2 创建最小权限 Token
在 Cloudflare API Token 页面创建自定义 Token。
官方 CrowdSec Cloudflare Bouncer 不同版本可能使用不同的 Cloudflare API 能力,例如:
- 账户级 IP/Rules Lists;
- Zone WAF 或 Firewall 规则;
- 旧版 Firewall Access Rules。
因此,应以当前安装版本自带的配置模板和官方 README 所列权限为准。不要为了省事使用 Global API Key。
常见所需权限类别可能包括:
- Account Rules Lists / Account Filter Lists:Edit;
- Zone Firewall Services 或 Zone WAF:Edit;
- Zone:Read。
资源范围应尽量限制为:
- 指定 Cloudflare Account;
- 指定 Zone;
- 不要授权所有账户和所有域名,除非确有需要。
不同 Cloudflare 套餐对列表数量、规则数量和列表容量可能有不同限制。请以当前控制台和 Cloudflare Limits 文档为准。
8.3 验证 Token 是否有效
将 Token 放入临时环境变量:
read -rsp "Cloudflare API Token: " CF_API_TOKEN
echo
export CF_API_TOKEN
调用官方验证接口:
curl -fsS \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json" \
https://api.cloudflare.com/client/v4/user/tokens/verify
正常响应中应包含:
{
"success": true
}
验证结束后,可以清除当前 Shell 中的变量:
unset CF_API_TOKEN
不要把 Token 直接写入 Shell 历史、公开 Git 仓库、截图或工单。
九、配置 CrowdSec Cloudflare Bouncer
CrowdSec 本身负责分析和生成决定,真正执行封禁的是 Remediation Component,也就是 Bouncer。
9.1 生成 Bouncer API Key
在 CrowdSec 容器中注册一个 Bouncer:
cd /opt/crowdsec
docker compose exec crowdsec \
cscli bouncers add cloudflare-bouncer
命令会输出一串 API Key,例如:
API key for 'cloudflare-bouncer':
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
这串 Key 通常只完整显示一次,立即保存到密码管理器。
查看已注册 Bouncer:
docker compose exec crowdsec cscli bouncers list
9.2 安装官方 Cloudflare Bouncer
在 Debian/Ubuntu 宿主机上,可以先添加 CrowdSec 官方软件源:
curl -s https://install.crowdsec.net | sudo sh
sudo apt update
然后安装:
sudo apt install crowdsec-cloudflare-bouncer
安装脚本和仓库地址具有时效性。如果命令返回 404、签名错误或包不存在,请停止操作并查看 CrowdSec 官方 Cloudflare Remediation Component 文档,不要从不明第三方站点下载二进制文件。
9.3 找到实际配置文件
常见路径为:
/etc/crowdsec/bouncers/crowdsec-cloudflare-bouncer.yaml
先通过软件包确认:
dpkg -L crowdsec-cloudflare-bouncer | grep -E '\.ya?ml$'
备份原始文件:
sudo cp \
/etc/crowdsec/bouncers/crowdsec-cloudflare-bouncer.yaml \
/etc/crowdsec/bouncers/crowdsec-cloudflare-bouncer.yaml.backup
9.4 填写 Bouncer 配置
当前常见配置结构如下,但字段应以安装包生成的样例为准:
crowdsec_lapi_url: http://127.0.0.1:8080/
crowdsec_lapi_key: "替换为刚才生成的_BOUNCER_API_KEY"
crowdsec_update_frequency: 10s
cloudflare_config:
accounts:
- id: "替换为_CLOUDFLARE_ACCOUNT_ID"
token: "替换为_CLOUDFLARE_API_TOKEN"
ip_list_prefix: "crowdsec"
default_action: "block"
zones:
- zone_id: "替换为_CLOUDFLARE_ZONE_ID"
actions:
- block
注意 YAML 缩进必须使用空格,不能混入 Tab。
设置严格权限:
sudo chown root:root \
/etc/crowdsec/bouncers/crowdsec-cloudflare-bouncer.yaml
sudo chmod 600 \
/etc/crowdsec/bouncers/crowdsec-cloudflare-bouncer.yaml
CrowdSec Cloudflare Bouncer 的配置结构可能随版本调整。如果安装包中的默认文件与上面不同,应保留默认结构,只替换对应的 LAPI 地址、Bouncer Key、Account ID、Zone ID 和 Token,而不是强行覆盖为旧格式。
9.5 启动并检查 Bouncer
sudo systemctl enable --now crowdsec-cloudflare-bouncer
sudo systemctl status crowdsec-cloudflare-bouncer
查看实时日志:
sudo journalctl \
-u crowdsec-cloudflare-bouncer \
-f
回到 CrowdSec 检查 Bouncer 是否连接:
docker compose exec crowdsec cscli bouncers list
如果显示最近拉取时间,说明 Cloudflare Bouncer 已成功连接 CrowdSec LAPI。
十、验证 Cloudflare API 自动封禁是否真正生效
10.1 添加一个短期测试决定
不要直接封禁自己当前使用的公网 IP,除非你准备了备用网络、控制台或救援通道。
可以先使用一个你可控的测试 IP:
docker compose exec crowdsec \
cscli decisions add \
--ip TEST_PUBLIC_IP \
--duration 2m \
--reason "cloudflare-bouncer-test"
查看决策:
docker compose exec crowdsec cscli decisions list
等待 Bouncer 的同步周期,然后查看日志:
sudo journalctl \
-u crowdsec-cloudflare-bouncer \
--since "5 minutes ago"
同时进入 Cloudflare 控制台,检查 Bouncer 创建或维护的:
- IP List;
- WAF/Firewall 规则;
- 安全事件;
- 对应列表条目。
不同 Bouncer 版本采用的 Cloudflare 对象可能不同,因此具体入口应以日志和当前官方文档为准。
10.2 删除测试决定
docker compose exec crowdsec \
cscli decisions delete \
--ip TEST_PUBLIC_IP
确认已经删除:
docker compose exec crowdsec cscli decisions list
Bouncer 通常会在后续同步周期中清除对应 Cloudflare 条目,而不是在执行删除命令的同一毫秒立即消失。
10.3 观察真实检测结果
查看告警:
docker compose exec crowdsec cscli alerts list
查看封禁决定:
docker compose exec crowdsec cscli decisions list
查看整体指标:
docker compose exec crowdsec cscli metrics
如果有告警但没有封禁决定,需要检查对应 Scenario 是否带有:
remediation: true
某些场景可能只产生观察性告警,不自动生成可供 Bouncer 执行的封禁决定。
十一、生产环境强化建议
11.1 不要无限期封禁所有攻击者
动态住宅 IP、移动网络和运营商 NAT 可能被多人共享。永久封禁很容易误伤后来的正常用户。
比较合理的策略是:
- 低强度扫描:数分钟到数小时;
- 明确暴力破解:数小时到数天;
- 高置信恶意 IP:更长时间;
- 误报风险高的业务:优先 Challenge,而不是 Block。
具体时长应结合网站类型、用户分布和攻击强度调整。
11.2 管理员 IP 不应只靠静态白名单
管理员 IP 可能变化,尤其是在移动网络和家庭宽带中。更稳妥的做法包括:
- 管理后台只允许 VPN;
- 使用 Cloudflare Access;
- 开启多因素认证;
- 使用硬件安全密钥;
- 后台路径启用 Turnstile;
- 登录接口设置独立限速;
- CrowdSec 白名单只作为辅助措施。
11.3 同时保留 IPv4 和 IPv6
如果只配置 Cloudflare IPv4 网段,IPv6 回源可能出现:
- 无法恢复真实 IP;
- 被防火墙拒绝;
- CrowdSec 记录到 Cloudflare IPv6 节点;
- 攻击者通过 IPv6 绕开部分策略。
因此必须同时维护:
https://www.cloudflare.com/ips-v4
https://www.cloudflare.com/ips-v6
11.4 定期更新 Cloudflare IP 段
Cloudflare IP 段不会频繁变化,但生产环境仍应定期同步。
可以编写受控脚本,流程应包括:
- 下载到临时文件;
- 验证文件非空;
- 生成临时 Nginx 配置;
- 执行
nginx -t; - 测试通过后原子替换;
- 重载 Nginx;
- 同步更新云防火墙或安全组。
不要让 Cron 直接覆盖正式配置后无条件 reload,否则一次下载异常就可能导致全站故障。
11.5 关注 Cloudflare 列表与规则配额
大量长时间封禁可能触及:
- 单列表最大条目数;
- 每账户列表数量;
- WAF 自定义规则数量;
- API 请求频率;
- 当前套餐限制。
CrowdSec Bouncer 的日志中如果出现配额错误,应优先:
- 缩短决策持续时间;
- 减少低置信度封禁;
- 检查过期条目是否被及时清理;
- 使用 CrowdSec 社区信誉数据提高判断质量;
- 根据当前 Cloudflare 套餐调整策略。
十二、常见排错指南(FAQ / Troubleshooting)
1. Nginx 日志里仍然是 Cloudflare IP
先查看完整生效配置:
sudo nginx -T 2>/dev/null | grep -A5 -B5 'real_ip_header'
应看到:
real_ip_header CF-Connecting-IP;
并且存在完整的 Cloudflare:
set_real_ip_from ...
然后确认 DNS 记录确实开启橙色云朵。如果是灰色云朵,Cloudflare 不会代理请求,也不会添加可信的 CF-Connecting-IP。
还要确认日志使用的是:
$remote_addr
而不是:
$realip_remote_addr
后者在启用 Real IP 模块后通常保存的是修改前的 Cloudflare 节点地址。
2. 能否直接把 $http_cf_connecting_ip 写进日志
技术上可以,但不推荐把它作为唯一可信来源。
$http_cf_connecting_ip
只是原始 HTTP 请求头。只有请求确定来自 Cloudflare 时,它才可信。
更安全的方式是:
- 使用
set_real_ip_from限制可信代理; - 让 Real IP 模块验证来源;
- 最终记录
$remote_addr。
3. CrowdSec 的 Acquisition Metrics 一直是零
检查宿主机日志是否存在:
sudo ls -lah /var/log/nginx/access.log
检查容器内是否可见:
docker compose exec crowdsec \
ls -lah /var/log/nginx/access.log
读取最后几行:
docker compose exec crowdsec \
tail -n 5 /var/log/nginx/access.log
如果容器内不存在,说明 Docker 卷映射错误。
如果 Nginx 也运行在 Docker 中,应使用共享命名卷,而不是假设日志一定存在于宿主机 /var/log/nginx。
4. CrowdSec 读取了日志,但 Parsed 数量很低
检查当前 Nginx 日志格式是否过度自定义。
CrowdSec 的 Nginx Parser 通常能识别常见 Combined Log Format。如果把 JSON、字段顺序或请求行改得过于特殊,就可能需要专门的 parser。
查看 CrowdSec 日志:
docker compose logs --tail=300 crowdsec
查看指标:
docker compose exec crowdsec cscli metrics
建议先使用接近标准 Combined 格式的日志,再逐步增加附加字段。
5. Bouncer 报 connection refused 127.0.0.1:8080
检查 CrowdSec LAPI 是否映射到宿主机:
sudo ss -lntp | grep ':8080'
应看到类似:
127.0.0.1:8080
检查容器:
docker compose ps
docker compose logs --tail=100 crowdsec
从宿主机测试端口:
curl -v http://127.0.0.1:8080/
即使根路径返回 404,也说明 TCP 和 HTTP 服务可达;连接拒绝则意味着端口没有监听。
6. Bouncer 报 401 或未认证
通常原因是:
- Bouncer API Key 填错;
- Key 前后包含空格;
- 修改配置后未重启;
- Key 属于另一个 CrowdSec LAPI;
- 删除并重建了 CrowdSec 数据卷。
重新注册一个 Key:
docker compose exec crowdsec \
cscli bouncers add cloudflare-bouncer-new
更新配置后重启:
sudo systemctl restart crowdsec-cloudflare-bouncer
7. Cloudflare API 返回 403
403 通常不是网络问题,而是权限或资源范围问题。
重点检查:
- Token 是否具有当前 Bouncer 所需的列表/WAF权限;
- Token 是否绑定了正确 Account;
- Zone 是否在同一个 Account 下;
- Zone ID 和 Account ID 是否填反;
- 当前套餐是否支持 Bouncer 使用的规则或列表能力;
- Token 是否已被撤销或过期。
使用验证接口只能证明 Token 存在,不能证明它拥有修改指定 Zone 或列表的权限。
8. CrowdSec 有 Decision,但 Cloudflare 没有对应封禁
依次检查:
docker compose exec crowdsec cscli decisions list
docker compose exec crowdsec cscli bouncers list
sudo systemctl status crowdsec-cloudflare-bouncer
sudo journalctl -u crowdsec-cloudflare-bouncer --since "15 minutes ago"
常见原因包括:
- Bouncer 没有连接 LAPI;
- Decision 已经过期;
- 场景被 Bouncer 的过滤条件排除;
- IP 属于 Bouncer 不处理的范围;
- Cloudflare 列表达到配额;
- API Token 权限不足;
- 配置文件缩进错误;
- Bouncer 尚未到下一次同步周期。
9. 为什么登录爆破没有触发 CrowdSec
首先检查登录失败时 Nginx 的状态码:
sudo tail -f /var/log/nginx/access.log
如果每次失败登录都是:
POST /login HTTP/2.0" 200
默认 Nginx 日志并没有足够信息判断它是失败登录。
解决办法是:
- 接入应用自身的认证失败日志;
- 使用对应应用的 CrowdSec Collection;
- 让应用输出结构化安全事件;
- 编写与业务语义匹配的 Parser 和 Scenario;
- 配合 Cloudflare Rate Limiting 或 Turnstile。
不要为了“让规则触发”而简单封禁所有高频 /login 请求,否则企业 NAT、密码管理器和移动网络用户可能被误伤。
10. Cloudflare 开启 Pseudo IPv4 后 IP 不一致
Cloudflare 的 Pseudo IPv4 模式可能影响部分请求头行为,尤其是 IPv6 访客。
如果选择覆盖请求头的模式,应同时关注:
CF-Connecting-IPv6
对于需要准确保留 IPv6 来源的 CrowdSec 部署,建议复核 Cloudflare 当前的 Pseudo IPv4 文档,避免使用会覆盖真实来源信息的模式。
11. 使用 Cloudflare Workers 后真实 IP 异常
如果请求经过 Worker,并由 Worker 再发起子请求,CF-Connecting-IP 的行为可能与普通代理链路不同。
应确认:
- Worker 是否改写请求头;
- 是否跨 Zone 发起请求;
- Worker 路由是否覆盖当前域名;
- 日志中的
CF-Ray是否符合预期。
不要仅凭一个请求头推断链路,应同时记录:
$remote_addr
$realip_remote_addr
$http_cf_connecting_ip
$http_cf_ray
排错完成后,可以减少不必要的敏感日志字段。
12. 误封了自己的公网 IP 怎么办
如果还能进入服务器:
docker compose exec crowdsec \
cscli decisions delete \
--ip YOUR_PUBLIC_IP
然后观察 Bouncer 同步:
sudo journalctl -u crowdsec-cloudflare-bouncer -f
如果已经无法访问网站,可以:
- 切换手机网络;
- 使用云厂商控制台;
- 暂时在 Cloudflare 控制台删除对应列表条目;
- 暂停 Bouncer 创建的规则;
- 使用服务器救援终端。
不要直接删除整个 CrowdSec 数据卷,这会同时丢失数据库和决策状态,且未必立即清除 Cloudflare 侧已有规则。
十三、最终检查清单
上线前逐项确认:
- [ ] 域名已开启 Cloudflare 代理;
- [ ] Nginx 已加载最新 Cloudflare IPv4 和 IPv6 网段;
- [ ]
real_ip_header使用CF-Connecting-IP; - [ ] 未信任
0.0.0.0/0或所有代理来源; - [ ] Nginx 日志首字段是恢复后的
$remote_addr; - [ ] 日志中能够看到真实访客 IP;
- [ ] 源站 80/443 只允许 Cloudflare 回源;
- [ ] CrowdSec 容器可以只读访问 Nginx 日志;
- [ ]
crowdsecurity/nginxCollection 已安装; - [ ]
cscli metrics显示日志正在被解析; - [ ] Cloudflare Token 使用最小权限;
- [ ] CrowdSec LAPI 仅监听
127.0.0.1:8080; - [ ] Cloudflare Bouncer 已成功连接 LAPI;
- [ ] 短期测试 Decision 可以同步到 Cloudflare;
- [ ] Decision 删除后,Cloudflare 条目能够被清理;
- [ ] 已准备误封后的备用管理通道;
- [ ] 已监控 Cloudflare 列表、规则和 API 配额。
结语
一套可靠的 CrowdSec Cloudflare 配置,重点并不只是“安装一个容器”或“填入一串 API Token”,而是建立可信的数据闭环:
- Cloudflare 把真实访客地址放入可信请求头;
- Nginx 只接受 Cloudflare 节点提供的该请求头;
- Nginx 把恢复后的真实 IP 写入访问日志;
- CrowdSec 根据真实 IP 分析攻击行为;
- Cloudflare Bouncer 把封禁决定同步到边缘;
- 防火墙阻止攻击者绕过 Cloudflare直连源站。
其中最关键的一条原则是:
真实 IP 不是“读取一个 Header”那么简单,而是建立一条只信任指定反向代理的安全边界。
完成这条链路后,网站暴力破解防护就不再局限于源站本机。扫描器、撞库工具和高频攻击者可以在 Cloudflare 边缘被提前拦截,而 CrowdSec 仍保留开放、可审计、可扩展的检测与决策能力。
本文主题:CrowdSec Cloudflare 配置实战:让 Nginx 获取真实访客 IP,并通过 Cloudflare API 自动封禁暴力攻击
引用出处:https://isoziyuan.com/p/100122/(作者:Isoziyuan · 发布于爱搜资源网)
登录后参与讨论
注册或登录账户,即可查看并发表文章评论。