为什么 2026 年该把 fail2ban 换成 CrowdSec
如果你是自己维护 VPS 的站长,fail2ban 大概率是你装的第一批安全工具。它确实好用:盯着日志、数失败次数、到阈值就丢一条 iptables 规则。但 fail2ban 有两个绕不开的天花板:它只看本机日志,而且封禁只在你这台机器上生效。也就是说,同一批僵尸网络今天扫你的 A 机器、明天扫你的 B 机器,两台机器各自从零开始数次数;攻击者换个 IP 就能绕开你已经封掉的名单。
CrowdSec 换了个思路:它是一个开源的、社区协作的入侵防御系统。本地依然解析日志、依然做决策,但每个节点都可以把「我这儿被打了」的信号上报到社区,也可以订阅别人共享的恶意 IP 名单。换句话说,你封别人时,也在帮别人;别人封过的 IP,你这边开箱即用。这篇文章就从零把 CrowdSec 在一个 Nginx + SSH 的普通 VPS 上跑起来,讲清楚它和 fail2ban 的区别、配置怎么写、以及几个新手一定会踩的坑。
CrowdSec 和 fail2ban 到底差在哪
先把概念对齐,不然配置时会晕。
- Agent(安全引擎):也叫 CrowdSec Security Engine,常驻进程,负责读日志、跑场景(Scenario)、做决策。每台机器装一个。
- Scenario(场景):相当于 fail2ban 的 filter,是一组用 YAML 写的规则,描述「什么样的日志序列算攻击行为」,比如 5 分钟内同一个 IP 出现 10 次 SSH 认证失败。
- Decision(决策):命中场景后产生的结论,最常见的是 ban(封禁多长时间)。决策是存在本地 SQLite/流式数据库里的,不依赖 iptables 存在。
- Bouncer(执行器):真正落地封禁的组件。它订阅引擎的决策,再把规则写进 iptables、nftables、Nginx、Cloudflare 或者应用层。这是 CrowdSec 最妙的设计——决策和执行解耦,你可以一个引擎挂多个 bouncer。
- Collections / Console:来自社区的规则集和共享名单。默认会连 CrowdSec 的中央 API,既拉取别人的封禁名单,也上报你自己的。
和 fail2ban 对比一句话总结:fail2ban 是「单机日志 + 单机 iptables」,CrowdSec 是「单机日志 + 社区情报 + 多执行器」。前者简单直接,后者在你有多台服务器、或者被打得比较狠时优势明显。
提醒:CrowdSec 默认会把你的封禁决策匿名上报社区(不含你站点内容)。如果你在意隐私,可以在配置里关闭社区上报,只用本地规则。这一点很多教程没讲,务必心里有数。
第一步:安装 CrowdSec 安全引擎
官方提供了 apt 仓库,比手动下二进制省心。以 Debian/Ubuntu 为例:
curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash
sudo apt-get install -y crowdsec装完先别急着配,跑一下诊断:
sudo cscli version
sudo cscli lapi status
sudo systemctl status crowdsec如果 cscli lapi status 报连接失败,多半是引擎还没起或者监听地址不对,先看 journalctl -u crowdsec -n 50。正常的话你会看到本地 API 在 127.0.0.1:8080 上。
第二步:装日志解析器和场景(Collections)
CrowdSec 装完后自带了一批基础解析器(Parser)和场景。你需要按服务器的实际服务安装对应 collection,比如 SSH、Nginx、以及最重要的 Linux 基础场景集:
# 基础 Linux 场景(含 SSH 爆破)
sudo cscli collections install crowdsecurity/linux
sudo cscli collections install crowdsecurity/sshd
# Nginx 访问日志(含爬虫、扫描、路径遍历等)
sudo cscli collections install crowdsecurity/nginx
# HTTP 通用误用检测
sudo cscli collections install crowdsecurity/http-cve装完检查一下生效情况:
sudo cscli collections list
sudo cscli scenarios list
sudo cscli parsers list每个场景后面会标 enabled/disabled。如果某条日志路径解析不到,场景是「空转」的——它不会报错,只是永远不触发,这也是新手最常见的困惑来源,后面会专门讲。
第三步:让 CrowdSec 真正读到你的日志
这是最容易翻车的一步。CrowdSec 靠 acquis.yaml 决定去读哪些日志文件,文件在 /etc/crowdsec/acquis.yaml。默认可能只配了 syslog,你的 Nginx 日志得自己加:
filenames:
- /var/log/nginx/access.log
- /var/log/nginx/error.log
labels:
type: nginx
---
filenames:
- /var/log/auth.log
labels:
type: syslog改完重载:
sudo systemctl reload crowdsec
# 看引擎有没有真的在跟随日志(能看到每行新增计数)
sudo cscli metricscscli metrics 里重点看 Acquisition 这一段,它会列出每个日志文件、读取行数、解析成功/失败数。如果 parsed 一直是 0,说明日志格式和你装的解析器对不上,场景永远不会触发。这时要么确认日志格式(比如 Nginx 用了自定义 log_format,默认解析器认不出),要么补装对应的解析器。
坑位提醒:Docker 部署的 Nginx,日志在宿主机上通常是 JSON 格式(/var/lib/docker/containers/.../*.log),普通 nginx 解析器读不了。要么在 Nginx 侧配一份传统的 combined 格式日志落到磁盘,要么用 crowdsecurity/nginx 的 Docker 变体解析器。别指望它能直接啃 docker json-file 日志。第四步:装 Bouncer,让封禁真正落地
引擎只负责「判」,不负责「封」。要真正把 IP 挡在门外,得装 bouncer。最常用的是 iptables/nftables 版:
sudo apt-get install -y crowdsec-firewall-bouncer-iptables如果是 nftables 环境(较新系统默认):
sudo apt-get install -y crowdsec-firewall-bouncer-nftables装 bouncer 时需要提供引擎的 API key,安装脚本会问你,或者手动生成:
sudo cscli bouncers add my-firewall-bouncer
# 输出一串 API key,复制粘贴到安装向导装完验证:
sudo cscli bouncers list
sudo cscli decisions listbouncers list 里应该出现你刚装的 bouncer,并且有「last pull」时间在滚动——说明它正持续从引擎拉取决策。
第五步:手动验证一次封禁,别等真被打了才发现没生效
安全工具最怕「以为装好了其实空转」。主动造一次攻击来验证:
# 手动给一个测试 IP 下一条封禁决策(比如 203.0.113.66,这是文档保留地址)
sudo cscli decisions add --ip 203.0.113.66 --duration 5m --reason "manual test"
# 查决策是否在库里
sudo cscli decisions list
# 到 bouncer 那侧看防火墙规则有没有真加进去
sudo iptables -L -n | grep 203.0.113.66
# 或者 nftables
sudo nft list ruleset | grep 203.0.113.66如果 cscli decisions list 有、但 iptables 里没有,说明 bouncer 没连上引擎或没拉取成功,回去看 journalctl -u crowdsec-firewall-bouncer -n 50。5 分钟后手动决策过期,再用 cscli decisions delete --ip 203.0.113.66 清掉。
第六步:调参——别把搜索引擎爬虫封了
CrowdSec 的场景默认比较激进,尤其 http 相关场景。上线后第一件事是观察 cscli decisions list,看有没有误封你自己的 IP、公司出口 IP、或者 Googlebot/Bingbot。误封处理有三种:
- 加白名单:
sudo cscli decisions add --ip 1.2.3.4 --type whitelist --duration 0(duration 0 表示永久) - 整段白名单:编辑
/etc/crowdsec/parsers/s02-enrich/whitelists.yaml,用 CIDR 把办公网、监控探针、uptime 检测服务全放进去 - 针对场景降敏:某些场景对个人站太吵(比如
crowdsecurity/http-sensitive-files),可以在白名单里排除路径,或者直接把该场景 disable
一个稳妥的入门白名单示例:
name: my/whitelist
description: "我的可信来源"
whitelist:
reason: "trusted internal/monitoring"
ip:
- "203.0.113.0/24"
expression:
- "evt.Meta.source_ip == '198.51.100.7'"放 /etc/crowdsec/parsers/s02-enrich/ 下,reload 引擎生效。
第七步:在 Nginx 层也执行封禁(AppSec 与 bouncer)
防火墙 bouncer 是网络层的。如果你想让 Nginx 直接把恶意 IP 挡在 403,可以装 Nginx bouncer:
sudo apt-get install -y crowdsec-nginx-bouncer它会在 Nginx 里生成一段 include,定期把封禁列表写成 deny 规则并 reload。注意:每次 reload 会重新加载配置,IP 很多时建议用 geo 或 Lua 模式,否则 reload 频繁会抖。更进阶的是 AppSec 组件,它相当于给 CrowdSec 加一层 WAF,能检测 SQL 注入、XSS 请求体,配合 crowdsecurity/appsec-* 规则使用。个人站如果只是防爆破和扫描,装 SSH + Nginx 两个 bouncer 就够,AppSec 属于锦上添花。
几个一定会踩的坑
- metrics 里 parsed 一直为 0:日志格式不匹配。自定义 log_format 必须确保解析器能提取到 source_ip 和 status,否则场景不触发。解决方法是用标准 combined 格式,或写自定义 parser。
- 封了 IP 但对方还能访问:bouncer 没生效。检查 bouncer 进程状态和 API key 是否正确,尤其多机部署时 bouncer 连的是不是本机引擎
127.0.0.1:8080。 - 社区名单里已经有你朋友/你自己的 IP:CrowdSec 社区名单是共享的,偶尔会误伤动态 IP。可以在配置里关闭
crowdsecurity/community-blocklist的拉取,只用本地场景。 - Docker 里的服务日志读不到:见上文,用宿主机落盘的传统日志格式。
- 封禁时长看不懂:CrowdSec 有时长递增机制(累犯封更久),这是场景里的
capacity和remediation决定的,别以为是 bug。
要不要把 fail2ban 卸了
不必激进。稳妥做法是让两者共存一段时间:fail2ban 继续管 SSH 爆破(你已经调好了),CrowdSec 管 Nginx 层和社区情报。观察一两周,确认 CrowdSec 的场景和误封都符合预期后,再把 fail2ban 的 jail 逐个关掉。CrowdSec 引擎本身占内存不大(通常几十 MB),对低配 VPS 友好,真正吃资源的往往是 bouncer 里 IP 列表很大时的 reload 动作。
小结
fail2ban 适合「我就一台机器、被扫得不多」的场景,简单够用。CrowdSec 的价值在于决策与执行解耦和社区共享情报:一次封禁能在多台机器、多个执行器(防火墙/Nginx/Cloudflare)同时生效,且能白嫖别人封过的恶意 IP。对一个手上有多台 VPS、或者站点经常被扫描爆破的站长来说,它值得从 fail2ban 平滑迁移过去。核心动作就四步:装引擎、装 collection、配 acquis 日志源、装 bouncer——然后一定要手动验证一次封禁真的落地了,别让安全工具空转。