> ## Content Index
> Fetch the complete content index at: https://isoziyuan.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# CrowdSec Cloudflare 配置实战：让 Nginx 获取真实访客 IP，并通过 Cloudflare API 自动封禁暴力攻击
- URL: https://isoziyuan.com/p/100122/
- Published: 2026-09-01T00:03:52.000Z
- Updated: 2026-09-01T00:03:52.000Z
- Author: Isoziyuan
- Tags: 网站安全, CrowdSec, Cloudflare, 防火墙

如果网站套上 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 或本机防火墙通常在源站执行封禁：

```text
攻击者
   ↓
Cloudflare
   ↓
源站防火墙拦截

```

这种方式虽然能保护应用，但攻击流量已经经过 Cloudflare 到达服务器，依然会占用：

- 源站网络带宽；
- TCP/TLS 连接资源；
- Nginx 工作连接；
- Cloudflare 到源站的回源额度；
- 日志和安全系统处理能力。

把 CrowdSec 的封禁决定同步到 Cloudflare 后，链路会变成：

```text
攻击者
   ↓
Cloudflare 边缘节点直接拦截
   ✕
不再回源

```

这就是 **Cloudflare API 自动封禁**的核心价值：CrowdSec 负责检测和决策，Cloudflare 负责在全球边缘执行拦截。

## 二、整个方案的工作原理

完整数据流如下：

```text
访客真实 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 规则

```

这里有三个必须同时成立的安全条件：

1. **Nginx 只信任 Cloudflare 官方 IP 段传来的真实 IP 请求头。**
2. **源站 80/443 端口应尽量只允许 Cloudflare 节点访问。**
3. **Nginx 日志必须把恢复后的 `$remote_addr` 写进去。**

缺少任何一步，最终封禁都有可能失效或被伪造。

## 三、准备工作与环境依赖

本文假设使用以下环境：

- 一台 Linux 服务器，示例以 Debian/Ubuntu 为主；
- 域名已经接入 Cloudflare；
- DNS 记录开启了橙色云朵代理；
- Nginx 位于源站或宿主机；
- Docker Engine 和 Docker Compose Plugin 已安装；
- 拥有 Cloudflare Zone ID、Account ID；
- 能创建 Cloudflare API Token；
- 服务器时间和时区正常。

确认 Docker 环境：

```bash
docker --version
docker compose version

```

确认 Nginx 编译时包含 Real IP 模块：

```bash
nginx -V 2>&1 | grep -o 'http_realip_module'

```

如果输出：

```text
http_realip_module

```

说明可以继续。

大多数发行版官方 Nginx 包都已包含该模块。如果使用自行编译的 Nginx，需要添加：

```text
--with-http_realip_module

```

### 建议先备份配置

```bash
sudo cp -a /etc/nginx /etc/nginx.backup-$(date +%F-%H%M%S)

```

同时确认当前日志位置：

```bash
sudo nginx -T 2>/dev/null | grep -E 'access_log|log_format'

```

本文默认日志为：

```text
/var/log/nginx/access.log

```

如果你的 Nginx 运行在容器中，则需要把同一个日志卷以只读方式挂载给 CrowdSec。

## 四、让 Nginx 安全获取 Cloudflare 后的真实 IP

### 4.1 为什么不能直接信任 X-Forwarded-For

下面这种配置非常危险：

```nginx
real_ip_header X-Forwarded-For;
set_real_ip_from 0.0.0.0/0;

```

它等于告诉 Nginx：

> 无论请求来自哪里，都无条件相信对方声明的客户端 IP。

攻击者可以绕过 Cloudflare，直接访问源站并发送：

```http
X-Forwarded-For: 8.8.8.8

```

这样日志和 CrowdSec 看到的来源就可能变成伪造地址。

正确做法是：

- 只信任 Cloudflare 官方公布的 IPv4/IPv6 网段；
- 使用 Cloudflare 提供的 `CF-Connecting-IP`；
- 最好同时在网络层禁止外部绕过 Cloudflare 访问源站。

### 4.2 自动生成 Cloudflare可信代理配置

创建配置目录：

```bash
sudo install -d -m 0755 /etc/nginx/snippets

```

下载 Cloudflare 官方 IP 段：

```bash
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

```

先确认文件不是空的：

```bash
test -s /tmp/cloudflare-ips-v4.txt
test -s /tmp/cloudflare-ips-v6.txt

```

生成 Nginx 配置：

```bash
{
  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

```

查看结果：

```bash
sudo cat /etc/nginx/snippets/cloudflare-real-ip.conf

```

内容应该类似：

```nginx
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-v4`
- `https://www.cloudflare.com/ips-v6`

### 4.3 在 Nginx 的 http 块中加载配置

编辑 `/etc/nginx/nginx.conf`：

```bash
sudo nano /etc/nginx/nginx.conf

```

在 `http {}` 内添加：

```nginx
http {
    include /etc/nginx/snippets/cloudflare-real-ip.conf;

    # 其他配置
}

```

不要把它放进一个只服务于其他域名的无关 `server {}` 中。如果整台服务器的所有网站都通过 Cloudflare，放在 `http {}` 最直观。

### 4.4 配置包含真实访客 IP 的 Nginx 日志

在 `http {}` 中定义日志格式：

```nginx
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 {}` 中使用：

```nginx
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，因此这里最关键的是：

```nginx
'$remote_addr ...'

```

### 4.5 检查并重载 Nginx

```bash
sudo nginx -t
sudo systemctl reload nginx

```

如果使用容器化 Nginx，则执行对应容器内的测试和重载命令，例如：

```bash
docker exec nginx nginx -t
docker exec nginx nginx -s reload

```

访问网站后查看日志：

```bash
sudo tail -f /var/log/nginx/access.log

```

正确结果应类似：

```text
198.51.100.23 - - [10/Sep/2026:12:30:21 +0800] "GET / HTTP/2.0" 200 ...

```

并且末尾的代理节点字段类似：

```text
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，防止把自己锁在服务器外：

```bash
sudo ufw allow from YOUR_ADMIN_IP to any port 22 proto tcp

```

然后根据 Cloudflare 官方列表逐条允许 80/443。可以使用下面的脚本生成规则：

```bash
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

```

确认规则无误后，再拒绝其他来源：

```bash
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 创建项目目录

```bash
sudo mkdir -p /opt/crowdsec
sudo chown -R "$USER":"$USER" /opt/crowdsec
cd /opt/crowdsec

```

创建 `acquis.yaml`：

```bash
cat > acquis.yaml <<'EOF'
filenames:
  - /var/log/nginx/access.log
labels:
  type: nginx
EOF

```

这里的 `type: nginx` 非常重要，它告诉 CrowdSec 使用 Nginx 相关解析链。

### 6.2 编写 Docker Compose 文件

创建 `compose.yaml`：

```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:

```

启动服务：

```bash
docker compose up -d

```

查看启动日志：

```bash
docker compose logs -f crowdsec

```

生产环境不建议长期使用漂移的 `latest` 标签。确认部署稳定后，应将 `CROWDSEC_VERSION` 固定为已经测试过的版本或镜像摘要。

例如创建 `.env`：

```bash
cat > .env <<'EOF'
CROWDSEC_VERSION=请替换为你已验证的版本号
EOF

```

具体版本应从 CrowdSec 官方镜像仓库或发行说明中确认，不要盲目照抄过时教程里的版本号。

### 6.3 检查 Nginx Collection

```bash
docker compose exec crowdsec cscli collections list

```

确认 `crowdsecurity/nginx` 已启用。

如未安装，可执行：

```bash
docker compose exec crowdsec cscli collections install crowdsecurity/nginx
docker compose restart crowdsec

```

检查解析器和检测场景：

```bash
docker compose exec crowdsec cscli parsers list
docker compose exec crowdsec cscli scenarios list

```

### 6.4 检查 CrowdSec 是否正在读取日志

```bash
docker compose exec crowdsec cscli metrics

```

重点观察：

- Acquisition Metrics；
- Parser Metrics；
- Nginx 日志读取行数；
- Parsed 和 Unparsed 数量；
- Scenario Metrics。

也可以查看 CrowdSec 日志：

```bash
docker compose logs --tail=200 crowdsec

```

如果访问网站后 Acquisition 的读取数量仍为零，通常是日志路径、挂载路径或权限配置错误。

## 七、理解“网站暴力破解防护”的检测边界

安装 Nginx Collection 并不等于 CrowdSec 能自动理解所有网站的业务登录逻辑。

CrowdSec 最容易识别的是：

- 大量 401、403、404；
- 常见漏洞探测；
- 恶意 User-Agent；
- 敏感路径扫描；
- 高频访问异常；
- 已知攻击行为模式。

但许多网站登录失败时仍返回：

```http
HTTP/1.1 200 OK

```

仅在 HTML 或 JSON 中提示“密码错误”。对 Nginx 日志来说，成功登录和失败登录可能都是：

```text
POST /login 200

```

CrowdSec 无法仅凭默认 access log 判断哪个请求失败。

### 更可靠的处理方式

按照优先级，可选择：

1. **让应用把登录失败写入结构化安全日志；**
2. **使用对应应用的 CrowdSec Collection；**
3. **让失败登录返回明确的 401 或 403；**
4. **针对固定登录路径编写本地 Scenario；**
5. **同时使用 Cloudflare Rate Limiting 和 Turnstile。**

WordPress、Nextcloud、面板程序、SSH、邮件服务等应优先查找 CrowdSec Hub 中是否存在适配的 Collection：

```bash
docker compose exec crowdsec cscli hub list

```

搜索相关组件：

```bash
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 放入临时环境变量：

```bash
read -rsp "Cloudflare API Token: " CF_API_TOKEN
echo
export CF_API_TOKEN

```

调用官方验证接口：

```bash
curl -fsS \
  -H "Authorization: Bearer ${CF_API_TOKEN}" \
  -H "Content-Type: application/json" \
  https://api.cloudflare.com/client/v4/user/tokens/verify

```

正常响应中应包含：

```json
{
  "success": true
}

```

验证结束后，可以清除当前 Shell 中的变量：

```bash
unset CF_API_TOKEN

```

不要把 Token 直接写入 Shell 历史、公开 Git 仓库、截图或工单。

## 九、配置 CrowdSec Cloudflare Bouncer

CrowdSec 本身负责分析和生成决定，真正执行封禁的是 Remediation Component，也就是 Bouncer。

### 9.1 生成 Bouncer API Key

在 CrowdSec 容器中注册一个 Bouncer：

```bash
cd /opt/crowdsec

docker compose exec crowdsec \
  cscli bouncers add cloudflare-bouncer

```

命令会输出一串 API Key，例如：

```text
API key for 'cloudflare-bouncer':

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

```

**这串 Key 通常只完整显示一次，立即保存到密码管理器。**

查看已注册 Bouncer：

```bash
docker compose exec crowdsec cscli bouncers list

```

### 9.2 安装官方 Cloudflare Bouncer

在 Debian/Ubuntu 宿主机上，可以先添加 CrowdSec 官方软件源：

```bash
curl -s https://install.crowdsec.net | sudo sh
sudo apt update

```

然后安装：

```bash
sudo apt install crowdsec-cloudflare-bouncer

```

安装脚本和仓库地址具有时效性。如果命令返回 404、签名错误或包不存在，请停止操作并查看 CrowdSec 官方 Cloudflare Remediation Component 文档，不要从不明第三方站点下载二进制文件。

### 9.3 找到实际配置文件

常见路径为：

```text
/etc/crowdsec/bouncers/crowdsec-cloudflare-bouncer.yaml

```

先通过软件包确认：

```bash
dpkg -L crowdsec-cloudflare-bouncer | grep -E '\.ya?ml$'

```

备份原始文件：

```bash
sudo cp \
  /etc/crowdsec/bouncers/crowdsec-cloudflare-bouncer.yaml \
  /etc/crowdsec/bouncers/crowdsec-cloudflare-bouncer.yaml.backup

```

### 9.4 填写 Bouncer 配置

当前常见配置结构如下，但**字段应以安装包生成的样例为准**：

```yaml
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。

设置严格权限：

```bash
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

```bash
sudo systemctl enable --now crowdsec-cloudflare-bouncer
sudo systemctl status crowdsec-cloudflare-bouncer

```

查看实时日志：

```bash
sudo journalctl \
  -u crowdsec-cloudflare-bouncer \
  -f

```

回到 CrowdSec 检查 Bouncer 是否连接：

```bash
docker compose exec crowdsec cscli bouncers list

```

如果显示最近拉取时间，说明 Cloudflare Bouncer 已成功连接 CrowdSec LAPI。

## 十、验证 Cloudflare API 自动封禁是否真正生效

### 10.1 添加一个短期测试决定

不要直接封禁自己当前使用的公网 IP，除非你准备了备用网络、控制台或救援通道。

可以先使用一个你可控的测试 IP：

```bash
docker compose exec crowdsec \
  cscli decisions add \
  --ip TEST_PUBLIC_IP \
  --duration 2m \
  --reason "cloudflare-bouncer-test"

```

查看决策：

```bash
docker compose exec crowdsec cscli decisions list

```

等待 Bouncer 的同步周期，然后查看日志：

```bash
sudo journalctl \
  -u crowdsec-cloudflare-bouncer \
  --since "5 minutes ago"

```

同时进入 Cloudflare 控制台，检查 Bouncer 创建或维护的：

- IP List；
- WAF/Firewall 规则；
- 安全事件；
- 对应列表条目。

不同 Bouncer 版本采用的 Cloudflare 对象可能不同，因此具体入口应以日志和当前官方文档为准。

### 10.2 删除测试决定

```bash
docker compose exec crowdsec \
  cscli decisions delete \
  --ip TEST_PUBLIC_IP

```

确认已经删除：

```bash
docker compose exec crowdsec cscli decisions list

```

Bouncer 通常会在后续同步周期中清除对应 Cloudflare 条目，而不是在执行删除命令的同一毫秒立即消失。

### 10.3 观察真实检测结果

查看告警：

```bash
docker compose exec crowdsec cscli alerts list

```

查看封禁决定：

```bash
docker compose exec crowdsec cscli decisions list

```

查看整体指标：

```bash
docker compose exec crowdsec cscli metrics

```

如果有告警但没有封禁决定，需要检查对应 Scenario 是否带有：

```yaml
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 绕开部分策略。

因此必须同时维护：

```text
https://www.cloudflare.com/ips-v4
https://www.cloudflare.com/ips-v6

```

### 11.4 定期更新 Cloudflare IP 段

Cloudflare IP 段不会频繁变化，但生产环境仍应定期同步。

可以编写受控脚本，流程应包括：

1. 下载到临时文件；
2. 验证文件非空；
3. 生成临时 Nginx 配置；
4. 执行 `nginx -t`；
5. 测试通过后原子替换；
6. 重载 Nginx；
7. 同步更新云防火墙或安全组。

不要让 Cron 直接覆盖正式配置后无条件 reload，否则一次下载异常就可能导致全站故障。

### 11.5 关注 Cloudflare 列表与规则配额

大量长时间封禁可能触及：

- 单列表最大条目数；
- 每账户列表数量；
- WAF 自定义规则数量；
- API 请求频率；
- 当前套餐限制。

CrowdSec Bouncer 的日志中如果出现配额错误，应优先：

- 缩短决策持续时间；
- 减少低置信度封禁；
- 检查过期条目是否被及时清理；
- 使用 CrowdSec 社区信誉数据提高判断质量；
- 根据当前 Cloudflare 套餐调整策略。

## 十二、常见排错指南（FAQ / Troubleshooting）

### 1\. Nginx 日志里仍然是 Cloudflare IP

先查看完整生效配置：

```bash
sudo nginx -T 2>/dev/null | grep -A5 -B5 'real_ip_header'

```

应看到：

```nginx
real_ip_header CF-Connecting-IP;

```

并且存在完整的 Cloudflare：

```nginx
set_real_ip_from ...

```

然后确认 DNS 记录确实开启橙色云朵。如果是灰色云朵，Cloudflare 不会代理请求，也不会添加可信的 `CF-Connecting-IP`。

还要确认日志使用的是：

```nginx
$remote_addr

```

而不是：

```nginx
$realip_remote_addr

```

后者在启用 Real IP 模块后通常保存的是修改前的 Cloudflare 节点地址。

### 2\. 能否直接把 `$http_cf_connecting_ip` 写进日志

技术上可以，但不推荐把它作为唯一可信来源。

```nginx
$http_cf_connecting_ip

```

只是原始 HTTP 请求头。只有请求确定来自 Cloudflare 时，它才可信。

更安全的方式是：

1. 使用 `set_real_ip_from` 限制可信代理；
2. 让 Real IP 模块验证来源；
3. 最终记录 `$remote_addr`。

### 3\. CrowdSec 的 Acquisition Metrics 一直是零

检查宿主机日志是否存在：

```bash
sudo ls -lah /var/log/nginx/access.log

```

检查容器内是否可见：

```bash
docker compose exec crowdsec \
  ls -lah /var/log/nginx/access.log

```

读取最后几行：

```bash
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 日志：

```bash
docker compose logs --tail=300 crowdsec

```

查看指标：

```bash
docker compose exec crowdsec cscli metrics

```

建议先使用接近标准 Combined 格式的日志，再逐步增加附加字段。

### 5\. Bouncer 报 `connection refused 127.0.0.1:8080`

检查 CrowdSec LAPI 是否映射到宿主机：

```bash
sudo ss -lntp | grep ':8080'

```

应看到类似：

```text
127.0.0.1:8080

```

检查容器：

```bash
docker compose ps
docker compose logs --tail=100 crowdsec

```

从宿主机测试端口：

```bash
curl -v http://127.0.0.1:8080/

```

即使根路径返回 404，也说明 TCP 和 HTTP 服务可达；连接拒绝则意味着端口没有监听。

### 6\. Bouncer 报 401 或未认证

通常原因是：

- Bouncer API Key 填错；
- Key 前后包含空格；
- 修改配置后未重启；
- Key 属于另一个 CrowdSec LAPI；
- 删除并重建了 CrowdSec 数据卷。

重新注册一个 Key：

```bash
docker compose exec crowdsec \
  cscli bouncers add cloudflare-bouncer-new

```

更新配置后重启：

```bash
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 没有对应封禁

依次检查：

```bash
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 的状态码：

```bash
sudo tail -f /var/log/nginx/access.log

```

如果每次失败登录都是：

```text
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 访客。

如果选择覆盖请求头的模式，应同时关注：

```text
CF-Connecting-IPv6

```

对于需要准确保留 IPv6 来源的 CrowdSec 部署，建议复核 Cloudflare 当前的 Pseudo IPv4 文档，避免使用会覆盖真实来源信息的模式。

### 11\. 使用 Cloudflare Workers 后真实 IP 异常

如果请求经过 Worker，并由 Worker 再发起子请求，`CF-Connecting-IP` 的行为可能与普通代理链路不同。

应确认：

- Worker 是否改写请求头；
- 是否跨 Zone 发起请求；
- Worker 路由是否覆盖当前域名；
- 日志中的 `CF-Ray` 是否符合预期。

不要仅凭一个请求头推断链路，应同时记录：

```nginx
$remote_addr
$realip_remote_addr
$http_cf_connecting_ip
$http_cf_ray

```

排错完成后，可以减少不必要的敏感日志字段。

### 12\. 误封了自己的公网 IP 怎么办

如果还能进入服务器：

```bash
docker compose exec crowdsec \
  cscli decisions delete \
  --ip YOUR_PUBLIC_IP

```

然后观察 Bouncer 同步：

```bash
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/nginx` Collection 已安装；
- \[ \] `cscli metrics` 显示日志正在被解析；
- \[ \] Cloudflare Token 使用最小权限；
- \[ \] CrowdSec LAPI 仅监听 `127.0.0.1:8080`；
- \[ \] Cloudflare Bouncer 已成功连接 LAPI；
- \[ \] 短期测试 Decision 可以同步到 Cloudflare；
- \[ \] Decision 删除后，Cloudflare 条目能够被清理；
- \[ \] 已准备误封后的备用管理通道；
- \[ \] 已监控 Cloudflare 列表、规则和 API 配额。

## 结语

一套可靠的 **CrowdSec Cloudflare 配置**，重点并不只是“安装一个容器”或“填入一串 API Token”，而是建立可信的数据闭环：

1. Cloudflare 把真实访客地址放入可信请求头；
2. Nginx 只接受 Cloudflare 节点提供的该请求头；
3. Nginx 把恢复后的真实 IP 写入访问日志；
4. CrowdSec 根据真实 IP 分析攻击行为；
5. Cloudflare Bouncer 把封禁决定同步到边缘；
6. 防火墙阻止攻击者绕过 Cloudflare直连源站。

其中最关键的一条原则是：

> **真实 IP 不是“读取一个 Header”那么简单，而是建立一条只信任指定反向代理的安全边界。**

完成这条链路后，网站暴力破解防护就不再局限于源站本机。扫描器、撞库工具和高频攻击者可以在 Cloudflare 边缘被提前拦截，而 CrowdSec 仍保留开放、可审计、可扩展的检测与决策能力。