Firecrawl 自建实例:吃多少资源 & 怎么分享给朋友
记录日期:2026-07-25 配套文档:
~/Desktop/Firecrawl自建实例-部署与卸载.md(部署清单 + 卸载流程)、~/Desktop/配置信息/Firecrawl自建实例.md(凭据 + 运维)
#一、资源占用实测
机器:东京 VPS(tky),8 核 AMD EPYC-Turin / 62GB 内存 / 450G 盘。
#内存:空闲时合计约 3.7 GB
以下是完全空闲(没有任何抓取任务)时的实测值:
| 容器 | 内存占用 | 上限 | 说明 |
|---|---|---|---|
firecrawl-api-1 |
2.78 GB | 8 GB | 大头。里面跑 10 个 Node 进程(api + worker + extract-worker + 5×nuq-worker + prefetch + reconciler) |
firecrawl-playwright-service-1 |
402 MB | 4 GB | Chromium 常驻 |
firecrawl-rabbitmq-1 |
335~377 MB | — | 消息队列 |
firecrawl-searxng-1 |
124 MB | — | 搜索后端 |
firecrawl-nuq-postgres-1 |
95 MB | — | 队列数据库 |
firecrawl-redis-1 |
6 MB | — | 缓存 |
| 合计 | ≈ 3.7 GB |
放在 62GB 的机器上占 6%,全机 free -h 显示 used 5.4GB(含 llm-relay 等其它服务),完全不吃紧。
抓取时会涨多少:主要是 playwright-service 每开一个页面涨几十到一两百 MB,上限锁死在 4GB;api 容器上限 8GB。最坏情况整套约 12GB 封顶,这是 compose 里写死的硬限制,不会失控。
#磁盘:约 6.7 GB 镜像 + 一堆构建缓存
| 项目 | 大小 |
|---|---|
| Docker 镜像(含 llm-relay 等共用的) | 6.7 GB |
| 其中 Firecrawl 专属 | ≈ 5.5 GB |
<HOME>/firecrawl 代码目录 |
83 MB |
| Docker 构建缓存 | 8.82 GB(其中 6.58 GB 可回收) |
那 8.8GB 构建缓存是第一次尝试本地编译 Rust 留下的垃圾。建议清掉:
ssh <VPS> "docker builder prune -af"
#CPU:有个坑,已经踩到了
RabbitMQ 的 Erlang 虚拟机默认开启忙等(busy-wait)——它在完全空闲的时候也会主动空转烧 CPU。实测这台机器上它空转就吃掉 5.7 个核(8 核机器),load average 被顶到 18,而用户态 CPU 实际只有 1%。
试过用官方推荐的 RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS='+sbwt none +sbwtdcpu none +sbwtdio none' 关掉忙等,结果是这个环境变量会覆盖掉官方镜像自带的必要启动参数,Erlang VM 直接起不来(日志全空、健康检查永远超时)。所以这条路走不通。
目前的处理是在 docker-compose.override.yaml 里给 rabbitmq 加 cpus 硬限制——忙等还在,但圈在限定核数里,不再拖垮整机。
如果朋友要自己装,这个坑一定要提前说:在 1~2 核的小机器上,RabbitMQ 空转会把 CPU 直接吃满,机器基本没法用。2 核以下不要碰这套东西。
⚠️ 另外记一笔:写这份文档时 tky 出现了
st(steal time)97% 的情况——即宿主机层面只分给这台 VM 约 3% 的 CPU。这不是 Firecrawl 造成的(用户态 CPU 只有 0.4%),是 Vultr 那边的事(大概率是之前那次 2.5 小时的本地编译烧光了突发额度被限流,或者是邻居机器闹的)。等它自己恢复,恢复期间 api 容器起不来属正常现象。
#一句话结论
内存不是问题,CPU 才是。 内存 3.7GB 空闲占用对 4GB 以上的机器都算友好;但 RabbitMQ 的忙等特性决定了这套东西必须放在至少 4 核的机器上才不难受。
#二、朋友想用,怎么搞
先分清他到底要哪种。这是两条完全不同的路,成本和心智负担差一个数量级。
| 方案 A:共用你的实例 | 方案 B:他自己装一套 | |
|---|---|---|
| 他要做的事 | 拿一个 token,改一行配置 | 买机器、部署、以后自己维护 |
| 成本 | 0(蹭你的服务器) | 一台 4 核以上 VPS,约 $20~40/月 |
| 出口 IP | 你的(东京 |
他自己的 |
| 谁背锅 | 你(他爬什么、被谁封,算在你头上) | 他自己 |
| 你的维护负担 | 长期。他一报"抓不到"就得找你 | 一次性给份文档就完事 |
| 适合 | 短期试用、少量抓取、关系够铁 | 长期用、量大、或者他自己也是技术人 |
#我的建议
先给方案 A 让他试用,明确说好是临时的;他真用上瘾了再推他走方案 B。
理由很直接:出口 IP 是你的。他要是拿去大批量爬电商、爬社交平台,被目标站封的是你这个 IP,连带影响你自己的抓取和 tky 上其它服务。而且 Firecrawl 自建版没有反爬引擎,他一遇到抓不动就会来问你——那是他的目标站的问题,不是你能修的,但解释成本落在你身上。
#方案 A:给他开个 token 共用
#现状
现在 nginx 里是写死的单个 token:
if ($http_authorization != "Bearer <KEY>") { return 401; }别把这个 token 直接给朋友——你俩用同一个,出了事分不清是谁干的,也没法单独把他停掉。
#改成多 token(推荐做法)
下面这段配置是建议方案,还没部署。要用的话跟我说一声,我改完验证一遍。
在 /etc/nginx/sites-available/firecrawl.saveme505.help 里,把 if 判断换成 map + 限速:
# 放在 http 块(/etc/nginx/nginx.conf 或单独 conf.d 文件)
map $http_authorization $fc_user {
default "";
"Bearer <KEY>" "leo";
"Bearer <KEY>" "friend1";
}
# 按用户分别限速,朋友那份给紧一点
limit_req_zone $fc_user zone=fc_limit:10m rate=30r/m;server 块里:
location / {
if ($fc_user = "") { return 401; }
limit_req zone=fc_limit burst=10 nodelay;
# 日志里记清楚是谁调的,方便回溯
access_log /var/log/nginx/firecrawl-access.log;
proxy_pass http://127.0.0.1:3002;
# ...其余 proxy_set_header 保持不变
}生成他那份 token:
python3 -c "import secrets; print('fc-friend-' + secrets.token_hex(20))"#给朋友的使用说明(可以直接转发给他)
接口地址:https://firecrawl.saveme505.help
认证:请求头带 Authorization: Bearer <你的 token>
接口格式跟官方 Firecrawl 完全一致,文档看 https://docs.firecrawl.dev
curl 示例:
curl -X POST https://firecrawl.saveme505.help/v1/scrape \
-H "Authorization: Bearer <你的 token>" \
-H 'Content-Type: application/json' \
-d '{"url":"https://example.com","formats":["markdown"]}'
如果你也用 Claude Code,MCP 这么配:
{
"command": "npx",
"args": ["-y", "firecrawl-mcp"],
"env": {
"FIRECRAWL_API_URL": "https://firecrawl.saveme505.help",
"FIRECRAWL_API_KEY": "<你的 token>"
}
}
能用的接口:/v1/scrape、/v1/map、/v1/crawl、/v1/search、/v1/parse
用不了的:agent、monitor、research、interact(这些是 Firecrawl 云端专属功能,自建版没有)
注意:没有反爬引擎,Cloudflare 之类强风控的站点大概率抓不动,这个改不了。#要停掉他的时候
把 map 里他那行删掉,systemctl reload nginx,立刻生效。不影响你自己。
#方案 B:他自己装一套
#机器要求
- CPU:至少 4 核(RabbitMQ 忙等的坑,见第一部分。2 核以下别试)
- 内存:8GB 起步,16GB 舒服
- 磁盘:20GB 以上(镜像就 5.5GB)
- 系统 Ubuntu / Debian,装好 Docker + Docker Compose v2
#部署步骤(照抄即可,坑都填好了)
git clone --depth 1 https://github.com/firecrawl/firecrawl.git <HOME>/firecrawl
cd <HOME>/firecrawl第 1 步:改成用官方预构建镜像(关键,否则本地编译 Rust 要两小时以上,还可能把机器打挂)
编辑 docker-compose.yaml,把开头的:
x-common-service: &common-service
# image: ghcr.io/firecrawl/firecrawl
build: apps/api改成:
x-common-service: &common-service
image: ghcr.io/firecrawl/firecrawl:latest第 2 步:写 .env
PORT=3002
HOST=0.0.0.0
USE_DB_AUTHENTICATION=false
BULL_AUTH_KEY=<随机字符串>
POSTGRES_USER=firecrawl
POSTGRES_PASSWORD=<随机密码>
# 库名必须是 postgres!镜像把 pg_cron 的 cron.database_name 硬编码成 postgres,
# 改成别的名字会让初始化脚本中断,队列表一张都建不出来
POSTGRES_DB=postgres
# 不配这个 /v1/search 就是废的
SEARXNG_ENDPOINT=http://searxng:8080
# 默认 60 秒不够,api 容器要拉起 10 个子进程,会超时自杀形成重启循环
HARNESS_STARTUP_TIMEOUT_MS=300000
NUM_WORKERS_PER_QUEUE=8
CRAWL_CONCURRENT_REQUESTS=10
MAX_CONCURRENT_JOBS=5
BROWSER_POOL_SIZE=5
LOGGING_LEVEL=info第 3 步:加 SearXNG(官方 compose 里没有,但 /v1/search 全靠它)
docker-compose.override.yaml:
services:
searxng:
image: searxng/searxng:latest
environment:
SEARXNG_BASE_URL: http://searxng:8080/
SEARXNG_SECRET: '<随机 64 位十六进制>'
volumes:
- ./searxng:/etc/searxng:rw
networks:
- backend
restart: unless-stopped
api:
ports: !override
- '127.0.0.1:3002:3002'
restart: unless-stopped
redis:
restart: unless-stopped
rabbitmq:
restart: unless-stopped
cpus: 4.0 # 圈住 Erlang 忙等,别让它吃满整机
nuq-postgres:
restart: unless-stopped
playwright-service:
restart: unless-stoppedsearxng/settings.yml:
use_default_settings: true
server:
secret_key: '<跟上面同一个>'
limiter: false
image_proxy: false
method: 'GET' # firecrawl 走 GET,默认是 POST
search:
safe_search: 0
formats:
- html
- json # 必须显式放开 json,默认只有 html
general:
debug: false第 4 步:启动(务必显式列服务名,别裸跑 docker compose up)
docker compose up -d api playwright-service redis rabbitmq nuq-postgres searxng为什么要列服务名:compose 里还有
foundationdb/foundationdb-init两个实验性服务, 没写 profile,裸跑会把它们也拉起来,白占资源还可能报错。
第 5 步:验证
# 抓取
curl -X POST http://127.0.0.1:3002/v1/scrape \
-H 'Content-Type: application/json' \
-d '{"url":"https://example.com","formats":["markdown"]}'
# 搜索(返回空数组也是 HTTP 200,要看 data 里有没有东西)
curl -X POST http://127.0.0.1:3002/v1/search \
-H 'Content-Type: application/json' \
-d '{"query":"test","limit":3}'第 6 步:对外暴露(如果需要)
⚠️ Firecrawl 自建版 USE_DB_AUTHENTICATION=false,自身不校验任何 key。直接挂公网 = 送全世界一个免费爬虫代理。 必须在 nginx 层加认证:
location /admin/ { return 404; } # 队列管理台必须屏蔽
location / {
if ($http_authorization != "Bearer <他的 token>") { return 401; }
proxy_pass http://127.0.0.1:3002;
proxy_read_timeout 300s; # 爬取耗时长,默认 60s 不够
# ...
}只自己本机用的话,最简单是根本不对外暴露,保持 127.0.0.1:3002 就行。
#三个必须提醒他的事
- api 千万别本地 build —— 我这边编了 2 小时没完,把 8 核机器 IO 打爆、load 冲到 250+、SSH 连不上,服务器最后强制重启了。
POSTGRES_DB必须叫postgres—— 官方 SELF_HOST.md 的建议是错的,照做会静默失败,表象是 api 无限重启刷relation "nuq.queue_scrape" does not exist。- RabbitMQ 空转吃 CPU —— 4 核以下的机器装了会很难受。
#三、附:自建版能力边界(两个方案都适用)
| 能用 | 用不了(Firecrawl 云端专属) |
|---|---|
firecrawl_scrape |
firecrawl_agent / agent_status |
firecrawl_map |
firecrawl_monitor_* 全套 |
firecrawl_crawl / check_crawl_status |
firecrawl_research_*(论文 / GitHub 检索) |
firecrawl_search(靠 SearXNG) |
firecrawl_interact / interact_stop |
firecrawl_parse |
firecrawl_feedback / search_feedback |
firecrawl_extract(需另配 LLM) |
其它差异:
- 没有 fire-engine(官方的反爬 / 绕 IP 封锁引擎),Cloudflare 之类强风控站点大概率抓不动,必要时得自己配
PROXY_SERVER。 - 搜索质量看 SearXNG —— 底层聚合 Google/Bing,被限流时结果会变少,不如官方稳。
/v1/extract默认不可用,要在.env配 LLM。你这边可以直接指向自己的中转:OPENAI_BASE_URL=https://relay.saveme505.help/v1 OPENAI_API_KEY=<new-api 的 key> MODEL_NAME=deepseek-chat
来源:沉淀/01-云与基础设施/Firecrawl-资源占用与分享给朋友.md(整理于 2026-08-18)