📚 离职知识库

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-stopped

searxng/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 就行。

#三个必须提醒他的事

  1. api 千万别本地 build —— 我这边编了 2 小时没完,把 8 核机器 IO 打爆、load 冲到 250+、SSH 连不上,服务器最后强制重启了。
  2. POSTGRES_DB 必须叫 postgres —— 官方 SELF_HOST.md 的建议是错的,照做会静默失败,表象是 api 无限重启刷 relation "nuq.queue_scrape" does not exist
  3. 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)