---
canonical: https://meta.cyberforums.com/t/forgejo-nginx/1828
webpage: https://wpcy.com/community/t/1828-forgejo-nginx
language: zh-Hans
---

# Forgejo 镜像仓库遭遇分布式爬虫：从发现到 nginx 拦截的完整排查

> 文派叶子支持论坛的只读副本，本页不能回复。
> 讨论原文：https://meta.cyberforums.com/t/forgejo-nginx/1828
> 网页版：https://wpcy.com/community/t/1828-forgejo-nginx

## 1 · devops

- 发布时间：2026年3月1日 03:31

问题描述
自托管 Forgejo 实例（500+ 仓库，其中 484 个是 GitHub 镜像）持续高负载，CPU 1220%，load average 19+。
排查过程
1. 定位进程
通过容器监控发现 Forgejo 容器 CPU 1220%，内存 936MB。
2. 分析请求日志
容器日志显示 272 requests/min，其中 261 是 git-heavy 路径（96%）。大量来自不同 IP 的请求，全部在爬镜像仓库的 commit/blame/src 页面，每个请求耗时 100-1100ms。
3. 确认是分布式爬虫
每个 IP 只出现 1 次 — 典型的分布式爬虫/僵尸网络。
关键特征：

每个 IP 只发 1-2 个请求，绕过 per-IP 限流
使用正常 User-Agent（Chrome 100+），绕过 UA 检测
只爬 commit/blame/src 等 git 重型路径
目标全是镜像仓库（Discourse 501、woocommerce 220、mautic 121…），0 个原创仓库请求

4. 已有防护为什么失效
之前已经部署了三层防护：robots.txt 禁止爬取、per-IP 限流（rate=3r/s）、UA 检测（map 恶意 bot）。
全部失效原因：

robots.txt：爬虫根本不遵守
per-IP 限流：分布式爬虫每个 IP 只来一次，永远不会触发
UA 检测：用的是正常浏览器 UA

解决方案
核心思路：按仓库归属区分处理
镜像仓库的 commit/blame 页面对用户没有价值（要看历史去 GitHub 原仓库），直接 403。原创仓库正常放行。
遇到的坑：nginx location 优先级
第一版用独立的 location 正则匹配，但不生效。原因是 location ^~ 前缀匹配优先级高于 location ~ 正则匹配。所有请求被 ^~ / 吃掉，正则 location 永远不会执行。
正确方案：在 ^~ location 内部用 if
在 catch-all 的 ^~ / location 内部，通过 if 判断 request URI 是否匹配 git-heavy 路径模式，同时用负向前瞻排除原创仓库用户名。匹配到的直接 return 403。
关键点：

用负向前瞻排除原创仓库用户名
必须放在 ^~ / 内部，独立 location 会被吞掉
URL 匹配要覆盖 blame、commit、src/commit、commits/commit、raw/commit 等变体

效果




指标
处理前
处理后




Load Average
19+
12


Forgejo CPU
1220%
约 850%


git-heavy 200/min
261
约 13


403 拦截率
0%
约 95%



剩余少量漏网请求是一些变体路径（如 .diff 后缀），影响已经很小。
经验总结

分布式爬虫的核心特征：每个 IP 只来 1-2 次，用正常 UA，per-IP 限流和 UA 检测完全无效
nginx location 优先级：^~ 优先于 ~。如果有 ^~ / catch-all，正则 location 永远不会匹配
镜像仓库不需要 git 历史浏览：直接 403 是最有效的方案，用户要看历史去上游仓库
robots.txt 只防君子：对恶意爬虫毫无作用，必须在 nginx 层硬拦
全局限流对分布式爬虫也有限：请求量大时 burst 很快用完，但新请求源源不断
