HeadlessX v2.1.2 配置参数详解

HeadlessX v2.1.2 三层配置体系拆解:.env 环境变量全量分组、安全强制键的启动校验与 AES-256-GCM 加密机制、/api/config 运行态配置实时修改实测,附 8-16 GB 内存档生产模板。

HeadlessX自托管REST API人工智能2026/10/24

HeadlessX v2.1.2 配置参数详解

HeadlessX 的配置分三层:环境变量(进程启动时读入,重启生效)、运行态配置(存数据库,改了即时生效)、安全强制校验(缺配置直接拒绝启动)。本文基于 《HeadlessX v2.1.2 Docker Compose 部署指南》 完成的标准部署,对每类参数做实测验证——所有输出均来自真实服务,参数行为均经重启或调用验证。

一、环境信息

项目说明
软件版本HeadlessX v2.1.2(仓库 main 分支,commit e3d938b)
部署形态标准部署(部署方法见本专栏部署篇,7 个服务全部运行)
服务器Ubuntu 22.04.4 LTS,12 核 32 GB,内网地址 192.168.146.128
服务端口API 38473,控制台 34872(官方默认值)

二、前置条件

  1. 已按部署篇完成 HeadlessX 部署并跑通 /api/health;
  2. 手上有一把 API Key:部署期的内部管理键(.env 中 DASHBOARD_INTERNAL_API_KEY 的值),或用它在 /api/keys 创建的用户键;
  3. 了解 .env 文件位置与编辑方法(见部署篇第 2 步;下文统一称"部署 .env")。

三、配置体系与查看方式

3.1 三层配置载体

层载体生效方式适用参数
环境变量部署 .env进程启动时读入,需重启服务进程端口、数据库、队列、外部服务地址、安全键
运行态配置PostgreSQL(控制台设置页 / PATCH /api/config)保存即生效,无需重启浏览器并发、stealth 档位、代理、浏览器窗口等
强制校验进程启动断言启动时检查,不满足拒绝启动两把安全键

3.2 环境变量的加载机制

API 进程按以下顺序寻找 .env 文件(源码 apps/api/src/env.ts):

  1. apps/api/.env.local(应用级,优先);
  2. 仓库根目录 .env;
  3. 两者都不存在时,直接使用进程注入的环境变量(标准部署即此形态,部署层已把部署 .env 注入进程环境)。

实测启动日志中的两处证据:

✅ Prisma migrations applied.
🚀 HeadlessX Backend running on http://0.0.0.0:8000
📂 Environment: production

进程内 dotenv 的注入行(标准部署下文件侧注入 0 个变量,值全部来自编排层注入):

[dotenv@17.2.3] injecting env (0) from .env

结论:标准部署改参数只改部署 .env,然后重启对应服务进程(启停命令见部署篇第十章);给应用目录另放 .env.local 属于源码开发形态,部署态不建议。

3.3 参数查看方式

看什么命令说明
运行快照(引擎/能力/并发)curl -s http://localhost:38473/api/health免认证
运行态配置全量curl -s http://localhost:38473/api/config -H "x-api-key: <APIKey>"13 项,可改
队列引擎状态curl -s http://localhost:38473/api/jobs/metrics -H "x-api-key: <APIKey>"队列可达性
各模块状态curl -s http://localhost:38473/api/operators/status -H "x-api-key: <APIKey>"搜索/YouTube/浏览器

环境变量属于进程启动参数,运行中无法通过 API 查询,以部署 .env 文件内容为准。

四、环境变量总览

部署 .env 的全部变量按用途分 7 组(★ 为强制必填,缺则拒绝启动):

① 安全强制类

变量默认值说明
DASHBOARD_INTERNAL_API_KEY ★(空)内部管理键:控制台服务端代理、/api/keys 管理命令的认证凭据;MCP 端点显式拒绝它
CREDENTIAL_ENCRYPTION_KEY ★(空)凭证加密键:派生 AES-256-GCM 密钥,加密存储的各平台登录态

② 端口类

变量默认值说明
POSTGRES_HOST_PORT35432数据库宿主端口
REDIS_HOST_PORT36379队列宿主端口
HTML_TO_MARKDOWN_HOST_PORT38081HTML→Markdown 微服务宿主端口
YT_ENGINE_HOST_PORT38090YouTube 引擎宿主端口
WEB_HOST_PORT34872控制台宿主端口
API_HOST_PORT38473API 宿主端口
PORT8000API 进程监听端口(内部,勿动)
WEB_PORT3000控制台进程监听端口(内部,勿动)
HOST0.0.0.0API 监听地址

③ 数据库类

变量默认值说明
POSTGRES_USERpostgres数据库用户
POSTGRES_PASSWORDpostgres数据库密码
POSTGRES_DBheadlessx数据库名
DATABASE_URLpostgresql://postgres:postgres@postgres:5432/headlessxAPI 进程使用的连接串
REDIS_URLredis://redis:6379队列连接串

④ 队列类

变量默认值说明
BULLMQ_QUEUE_NAMEheadlessx-jobsBullMQ 队列名
QUEUE_WORKER_CONCURRENCY2Worker 同时处理的作业数
QUEUE_JOB_ATTEMPTS3作业失败重试次数
QUEUE_JOB_BACKOFF_MS5000重试退避间隔(毫秒)
QUEUE_STREAM_POLL_MS1000事件流轮询间隔(毫秒)

⑤ 搜索引擎类

变量默认值说明
TAVILY_API_KEY(空)Tavily 云搜索键
EXA_API_KEY(空)Exa 云搜索键

⑥ YouTube 引擎类

变量默认值说明
YT_ENGINE_URLhttp://yt-engine:8090引擎服务地址
YT_ENGINE_TIMEOUT_MS45000引擎调用超时(毫秒)
YT_ENGINE_PORT8090引擎监听端口(内部)
YT_ENGINE_TEMP_DIR/app/tmp/yt-engine媒体暂存目录
YT_ENGINE_JOB_TTL_HOURS12产物保留时长(超时自动清理)

⑦ HTML→Markdown 与控制台类

变量默认值说明
HTML_TO_MARKDOWN_SERVICE_URLhttp://html-to-md:8080微服务地址
HTML_TO_MARKDOWN_TIMEOUT_MS60000微服务超时(毫秒)
NEXT_PUBLIC_API_URLhttp://localhost:38473控制台回连 API 的地址,远程访问改为 http://<服务器IP>:38473
INTERNAL_API_URLhttp://api:8000控制台内部回环地址(部署模板内服务名,勿改)
FRONTEND_URLhttp://localhost:34872API 侧记录的前端回调地址,远程访问同步改
BROWSER_WINDOW_WIDTH / HEIGHT(空,默认 1366×768)可选,覆盖浏览器窗口尺寸,非法值会告警忽略

服务间地址(REDIS_URL、YT_ENGINE_URL、INTERNAL_API_URL 等)在标准部署下保持模板值即可,它们指向部署网络内的固定服务名。

五、安全强制参数实测

5.1 校验逻辑

进程启动时执行 assertSecurityConfiguration()(源码 apps/api/src/utils/security.ts):检查两把安全键 trim() 后非空,任一为空即抛错终止,不设长度门槛。但 CREDENTIAL_ENCRYPTION_KEY 的实际用途是 sha256 派生 AES-256-GCM 密钥去加密凭证(密文带 enc-v1: 前缀),从强度出发务必用完整随机值:

openssl rand -hex 16

5.2 缺键拒绝启动(实测)

把部署 .env 中 DASHBOARD_INTERNAL_API_KEY 置空,重启 API 进程,服务立即失败,日志:

🚀 Starting HeadlessX API Server...
[dotenv@17.2.3] injecting env (0) from .env
❌ Failed to start server: Error: Missing required security environment variables: DASHBOARD_INTERNAL_API_KEY
    at assertSecurityConfiguration (/app/apps/api/src/utils/security.ts:29:15)
    at startServer (/app/apps/api/src/server_entry.ts:14:9)

把键值填回(本例 hx-dash-internal-b5b8f2e2453a5ab9519c57d006e446ff)并重启,恢复正常序列:

✅ Prisma migrations applied.
🚀 HeadlessX Backend running on http://0.0.0.0:8000
📂 Environment: production

⚠️ 两把键的对应关系:DASHBOARD_INTERNAL_API_KEY 泄露等于交出管理面(可创建/吊销用户键、读任务日志),CREDENTIAL_ENCRYPTION_KEY 泄露等于交出所有已保存的平台登录态,且更换加密键后旧密文无法解密——已存的登录态会失效,换键前请评估。

六、运行态配置详解(/api/config)

运行态配置存数据库,控制台"设置"页与 API 读写同一份。查询:

curl -s http://localhost:38473/api/config -H "x-api-key: hx_e9a271e7c086cb0f3ff3c2f9c49c0bbefc31fd02441f7c96"

实测输出(部署初值):

{"success":true,"config":{"browserHeadless":true,"browserTimeout":60000,"maxConcurrency":5,"stealthMode":"advanced","proxyEnabled":false,"proxyProtocol":"http","profileRotation":false,"profileRotationInterval":3600000,"camoufoxGeoip":true,"camoufoxBlockWebrtc":true,"camoufoxBlockImages":false,"camoufoxEnableCache":true,"camoufoxHumanize":2.5}}

13 项逐条解释:

配置项初值说明
browserHeadlesstrue无头模式;排障时改 false 观察浏览器窗口
browserTimeout60000单页操作超时(毫秒)
maxConcurrency5浏览器最大并发实例数
stealthModeadvanced隐匿档位(配合 Camoufox 指纹浏览器)
proxyEnabledfalse出口代理总开关
proxyProtocolhttp代理协议(http/socks5)
profileRotationfalse浏览器用户目录轮换开关
profileRotationInterval3600000轮换间隔(毫秒)
camoufoxGeoiptrueCamoufox 按 IP 一致性调整地理/区域指纹
camoufoxBlockWebrtctrue屏蔽 WebRTC 泄露真实 IP
camoufoxBlockImagesfalse屏蔽图片加载(省流提速,可能影响截图)
camoufoxEnableCachetrue浏览器缓存开关
camoufoxHumanize2.5拟人化鼠标/交互强度

修改实测——把并发从 5 降到 3:

curl -s -X PATCH http://localhost:38473/api/config \
  -H "x-api-key: hx_e9a271e7c086cb0f3ff3c2f9c49c0bbefc31fd02441f7c96" \
  -H "Content-Type: application/json" \
  -d '{"maxConcurrency":3}'

实测返回(maxConcurrency 已变为 3,保存即生效,无需重启):

{"success":true,"config":{...,"maxConcurrency":3,"stealthMode":"advanced",...}}

GET /api/health 的快照同步变化。测完恢复 {"maxConcurrency":5}。

与运行态相关的另一处入口是 /api/health,它反映的 maxConcurrency、stealthMode、proxy 与 /api/config 同源:

{
  "status": "online",
  "capabilities": { "website": true, "search": false, "youtube": true },
  "captchaModels": { "classification": false, "detection": false },
  "searchProviders": { "tavily": false, "exa": false },
  "maxConcurrency": 5,
  "stealthMode": "advanced",
  "proxy": { "enabled": false, "count": 0 }
}

(search: false、searchProviders 双 false 是未配置 Tavily/Exa 键的正常表现;captchaModels 双 false 是未放置可选 ONNX 模型。)

七、外部模块参数实测

队列参数:QUEUE_WORKER_CONCURRENCY=2 等队列参数随 Worker 进程启动生效。实测提交 crawl 作业后,Worker 日志出现完整生命周期:

👷 HeadlessX Queue Worker is running
📋 Job created: 36517871-50cb-4596-928d-eb83210e280f
📋 Job 36517871-50cb-4596-928d-eb83210e280f status: running
✅ Queue job completed: 36517871-50cb-4596-928d-eb83210e280f

GET /api/jobs/metrics 确认队列引擎可达:

{"success":true,"metrics":{"queueName":"headlessx-jobs","redisTarget":"redis://redis:6379","available":true,"counts":{"active":1,"waiting":0,"delayed":0,"completed":0,"failed":0,"paused":0}}}

搜索引擎参数:TAVILY_API_KEY、EXA_API_KEY 留空时模块状态实测(/api/operators/tavily/status):

{"success":true,"data":{"status":"online","configured":false,"service":"tavily-v1"}}

configured: false 表示服务在线但未配键,真正调用搜索面时会报未配置。填入有效键并重启 API 进程后此状态翻转为 true。

YouTube 引擎参数:/api/operators/youtube/status 实测:

{"success":true,"data":{"status":"online","configured":true,"service":"yt-dude-v1","ffmpeg_available":true,"temp_dir":"/app/tmp/yt-engine","job_ttl_hours":12}}

configured: true 表示引擎服务就绪(这与 TAVILY_API_KEY 的语义不同:引擎是自托管组件,配好即在线)。但引擎就绪 ≠ YouTube 可达:本例服务器出口无法访问 YouTube,/api/operators/youtube/info 45 秒后按 YT_ENGINE_TIMEOUT_MS 超时报 YOUTUBE_ENGINE_FAILED。这类"参数全对但出口不通"的情况需先解决服务器出网。

八、生产配置模板(8-16 GB 内存档)

在官方默认基础上建议改动的项(其余保持默认):

# ── 安全键:务必重新生成,不要照抄 ──
DASHBOARD_INTERNAL_API_KEY=<openssl rand -hex 16 输出>
CREDENTIAL_ENCRYPTION_KEY=<openssl rand -hex 16 输出>

# ── 数据库:改默认密码,并与 DATABASE_URL 同步 ──
POSTGRES_PASSWORD=<强密码>
DATABASE_URL=postgresql://postgres:<强密码>@postgres:5432/headlessx

# ── 远程访问:按服务器实际地址填写 ──
NEXT_PUBLIC_API_URL=http://<服务器IP>:38473
FRONTEND_URL=http://<服务器IP>:34872

# ── 搜索面:用到才填 ──
TAVILY_API_KEY=<你的Tavily键>
EXA_API_KEY=<你的Exa键>

# ── 队列:8 GB 内存档建议保守并发 ──
QUEUE_WORKER_CONCURRENCY=2
QUEUE_JOB_ATTEMPTS=3

资源取向:每个浏览器实例约占 0.5~1 GB 内存,16 GB 服务器建议运行态 maxConcurrency 不超过 6、QUEUE_WORKER_CONCURRENCY 保持 2;主服务部署产物内含指纹浏览器束(约 0.7 GB),磁盘预留 20 GB。

九、常见问题

Q1:改了部署 .env 不生效?

环境变量在进程启动时读入。改完必须重启所有引用该变量的服务进程(安全键、数据库、队列参数涉及 api 与 worker 两个进程;控制台类参数涉及 web 进程)。只改文件不重启是最常见的"配置失效"。

Q2:NEXT_PUBLIC_API_URL 改了之后要不要重新构建?

标准部署不需要。该值在控制台服务端被消费(源码中仅服务端引用),属于运行时注入,改部署 .env 后重启 web 进程即生效。只有源码开发形态(本地构建前端)才涉及构建期注入问题。

Q3:改了 POSTGRES_PASSWORD 后数据库连不上?

DATABASE_URL 里写死了密码,两处必须同步改。只改 POSTGRES_PASSWORD 不改 DATABASE_URL,API 进程会用旧密码连接新密码库,报认证失败。

Q4:运行态配置和环境变量重复的参数以谁为准?

maxConcurrency、stealthMode 等运行态项只认数据库配置(.env 中没有对应变量),两者不冲突;/api/health 展示的永远是运行态值。环境变量管"进程级"(端口、连接、超时),运行态管"行为级"(浏览器、代理、隐匿),职责不重叠。

Q5:安全键可以填短一点好记吗?

校验只要求非空,短键也能启动。但内部管理键等价于管理面凭据、加密键等价于凭证保险柜钥匙,强烈建议 openssl rand -hex 16 生成 32 位随机值。注意加密键一经使用就不要再换——换键后旧密文无法解密。

Q6:搜索键填错了怎么发现?

看 /api/operators/tavily/status(或 exa):服务在线返回 configured: true 只代表键存在,键无效会在实际调用时暴露,任务日志(GET /api/logs)里会留下失败记录。

十、参考链接