一个 TUI、一个 Web 控制台和一个 CLI,帮助你配置服务器以阻止恶意机器人,而无需隐藏在 CDN 后面。
它与 NGINX 和你现有的防火墙(nftables 或 iptables)协同工作:

该应用会尽力避免将你锁在服务器之外,但使用风险由你自己承担。另请注意,它采用 AGPL 许可,因此如果你将其用于商业用途,请确保遵守该许可。
在 Debian 或 Ubuntu 上,从 APT 仓库安装:
curl -fsSL https://ivankovic.github.io/stop-bots/key.gpg \
| sudo tee /usr/share/keyrings/stop-bots.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/stop-bots.gpg] \
https://ivankovic.github.io/stop-bots stable main" \
| sudo tee /etc/apt/sources.list.d/stop-bots.list
sudo apt update && sudo apt install stop-bots
该软件包提供 man stop-bots(以及每个动词对应的手册页,例如 man stop-bots-batch)以及
bash、zsh 和 fish 补全。它不安装任何服务,也不启动任何内容。
或者从 crates.io 安装,需要 Rust 1.88 或更高版本:
cargo install stop-bots
或者从 GitHub releases 下载适用于 x86_64 或 aarch64 Linux 的静态二进制文件。
install 会拒绝非 Debian
或其衍生版本的主机。nft,或 iptables-restore 和 ip6tables-restore;
其余功能需要 nginx。NGINX 运行在容器中也可以——参见
在容器中运行 NGINX。sudo stop-bots 启动 TUI。它需要 root 权限:它会重写 /etc/nginx 并加载防火墙
规则。u 下载所有列表:机器人列表、爬虫 IP 范围,以及你启用的任何订阅源或国家/地区。1)包含主机级策略:哪些机器人类别被阻止、
国家/地区,以及读取日志的检测器。在 NGINX 屏幕(4)上,r 查找你的
站点。Blocks 屏幕(5)列出检测器或你添加的每条规则,以及原因。a 应用所有内容。它首先显示将会发生的变化——文件、添加和
删除的规则,以及锁定检查的结论(d 查看差异)——然后询问。sudo stop-bots install firewall 使已应用的规则在重启后仍然有效。没有它,
重启后所有规则都会丢失。sudo stop-bots status 检查内核、单元和文件,并说明缺少
什么。sudo stop-bots status
sudo stop-bots batch --dry-run --diff
sudo stop-bots batch --apply
sudo stop-bots install firewall
sudo stop-bots status
batch --dry-run 不会下载或扫描任何内容:在全新安装时,它会显示二进制文件中内置的机器人列表中的 NGINX 块,并且还没有防火墙规则,因为尚未从你的日志中读取任何内容。不带 --apply 的 sudo stop-bots batch 会执行下载和扫描,并写入文件以供审查,但不会强制执行它们。关于 batch 的功能,请参阅无人值守,来自 cron。
sudo stop-bots uninstall all --dry-run
sudo stop-bots uninstall all
第一个列出每一步,第二个执行它们。参见 升级与卸载。
已知机器人,按类别(扫描器 / 搜索引擎 / AI 爬虫),来源于
ArcJet 的 Well-Known Bots、
ai.robots.txt 以及
NGINX Ultimate Bad Bot Blocker
列表。屏蔽某个类别会向每个站点的 NGINX 配置注入一条 if ($http_user_agent ...) 规则。
请求过多,通过 NGINX 自身的速率限制。
先礼后兵 —— 生成一个 robots.txt,列出你正在屏蔽的每个机器人,供遵守它的爬虫读取,外加下方的蜜罐路径。
除你另有说明之处 —— 按站点的路径豁免,以及受信任的地址和用户代理(trust),任何屏蔽、列表或速率限制都不适用于它们。
看起来不像浏览器的请求,按站点。六条独立规则,每条都有自己的开关,且默认全部关闭 —— 每条规则一个开关,这样如果你自己的某个东西停止工作,你能判断是哪条规则导致的:
| 规则 | 除机器人外还会拒绝 |
|---|---|
| HTTP/1.0 和 HTTP/1.1 | 不支持 HTTP/2 的爬虫和 API 客户端 |
无 Accept 头 | 某些 API 客户端不发送 |
无 Accept-Language | 隐私工具会将其剥离 |
空/缺失的 User-Agent | 脚本和健康检查常常省略它 |
Host 是裸 IP | 会破坏通过 IP 访问站点 |
| TLS 1.0 / 1.1 | 仅限非常旧的客户端 |
有七种选择:
| 选项 | 用途 |
|---|---|
403 Forbidden(默认) | 表明屏蔽是故意的;是唯一一个被误伤的人能据此采取行动的选项 |
404 Not Found | 隐藏任何被屏蔽的迹象 |
410 Gone | 请求行为良好的爬虫永久丢弃该 URL —— 当你是在拒绝爬虫而非攻击者时,优先用它而非 403 |
429 Too Many Requests | 告诉有礼貌的客户端退避并重试 |
418 I'm a teapot | RFC 2324 的玩笑。它能用;只是未在 IANA 注册,且 NGINX 发送它时带空响应体 |
444 close connection | 完全不回复;最省资源,但与服务器宕机无法区分 |
Tarpit | 回复 403,但以每秒一字节的速度缓慢发送响应体,让客户端等待而不是继续前进 |
对于误报,tarpit 是最温和的选项 —— 被误伤的客户端只是被拖慢,而非被拒绝 —— 而对机器人来说成本最严苛,其连接会一直闲置。选择它之前需要知道一件事:它同样会在整个过程中占用你的一个 worker 连接,因此大量被 tarpit 的客户端会与真实访客争夺 worker_connections。
以下每一项都是 Dashboard 的 "Automatic blocking" 面板上的独立开关,或 CLI 上的 set-detector。每一项都会添加一条定时的防火墙屏蔽。使用 nftables 时,内核会在其到期时解除;使用 iptables 时,它会一直保留到脚本下次被应用。
检测是按窗口进行的:检测器只统计其窗口内日志显示的内容(一天,或下方三个行为类检测器为一小时;set-detector --window-hours 可更改),且一次屏蔽会消耗掉促成它的证据。因此,过期的屏蔽只会因新的违规而再次出现,而首次扫描绝不会因旧日志行而屏蔽。list-detectors 显示每个检测器的开关、屏蔽时长、阈值和窗口。
它们运行在一个内部定时器上,每分钟重新读取你的 SSH 和 NGINX 访问日志 —— 但仅在 TUI 或 Web UI 运行时。 两者任一都保持相同的调度、相同的数据库,因此让 Web UI 保持运行就足够了;两者都不运行时不会检测任何东西。对于完全没有 stop-bots 进程的服务器,参见下方的无人值守,通过 cron。
前五个在新数据库中默认开启:
/.env、/.git/config、/wp-config.php 及类似路径的单次请求即立即封禁。内置列表刻意省略了在某些地方合法的路径 —— /wp-login.php、/wp-admin/、/xmlrpc.php、/phpmyadmin —— 因为锁死你自己的管理员会比漏掉一个反正会被 404 检测器捕获的扫描器更糟。用 set-probe-paths 添加你自己的路径。${jndi: 查找、PHP-CGI allow_url_include 漏洞利用、$(wget …) 或 ../../,无论其如何编码。一次请求就足够,且屏蔽持续一周。人可能输入的文本,例如 /etc/passwd 或 union select,只在搜索框和 referer 之外才计数,因此在博客中搜索它是安全的。默认关闭:
robots.txt 中作为 Disallow: 公布、且无处链接的路径。到达它意味着无视 robots.txt,理应被封禁。需要开启 robots.txt 生成才能工作。另外三个检测器看的是客户端行为而非它请求什么。三者默认全部关闭,因为每个都有误报 —— 且三者都豁免已验证的搜索引擎爬虫,否则它们会匹配上每一个:
304 算作已获取的资源)。在完全不提供任何资源的站点上帮不了你。Referer。会被 Referrer-Policy: no-referrer 和隐私工具削弱;不同路径阈值使其可用。任何检测器都不会屏蔽 Cloudflare 边缘地址 —— 屏蔽一个边缘会屏蔽所有经由它路由的人。如果你的站点在 Cloudflare 后面,且 NGINX 记录的是边缘而非访客,检测器就谁也屏蔽不了。此时 status 会警告(cdn-edges)并给出让 NGINX 重新记录访客的 set_real_ip_from 和 real_ip_header 行。
/24 中的多个地址在同一次扫描中被标记时,屏蔽该 /24(set-subnet-escalation)。默认关闭 —— 因为三个行为不端就屏蔽 256 个地址,按设计就是附带损害。(IPv6 不同,无需开关:一次检测总是屏蔽 /64,因为一个 /64 就是一个 LAN,等同于单个 IPv4 地址所代表的东西。屏蔽 IPv6 攻击者恰好使用的单个地址什么也阻止不了 —— 他们还有 2^64 个。)add-firewall-rule。每个决策都是生成的,绝不自动应用。
一次渲染会写入 /etc/stop-bots/firewall.next.nft(或 iptables 的 firewall.next.sh),没有任何东西会加载它。只有成功的应用才会把它复制为 firewall.nft,即启动单元加载的脚本。有三种方式会应用,且都需要你主动请求:
a("apply everything"),或勾选 "apply after writing" 后按 F。render-firewall --apply 和 batch --apply —— 参见无人值守,通过 cron。a 和 "Apply everything…" 会先显示将发生什么变化 —— 文件、添加和移除的规则,以及锁定检查的结论,可按需显示 diff —— 然后询问。从 CLI,batch --dry-run 打印相同内容且不做任何更改;--diff 添加每个文件的统一 diff。
两个开关让内部定时器替你应用:set-auto-apply(NGINX,每小时)和 set-auto-apply-firewall。除非你打开它们,否则两者都关闭,且第二个除非锁定检查能实际运行,否则拒绝应用。
NGINX 侧同样如此:更改设置只会改变将要写入的内容。NGINX 屏幕会将每个站点显示为 STALE,直到你应用。