Inventaire 5.1.1 配置参数详解
Inventaire 5.1.1 全量配置参数详解:node-config 三层加载机制、/api/config 查看与 local.ts、NODE_CONFIG 修改实测(含优先级验证)、CouchDB/Elasticsearch/邮件/媒体存储/联邦/安全限流逐项说明与两种形态的生产模板,均在 Ubuntu 22.04 与 Compose 双环境实测。
Inventaire 5.1.1 配置参数详解
目标:系统梳理 Inventaire 5.1.1 服务端的全部配置参数——配置加载机制、参数查看与修改方法、逐项参数语义与生产推荐模板。本文全部命令与回显均在两套实测环境执行通过:① Ubuntu 22.04 源码安装环境(Node.js 20.20.2 + CouchDB 3.5.3 + Elasticsearch 7.17.29,systemd 托管);② Docker Compose 官方套件部署环境(inventaire/inventaire:5.1.1 + couchdb:3.4.2 + elasticsearch:7.17.28)。实测日期 2026-10-24。
一、环境信息
本文实测覆盖两种部署形态,配置机制相同、参数来源不同,读者按自己的形态对号入座:
环境 ①:源码安装(Ubuntu 22.04)
| 项目 | 实测值 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS(x86_64) |
| Inventaire 版本 | 5.1.1(/api/config 返回 serverGitHeadRev: 2263179) |
| Node.js | v20.20.2(nvm 安装) |
| CouchDB | 3.5.3(systemd 服务 couchdb.service,监听 127.0.0.1:5984) |
| Elasticsearch | 7.17.29(systemd 服务 elasticsearch.service,监听 127.0.0.1:9200) |
| 服务监听端口 | 3006(默认开发/单机端口) |
| 项目根目录 | /home/inventaire/inventaire |
| 配置目录 | /home/inventaire/inventaire/config/ |
环境 ②:Docker Compose 官方套件
| 项目 | 实测值 |
|---|---|
| Inventaire 镜像 | inventaire/inventaire:5.1.1(serverGitHeadRev: 3ba29ff) |
| CouchDB | couchdb:3.4.2(套件自建层) |
| Elasticsearch | 7.17.28(套件 compose 固定) |
| 服务监听端口 | 3016(联邦模式端口),宿主机映射 8138 |
| 配置来源 | 容器内 /opt/inventaire/dist/config/local.js(entrypoint 每次启动重新生成) |
两种形态的参数语义完全一致(同一套 node-config 配置体系),差异只在「参数从哪来、怎么改」:源码安装直接编辑
config/local.ts;Compose 形态通过.env与NODE_CONFIG注入。均见第三章实测。
二、前置条件
阅读与操作本文的前提:
- 已按 《Inventaire 5.1.1 Docker Compose 部署指南》或源码安装方式完成部署,服务可访问(验证命令
curl -s http://localhost:3006/api/config或映射端口等价形式,返回 JSON 即可); - 源码安装形态需要对项目目录的写权限(
config/local.ts属于部署用户)与重启服务的能力(本文以tsx server/server.ts启动的进程为例,systemd 托管时等价执行systemctl restart inventaire); - Compose 形态需要能编辑部署目录下的
.env与docker-compose.yml覆盖文件,并执行docker compose up -d重建服务; - 了解 JSON 与 JavaScript 对象字面量基本语法(配置文件即 JS 模块)。
三、参数查看与修改方式
Inventaire 服务端配置基于 node-config 机制:全部参数有一个内置默认值(config/default.ts),再按环境叠加覆盖文件,最终形成运行时生效值。本章先讲「怎么看到生效值」,再讲「怎么改」。
3.1 查看生效参数:GET /api/config
服务内置一个公开的配置查看端点 GET /api/config,返回对外可见的生效参数(实例信息、对外地址、地图服务等,不含数据库密码等敏感项):
curl -s http://localhost:3006/api/config | python3 -m json.tool
实测回显(环境 ①,源码安装、默认配置):
{
"version": "5.1.1",
"softwareName": "inventaire",
"serverGitHeadRev": "2263179",
"env": "default",
"instanceName": "My Inventaire Instance",
"orgName": "Example Organization",
"orgUrl": "https://inventaire.example.org",
"mapTiles": {
"tileUrl": "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
"attribution": "Map data & imagery © <a href=\"http://openstreetmap.org\">OpenStreetMap</a> contributors, <a href=\"http://creativecommons.org/licenses/by-sa/2.0/\">CC-BY-SA</a>"
},
"publicHost": "localhost:3006",
"publicOrigin": "http://localhost:3006",
"defaultLandingPageMapPosition": [45.744, 4.821],
"orgFediverseAccount": null,
"maintenance": {"ongoingReindexation": false},
"contactAddress": "contact@inventaire.example.org"
}
要点:env 字段显示当前生效的配置环境名(default/production 等),publicOrigin 是客户端实际使用的对外地址,改完配置后先看这个端点确认生效。
3.2 源码安装形态:配置文件体系与加载顺序
源码安装时,配置文件全部在项目根的 config/ 目录,实测该目录内容:
config/
├── default.ts # 全部参数的默认值(约 440 行,见第四章总览)
├── production.ts # NODE_ENV=production 时叠加
├── production-federated.ts # NODE_ENV=production + NODE_APP_INSTANCE=federated 时叠加
├── production-primary.ts # NODE_APP_INSTANCE=primary 时叠加(实体主库实例用)
├── production-alt.ts # NODE_APP_INSTANCE=alt 时叠加
├── dev.ts # NODE_ENV=dev 时叠加
├── dev-federated.ts # NODE_ENV=dev + NODE_APP_INSTANCE=federated 时叠加
├── tests-*.ts # 自动化测试环境用
└── local.ts # ★ 运维者自己的覆盖文件,加载顺序最后、优先级最高(本地文件)
加载顺序遵循 node-config 的规则:default.ts → <环境>.ts → <环境>-<实例>.ts → local.ts → NODE_CONFIG 环境变量,后者逐层覆盖前者。local.ts 不在官方仓库中(.gitignore 排除),首次部署由运维者自己创建,是源码安装形态下改参数的标准位置。实测环境 ① 的 config/local.ts:
// Override settings from ./default.ts in this file
const config = {
db: {
username: "admin",
password: "q1w2e3r4",
},
publicHostname: "inventaire.example.com",
}
export default config
production.ts 的关键覆盖项(与默认值的差异,实测读源文件):
const config: PartialDeep<Config> = {
env: 'production',
publicHostname: 'OVERRIDE', // 强制要求部署者覆盖
publicProtocol: 'https',
publicPort: null,
serveStaticFiles: false, // 生产环境静态文件交给 Nginx
db: {
username: 'OVERRIDE',
password: 'OVERRIDE',
suffix: 'prod', // 业务库名加 -prod 后缀
},
mailer: { disabled: false, nodemailer: { requireTLS: true } },
activitySummary: { disabled: false },
wikidataEdit: { dry: false },
// ...
}
production-federated.ts(联邦实例,Compose 官方镜像即以此模式运行)的关键覆盖项:
const config: PartialDeep<Config> = {
port: 3016, // 联邦模式固定端口
federation: { remoteEntitiesOrigin: 'https://inventaire.io' },
activitySummary: { disabled: false, maxEmailsPerHour: 20 },
debouncedEmail: { disabled: true },
jobs: { // 实体主库专属任务,联邦实例关闭
'inv:deduplicate': { run: false },
'entity:auto-enrich-editions': { run: false },
'entity:popularity': { run: false },
'wd:entity:indexation': { run: false },
},
dataseed: { enabled: false },
// ...
}
3.3 修改参数并重启验证(源码安装实测)
以「把实例名称从默认值改为自己的名称」为例,完整走一遍修改闭环。第一步编辑 config/local.ts,追加 instanceName 与 contactAddress 两个参数:
const config = {
db: {
username: "admin",
password: "q1w2e3r4",
},
publicHostname: "inventaire.example.com",
instanceName: "My Home Library",
contactAddress: "admin@inventaire.example.com",
}
export default config
第二步重启服务(本文实测环境以前台进程方式运行,实际服务器用 systemd 时执行 systemctl restart inventaire):
pkill -f 'tsx server/server.ts'
nohup node_modules/.bin/tsx server/server.ts > logs/server.log 2>&1 &
第三步观察启动日志确认就绪(实测回显):
inventaire server is listening on port 3006...
startup: 1.459s
mailer disabled
activity summary disabled
GET http://localhost:5984/items/_changes?limit=0&descending=true [r18] 🗝 200 3ms
GET http://localhost:5984/entities/_changes?limit=0&descending=true [r22] 🗝 200 6ms
日志同时给出了两项关键佐证:CouchDB 连接走 http://localhost:5984(db.* 参数生效值),Elasticsearch 索引初始化正常。第四步用 GET /api/config 验证参数已生效(实测回显,与 3.1 节基线对比):
{
"instanceName": "My Home Library",
"publicHost": "inventaire.example.com:3006",
"publicOrigin": "http://inventaire.example.com:3006",
"contactAddress": "admin@inventaire.example.com"
}
三个参数全部按预期变化:instanceName 变为 My Home Library;publicHostname 的修改连带 publicHost/publicOrigin 一起更新(这两个是派生值);contactAddress 从默认值变为新地址。
⚠️ 注意:Inventaire 只在启动时读取配置,改完必须重启进程才会生效;配置文件是 TS 模块,语法错误会导致启动失败,启动日志会给出具体解析报错行。
3.4 NODE_CONFIG 环境变量覆盖(优先级实测)
NODE_CONFIG 是 node-config 官方的环境变量覆盖机制:值为一个 JSON 字符串,运行时直接覆盖任意配置项,优先级高于包括 local.ts 在内的所有配置文件,适合不改文件、临时验证或 secrets 注入场景。实测:带着 NODE_CONFIG='{"instanceName":"Env Override Instance"}' 重启服务(local.ts 中仍是 My Home Library):
NODE_CONFIG='{"instanceName":"Env Override Instance"}' node_modules/.bin/tsx server/server.ts
验证生效值(实测回显):
Env Override Instance | http://inventaire.example.com:3006
instanceName 取了环境变量里的 Env Override Instance,而 publicOrigin 仍是 local.ts 定义的 http://inventaire.example.com:3006——证明覆盖只发生在 NODE_CONFIG 里声明的键,其余键继续沿文件链取值。
💡 说明:官方 Docker 镜像内部正是同时使用这两种机制——entrypoint 脚本每次启动用
.env变量重新生成dist/config/local.js(文件层),再由部署者按需注入NODE_CONFIG(环境变量层),见 3.5 节。
3.5 Docker Compose 形态:.env 变量到配置键的映射
Compose 部署时不需要(也不应该)手工编辑容器内配置文件:官方镜像的 /opt/docker-entrypoint.sh 在每次启动时用 24 个环境变量重新生成 dist/config/local.js。实测环境 ② 容器内生成的 local.js 全文如下(即当前生效的文件层配置):
// Built by docker-inventaire/inventaire/docker-entrypoint.sh
// The built server will only care for dist/config/local.js, but config/local.ts is kept in sync for consistency
export default {
hostname: 'inventaire',
port: '3016',
publicHostname: 'localhost',
instanceName: 'My Inventaire Instance',
orgName: 'Example Organization',
orgUrl: 'https://inventaire.example.org',
contactAddress: 'contact@inventaire.example.org',
db: {
username: 'admin',
password: 'q1w2e3r4',
hostname: 'couchdb',
backupDirectory: '/opt/inventaire_backups',
},
leveldb: {
directory: '/opt/inventaire_leveldb',
suffixDirectoryPathWithDbSuffix: false,
},
elasticsearch: {
origin: 'http://elasticsearch:9200',
},
mailer: {
disabled: false,
nodemailer: {
host: 'smtp.example.org',
port: 587,
auth: {
user: 'your_username_on_smtp.example.org',
pass: 'your_password_on_smtp.example.org'
},
},
},
mapTilesAccessToken: 'youraccesstoken',
matomo: {
enabled: false,
endpoint: 'https://yourmatomoendpoint/matomo.php',
idsite: 1,
rec: 1,
},
mediaStorage: {
mode: 'local',
swift: {
username: 'customizedInLocalConfig',
password: 'customizedInLocalConfig',
authUrl: 'https://openstackEndpointToCustomize',
publicURL: 'https://swiftPublicURL',
tenantName: '12345678',
region: 'SBG-1',
},
local: {
directory: '/opt/inventaire_local_media_storage'
},
},
}
24 个环境变量与配置键的对应关系(entrypoint 脚本逐字提取核对):
| .env 变量 | 生成的配置键 | 备注 |
|---|---|---|
| PUBLIC_HOSTNAME | publicHostname | 对外域名 |
| INSTANCE_NAME | instanceName | 实例名称 |
| ORG_NAME / ORG_URL | orgName / orgUrl | 组织信息 |
| CONTACT_ADDRESS | contactAddress | 联系邮箱 |
| COUCHDB_USER / COUCHDB_PASSWORD | db.username / db.password | 主库凭据 |
| INVENTAIRE_PORT | port | 监听端口 |
| MAILER_SMTP_HOST / MAILER_SMTP_PORT | mailer.nodemailer.host / .port | SMTP 服务器 |
| MAILER_SMTP_USERNAME / MAILER_SMTP_PASSWORD | mailer.nodemailer.auth.user / .pass | SMTP 认证 |
| MAP_TILES_ACCESS_TOKEN | mapTilesAccessToken | 地图瓦片令牌 |
| MOTOMO_ENABLED / MOTOMO_ENDPOINT / MOTOMO_IDSITE / MOTOMO_REC | matomo.enabled / .endpoint / .idsite / .rec | Matomo 统计 |
| MEDIA_STORAGE_MODE | mediaStorage.mode | local 或 swift |
| SWIFT_USERNAME / SWIFT_PASSWORD / SWIFT_AUTH_URL / SWIFT_PUBLIC_URL / SWIFT_TENANT_NAME / SWIFT_REGION | mediaStorage.swift.* | Swift 对象存储六项 |
另有 3 个环境变量不进 local.js、直接由 node-config 运行时消费:NODE_ENV(固定 production,选择 production.ts)、NODE_APP_INSTANCE(官方默认 federated,选择 production-federated.ts)、NODE_CONFIG(JSON 直接覆盖任意键)。生成的 local.js 中 CouchDB 主机名 couchdb、ES 地址 http://elasticsearch:9200、LevelDB 目录 /opt/inventaire_leveldb 等是 entrypoint 模板硬编码的,.env 没有对应变量——单容器连接外部数据库/搜索服务时,必须用 NODE_CONFIG 覆盖 db.hostname 与 elasticsearch.origin(实测可行,见 《Inventaire 5.1.1 Docker Compose 部署指南》第九章)。
Compose 形态改参数的完整闭环:改 .env(或 compose 覆盖文件的 NODE_CONFIG)→ docker compose up -d 重建 inventaire 服务 → 观察启动日志出现 server started → curl -s http://localhost:8138/api/config 验证。实测环境 ② 的生效值:
{
"version": "5.1.1",
"env": "production",
"instanceName": "My Inventaire Instance",
"publicHost": "localhost:8138",
"publicOrigin": "http://localhost:8138",
"remoteEntitiesOrigin": "https://inventaire.io"
}
env: production 与 remoteEntitiesOrigin 正是 production.ts + production-federated.ts 两层叠加的结果,与 3.2 节的文件加载顺序吻合。
四、参数总览
config/default.ts 按功能分区给出全部默认值,下表为全景速查(默认值均摘自实测环境 ① 的源文件,标注 ★ 的为核心运维参数,第五章逐项详解):
| 分区 | 参数 | 默认值 | 说明 |
|---|---|---|---|
| 实例信息 | instanceName | 'My Inventaire Instance' | ★ 实例名称,大屏菜单标题 |
| 实例信息 | orgName / orgUrl | 'Example Organization' / 'https://inventaire.example.org' | ★ 落地页组织信息 |
| 实例信息 | contactAddress | 'contact@inventaire.example.org' | ★ 实例邮件的回复地址 |
| 实例信息 | defaultLandingPageMapPosition | [45.744, 4.821] | 落地页地图默认经纬度 |
| 实例信息 | orgFediverseAccount | null | 链接分享到联邦宇宙时的署名账号 |
| 监听与对外 | protocol / hostname / port | 'http' / 'localhost' / 3006 | ★ 服务自身监听(生产 TLS 交给 Nginx) |
| 监听与对外 | publicProtocol / publicHostname / publicPort | 'http' / 'localhost' / undefined | ★ 对外地址三元组(生产应为 https/域名/null) |
| 监听与对外 | trustProxy | 'loopback, uniquelocal' | Express 反代信任网段 |
| 监听与对外 | serveStaticFiles | true(生产强制 false) | ★ 是否由 Node 托管前端静态文件 |
| 监听与对外 | autoRotateKeys | true | 会话签名密钥自动轮换 |
| 监听与对外 | cookieMaxAge | 180*24*3600*1000(180 天) | 会话 Cookie 最长有效期 |
| CouchDB | db.protocol / hostname / port | 'http' / 'localhost' / 5984 | ★ 主库地址 |
| CouchDB | db.username / password | 占位值 | ★ 主库凭据(必须覆盖) |
| CouchDB | db.suffix | null(生产 'prod') | 业务库名后缀 |
| CouchDB | db.follow.reset / freeze / delay | false / false / 5000 | 库事件跟随行为 |
| CouchDB | db.debug | false | 打印 CouchDB 请求参数 |
| CouchDB | db.backupDirectory | 'backups/couchdb' | ★ 备份产物目录 |
| CouchDB | db.runMigrations | true | 启动时执行数据迁移 |
| LevelDB | leveldb.directory | './db/leveldb' | LevelDB 目录(缓存+任务队列) |
| LevelDB | leveldb.inMemoryLRUCacheSize | 64 MB | 内存 LRU 缓存大小 |
| LevelDB | leveldb.ttlCheckFrequency | 60000 | 缓存 TTL 巡检周期(ms) |
| 缓存 | cache.defaultTTL / debug | 30 天 / false | 通用缓存 TTL |
| Elasticsearch | elasticsearch.origin | 'http://localhost:9200' | ★ ES 地址 |
| Elasticsearch | elasticsearch.updateDelay | 1000 | 写入后索引可见延迟(ms) |
| Elasticsearch | elasticsearch.minReindexationInterval | 60000 | 重索引最小间隔(ms) |
| Elasticsearch | elasticsearch.logResponses / selfSignedCertificate | false / false | ES 调试与自签证书 |
| 日志 | verbose | true | 详细日志开关 |
| 日志 | requestsLogger.mutedRootSections / mutedPath | [] / ['/api/reports/online'] | 降噪过滤 |
| 邮件 | mailer.disabled | true(生产 false) | ★ 邮件总开关 |
| 邮件 | mailer.nodemailer.host / port / auth | smtp.ethereal.email / 587 / 占位 | ★ SMTP 参数 |
| 邮件 | mailer.initDelay / deniedAddressesPatterns | 10000 / [] | 启动延迟 / 拒发地址模式 |
| 邮件 | debouncedEmail.crawlPeriod / debounceDelay / disabled | 60s / 10min / false | 通知合并邮件 |
| 邮件 | activitySummary.disabled / maxEmailsPerHour | true(生产 false)/ 5 | 周期活动摘要 |
| 邮件 | tokenDaysToLive | 3 | 邮箱验证令牌有效期(天) |
| 媒体存储 | mediaStorage.mode | 'local' | ★ local 或 swift |
| 媒体存储 | mediaStorage.local.directory | './storage' | ★ 本地图片目录 |
| 媒体存储 | mediaStorage.images.maxSize | 1600 | 上传图片最大边长(px) |
| 媒体存储 | mediaStorage.swift.* | 占位值 | Swift 六项(mode=swift 时必填) |
| 媒体存储 | remoteImages.useEntitiesHostCachedImages | false | 远端图片走实体主库缓存 |
| 地图 | mapTiles.tileUrl / attribution | OpenStreetMap 官方瓦片 / OSM 署名 | 地图瓦片源 |
| 地图 | mapTilesAccessToken(Compose 形态) | 占位值 | MapBox 令牌 |
| 统计 | matomo.enabled / endpoint / idsite / rec | false / 占位 / 1 / 1 | Matomo 埋点 |
| 联邦 | federation.remoteEntitiesOrigin | undefined(联邦模式 https://inventaire.io) | ★ 远端实体来源 |
| 安全 | rateLimiting.disabled / timeWindow | false / 30 分钟 | ★ 接口限流 |
| 安全 | rateLimiting.exemptedUserAgents / restrictedUserAgents | [] / [] | UA 白/黑名单 |
| 安全 | incomingRequests.logBody | false | 入站请求体日志 |
| 安全 | outgoingRequests.baseBanTime / banTimeIncreaseFactor / maxBanTime | 5000 / 4 / 24h | 出站请求封禁梯度 |
| 安全 | outgoingRequests.rejectPrivateUrls | true | 禁止请求内网地址(SSRF 防护) |
| 安全 | spam.suspectKeywords | ['agent','SEO','marketing','shopping'] | 垃圾内容触发词 |
| 安全 | waitFactor | 1 | 请求等待时间全局倍率 |
| 后台任务 | jobs.'inv:deduplicate' 等 5 项 | run: true(联邦模式 4 项 false) | ★ LevelDB 任务开关 |
| Wikidata | wikidataOAuth.consumer_key / consumer_secret | 占位值 | 用户 Wikidata OAuth 接入 |
| Wikidata | wikidataBotAccount.* / wikidataEdit.dry | 占位 / true(生产 false) | 机器人账号与 dry-run |
| 开发开关 | i18n.autofix / offline / useSlowPasswordHashFunction / deduplicateRequests | false / false / true / true | 仅测试开发环境调整 |
表格较长,选型解读一句话概括:单机自托管最小必改集 = db 凭据 + publicHostname + instanceName/orgName/orgUrl/contactAddress + mailer;其余参数保持默认即可稳定运行。
五、核心参数分类详解
本章对标注 ★ 的核心参数逐组展开:语义、默认值、修改影响与实测依据。
5.1 实例信息参数(instanceName / orgName / orgUrl / contactAddress)
这四个参数决定实例的「身份展示」:instanceName 显示在大屏菜单标题与 GET /api/config 响应中;orgName/orgUrl 展示在落地页;contactAddress 是实例发出邮件(验证信、通知)里用户可以直接回复的地址。修改方法与生效验证见 3.3 节实测(instanceName 与 contactAddress 修改后均从 /api/config 读到新值)。
5.2 服务监听与对外地址(protocol / hostname / port / public* 三元组 / serveStaticFiles)
两组地址参数的分工:protocol/hostname/port 是服务进程自己监听的地址;publicProtocol/publicHostname/publicPort 拼成 publicOrigin,是对外宣称的访问入口(生成邮件里的链接、Cookie 域、客户端 API 基址)。
publicProtocol影响会话 Cookie 的 Secure 标记:服务端按secure: publicProtocol === 'https'设置,HTTP 直连部署必须改为'http',否则登录成功但 Cookie 不下发、所有需认证接口 401(实测排障结论,见部署指南 FAQ);publicPort默认取port的值,置null表示对外 URL 不带端口(生产由 Nginx 占 80/443 时的标准写法);serveStaticFiles默认true(Node 直接托管前端),生产形态官方置false交给 Nginx;本地无 Nginx 直连部署时应改回true,否则只有 API 没有页面;trustProxy默认'loopback, uniquelocal',Nginx 反代部署时保持默认即可正确识别X-Forwarded-*头。
实测佐证:环境 ② 以 NODE_CONFIG 注入 {"serveStaticFiles":true,"publicProtocol":"http","publicHostname":"localhost","publicPort":null} 后,HTTP 直连形态登录与页面托管均正常,/api/config 的 publicOrigin 精确反映为 http://localhost:8138。
5.3 CouchDB 连接参数(db.*)
主库连接七件套:db.protocol(默认 http)、db.hostname、db.port、db.username、db.password、db.suffix、db.getOrigin()(派生)。suffix 决定业务库名是否带后缀:生产模式自动 'prod',实际库名形如 items-prod、users-prod(启动日志可见 CouchDB: initializing design docs in users-prod)。
辅助参数:
db.follow.reset(默认 false):置 true 时外部索引从第一个序列号重建;db.follow.freeze(默认 false):冻结库事件钩子,仅调试用;db.follow.delay(默认 5000 ms):事件跟随延迟;db.debug(默认 false):打印 CouchDB 请求参数,排障时临时开启;db.backupDirectory(默认backups/couchdb):内置备份脚本产物目录,Compose 形态固定为/opt/inventaire_backups(对应独立的备份卷);db.runMigrations(默认 true):启动时自动执行 CouchDB 数据迁移,升级版本时保持开启。
实测佐证:环境 ① 启动日志中全部业务库请求都指向 http://localhost:5984(db.hostname=localhost、db.port=5984 生效);环境 ② 生成的 local.js 中 db.hostname: 'couchdb' 与 compose 服务名一致。
5.4 LevelDB 与缓存参数(leveldb.* / cache.*)
Inventaire 用 LevelDB 承载两类数据:处理结果缓存与任务队列(level-jobs)。关键参数:
leveldb.directory(默认./db/leveldb):数据目录。leveldb.suffixDirectoryPathWithDbSuffix为 true 时目录名带环境后缀;Compose 形态固定为/opt/inventaire_leveldb并挂独立卷持久化;leveldb.inMemoryLRUCacheSize(默认 64 MB):内存 LRU 缓存上限,内存充裕的小型实例可维持默认,内存紧张时下调;leveldb.ttlCheckFrequency(默认 60000 ms):过期巡检周期;cache.defaultTTL(默认 30 天):通用缓存存活时间。
💡 说明:
db.backupDirectory(备份目录)与leveldb.directory(运行数据目录)都支持相对路径——相对路径以 Inventaire 项目根为基准解析;生产建议一律写绝对路径,避免随启动目录漂移。
5.5 Elasticsearch 参数(elasticsearch.*)
elasticsearch.origin(默认http://localhost:9200):ES 集群地址,分体式部署必改;elasticsearch.updateDelay(默认 1000 ms):写入后检索可见的延迟,与 ES refresh 机制对应;elasticsearch.minReindexationInterval(默认 60000 ms):两次重索引的最小间隔,防止索引风暴;elasticsearch.selfSignedCertificate(默认 false):ES 启用 HTTPS 自签证书时置 true;elasticsearch.logResponses(默认 false):打印 ES 响应,排障用;maintenance.ongoingReindexation(默认 false):重索引进行中的标记位,一般不动。
实测佐证:环境 ① 启动日志显示 elasticsearch index created: http://localhost:9200/groups(origin 生效且自动建索引);检索接口 GET /api/search 返回结果带 _score 评分,索引链路正常。
5.6 邮件参数(mailer.* / debouncedEmail / activitySummary / tokenDaysToLive)
邮件是注册闭环的硬依赖(账号验证邮件必须能发出),默认却是关闭的(mailer.disabled: true,开发友好),生产必须改:
mailer: {
disabled: false,
nodemailer: {
host: 'smtp.provider-domain.org',
port: 587,
auth: {
user: 'your-provider-username',
pass: 'your-provider-password',
},
},
},
逐项说明:mailer.nodemailer.* 即 Nodemailer 的 SMTP 传输参数,port 常用 587(STARTTLS);生产模式自动追加 requireTLS: true;mailer.initDelay(默认 10000 ms)延迟初始化 SMTP 连接,避免拖慢启动;mailer.deniedAddressesPatterns 可屏蔽特定收件域。Compose 形态由 MAILER_SMTP_* 四个变量生成(见 3.5 节映射表)。
配套三个参数组:debouncedEmail(把短时间多条通知合并成一封摘要邮件,crawlPeriod 60s 扫描一次、debounceDelay 10min 合并窗口,联邦模式自动禁用);activitySummary(周期性活动摘要邮件,生产默认开启、每小时最多 maxEmailsPerHour 封);tokenDaysToLive(邮箱验证令牌有效期,默认 3 天)。
官方文档提供
npm run send-test-email your@email.org一键发测试邮件验证 SMTP 配置(出处:仓库 docs/configuration/email_provider.md)。
5.7 媒体存储参数(mediaStorage.*)
用户头像、小组封面(实体主库还有书封)的上传图片存储位置:
💡 技术拓展:自托管应用的图片存储后端不止本地磁盘一种,常见选项对比——
存储模式 原理/特点 适用场景 local 本地目录 直接写服务器文件系统,备份即拷目录 单机部署、中小规模(最常用) OpenStack Swift 对象存储 经 Swift API 上传,容量弹性、天然多副本 多实例共享存储、大图片量 S3 兼容对象存储 AWS S3/MinIO 等通用协议 主流云环境(Inventaire 未支持,仅 Swift) Inventaire 实际支持
local与swift两种(mediaStorage.mode),未提供 S3 协议接入;单机自托管选local即可。
mediaStorage.mode:'local'(默认)或'swift';mediaStorage.local.directory(默认./storage):本地存储目录,Compose 形态固定/opt/inventaire_local_media_storage并挂独立卷;mediaStorage.images.maxSize(默认 1600 px):上传图最大边长,超限自动缩放;mediaStorage.swift.*六项(username/password/authUrl/publicURL/tenantName/region):仅 mode=swift 时生效,对应 OpenStack 凭据;remoteImages.useEntitiesHostCachedImages(默认 false):联邦实例展示远端实体图片时改 true 可直接取用实体主库(inventaire.io)的缩放缓存,显著加速图片加载。
5.8 地图与统计参数(mapTiles / mapTilesAccessToken / matomo.*)
mapTiles.tileUrl(默认 OpenStreetMap 官方瓦片):服务端地图接口使用的瓦片源,可自建瓦片服务替换;mapTilesAccessToken:MapBox 令牌,客户端地图功能使用;不填实例可运行,但地图相关页面不可用(官方 .env 模板将其列为必填占位);matomo.enabled/endpoint/idsite/rec:Matomo(ex-Piwik)隐私友好统计埋点,默认关闭;开启后访问统计上报到endpoint指定的 Matomo 实例(Compose 形态对应MOTOMO_*四个变量,官方变量名沿用旧拼写 Motomo)。
5.9 联邦模式参数(federation.remoteEntitiesOrigin / NODE_APP_INSTANCE / jobs.*)
Inventaire 的实例分两类角色:实体主库(primary,自建图书/著作/人物实体数据库并承担 Wikidata 同步任务)与联邦实例(federated,复用旗舰实例 inventaire.io 的实体数据,专注本地用户/物品/小组)。角色由 NODE_APP_INSTANCE 环境变量选择:不设 = 单机默认模式,federated = 联邦实例,primary = 实体主库。
federation.remoteEntitiesOrigin:远端实体来源域名,联邦模式由production-federated.ts固定为https://inventaire.io;开发环境想用旗舰站实体可同样设置。实测佐证:环境 ②(federated)的/api/config返回remoteEntitiesOrigin: https://inventaire.io,且实体检索接口返回entities should be searched on remote instance提示(本地只搜用户与小组);jobs.*:基于 LevelDB 队列的 5 个后台任务开关(inv:deduplicate实体去重、entity:auto-enrich-editions版本信息自动补全、entity:popularity热度计算、wd:entity:indexationWikidata 双库索引同步、post:activity联邦宇宙动态发布),主库实例默认全开,联邦实例自动关闭前 4 个(见 3.2 节production-federated.ts实录)。
5.10 安全与限流参数(rateLimiting / outgoingRequests / spam / waitFactor)
rateLimiting.disabled(默认 false):接口限流总开关,生产保持开启;timeWindow(默认 30 分钟)为限流统计窗口;exemptedUserAgents/restrictedUserAgents可对爬虫类 UA 放行或限制;outgoingRequests.rejectPrivateUrls(默认 true):SSRF 防护——服务端代替用户抓取外部图片/数据时拒绝内网地址,生产严禁关闭;outgoingRequests.baseBanTime(默认 5000 ms)/banTimeIncreaseFactor(默认 4)/maxBanTime(默认 24 h):对外请求失败后的自动封禁梯度(5s 起步、每次 ×4、封顶 1 天),防止故障外部服务拖垮自身;spam.suspectKeywords(默认含 'agent'/'SEO'/'marketing'/'shopping'):用户简介、物品评论等文本中出现这些词时在用户文档打可疑标记,管理员可在用户管理页复核;cookieMaxAge(默认 180 天)与autoRotateKeys(默认 true):会话有效期与会话签名密钥轮换;多实例负载均衡时共享会话需固定一套密钥——一台autoRotateKeys: true、其余false;waitFactor(默认 1):全局请求等待时间倍率,机器负载高时可调大让重操作更耐心。
5.11 Wikidata 接入参数(wikidataOAuth / wikidataBotAccount / wikidataEdit)
仅实体主库实例需要关注:wikidataOAuth.consumer_key/consumer_secret(用户用 Wikidata 账号登录本实例的 OAuth 接入,在 Wikimedia 官方申请);wikidataBotAccount.*(服务器自身对 Wikidata 做自动化编辑的机器人 OAuth 四件套);wikidataEdit.dry(默认 true 的 dry-run 保护,生产置 false 才会真正写 wikidata.org)。联邦实例无需配置这些参数——Wikidata 同步任务已自动关闭。
六、生产配置模板
以下模板按「4 GB 内存、40 GB 磁盘、50 人以内团队的单机自托管藏书库」场景给出(与本文实测环境同规格),两个形态二选一。
形态 A:源码安装(Ubuntu 22.04,Nginx TLS 反代) —— config/local.ts:
const config = {
// 主库凭据(与 CouchDB 管理员一致)
db: {
username: "admin",
password: "q1w2e3r4",
// 分体式部署时改为 CouchDB 实际地址
// hostname: "192.168.1.10",
},
// 对外地址(Nginx 占 443,Node 只听本机)
publicProtocol: "https",
publicHostname: "books.example.org",
publicPort: null,
serveStaticFiles: false,
// 实例身份
instanceName: "My Home Library",
orgName: "Example Organization",
orgUrl: "https://books.example.org",
contactAddress: "admin@books.example.org",
// 邮件(生产必须,否则注册闭环断裂)
mailer: {
disabled: false,
nodemailer: {
host: "smtp.example.org",
port: 587,
auth: { user: "books", pass: "q1w2e3r4" },
},
},
// 图片本地存储(绝对路径,纳入备份计划)
mediaStorage: {
mode: "local",
local: { directory: "/var/lib/inventaire/storage" },
},
}
export default config
启动方式(以生产环境变量运行,联邦实例):
cd /home/inventaire/inventaire
NODE_ENV=production NODE_APP_INSTANCE=federated node_modules/.bin/tsx server/server.ts
形态 B:Docker Compose 部署 —— 部署目录 .env(完整 24 变量中与上述场景相关的关键项):
PUBLIC_HOSTNAME=books.example.org
COUCHDB_USER=admin
COUCHDB_PASSWORD=q1w2e3r4
INSTANCE_NAME=My Home Library
ORG_NAME=Example Organization
ORG_URL=https://books.example.org
CONTACT_ADDRESS=admin@books.example.org
MAILER_SMTP_HOST=smtp.example.org
MAILER_SMTP_PORT=587
MAILER_SMTP_USERNAME=books
MAILER_SMTP_PASSWORD=q1w2e3r4
MAP_TILES_ACCESS_TOKEN=your-mapbox-token
MOTOMO_ENABLED=false
MOTOMO_ENDPOINT=https://matomo.example.org/matomo.php
MOTOMO_IDSITE=1
MOTOMO_REC=1
MEDIA_STORAGE_MODE=local
SWIFT_USERNAME=placeholder
SWIFT_PASSWORD=placeholder
SWIFT_AUTH_URL=https://swift.example.org/auth
SWIFT_PUBLIC_URL=https://swift.example.org/public
SWIFT_TENANT_NAME=12345678
SWIFT_REGION=SBG-1
要点回顾:.env 管不到的连接类参数(CouchDB/ES 地址、LevelDB 目录)由 entrypoint 硬编码为套件内部服务名,单机套件部署无需关心;HTTP 直连测试形态另需 NODE_CONFIG 注入四项(见 3.5 节实测)。磁盘规划:主库卷 + LevelDB 卷 + 图片卷各按 10 GB 起步,备份卷按主库体积 2 倍预留。
七、常见问题
Q1:改了配置文件重启后参数没生效?
三个常见原因逐一排查:① 改错了文件——源码安装改的是项目根 config/local.ts,不是 dist/config/local.js(后者是编译产物,TS 源文件才是运行时真源,npm run build 时从 config/ 生成);② 没重启进程——配置只在启动时读取;③ 被 NODE_CONFIG 覆盖——环境变量优先级最高,检查启动环境里是否残留(echo $NODE_CONFIG)。
Q2:启动直接失败,日志报 Cannot parse config file ... local.js: SyntaxError?
配置文件是 JS 模块,语法错误会在启动时抛出,报错行号即出错位置。Compose 形态的经典成因是用 docker run --env-file 传入带引号的 .env——单引号字面量进入 entrypoint 模板生成非法 JS(如 instanceName: ''My Inventaire Instance'')。Compose 的 env_file 会剥引号而 docker run --env-file 不会,两者不通用(实测复现结论)。
Q3:NODE_ENV=production 启动后为什么强制要求改一堆 OVERRIDE?
production.ts 把 publicHostname、db.username、db.password 显式设为 'OVERRIDE' 占位,就是逼部署者显式覆盖:不改就带着字面量 OVERRIDE 运行,数据库连不上或对外地址错误。这是官方故意的防呆设计。
Q4:联邦实例和主库实例怎么选,配置上差在哪?
只差 NODE_APP_INSTANCE 一个环境变量:federated 自动获得 remoteEntitiesOrigin=https://inventaire.io、关闭实体类后台任务;primary 需自行配置 Wikidata OAuth 并保证磁盘充裕(自建全量实体库)。单机自托管藏书库用 federated(官方 Compose 镜像默认值)。
Q5:想确认限流、SSRF 防护这些安全参数真的在工作?
rateLimiting 与 outgoingRequests 参数不在 /api/config 暴露(避免向攻击者泄露防护配置),确认方式是看源码 config/default.ts 的生效值与版本一致,并结合行为验证:超频请求被 429 拒绝、构造内网 URL 的图片代理请求被拒绝。默认值即安全值,无特殊需求不要关闭。
八、参考链接
- 参数默认值源文件(本文第四、五章依据):https://codeberg.org/inventaire/inventaire/raw/branch/main/config/default.ts
- 官方配置子文档(邮件/统计/地图/存储):https://codeberg.org/inventaire/inventaire#docs-configuration
- node-config 环境变量覆盖机制:https://github.com/node-config/node-config/wiki/Environment-Variables#node_config
- node-config 文件加载顺序:https://github.com/node-config/node-config/wiki/Configuration-Files#file-load-order
- 官方部署套件(entrypoint 与 dotenv 模板):https://github.com/inventaire/docker-inventaire
- Nodemailer SMTP 参数:https://nodemailer.com/smtp/
- Matomo 集成指引:https://developer.matomo.org/guides/integrate-introduction
- 本专栏姊妹篇:《Inventaire 5.1.1 Docker Compose 部署指南》、《Inventaire 5.1.1 介绍与选型指南》、《Inventaire 5.1.1 API 详解》