Papermerge 3.5.3 配置参数详解
Papermerge 3.5.3 配置参数详解:PAPERMERGE__ 环境变量分层机制、四组件 config.py 默认值实测、数据库/检索/OCR/认证参数逐项与死配置白名单陷阱
Papermerge 3.5.3 配置参数详解
目标:把 Papermerge 3.5.3 的全部配置参数讲透——配置的分层机制、每个组件的配置文件在哪、每个参数的代码默认值与生产改法,以及实测踩到的"死配置""假白名单"陷阱。
本文以《Papermerge 3.5.3 Docker Compose 部署指南》部署的六服务栈(webapp + db + redis + solr + ocr_worker + i3worker)为实测环境;组件定位与选型见《Papermerge 介绍与选型指南》;REST API 用法见本专栏《Papermerge 3.5.3 API 使用详解》。文中所有命令与回显均为 2026-11-02 在该栈上实测照抄,示例账号 admin / q1w2e3r4。
一、环境信息
| 项目 | 值 |
|---|---|
| 操作系统 | Linux(x86_64,内核 7.0.0-38-generic) |
| 应用版本 | Papermerge 3.5.3(papermerge/papermerge:3.5.3) |
| 配置机制 | 环境变量 PAPERMERGE__<SECTION>__<KEY>(pydantic-settings),无用户可编辑的 settings.py |
| 配置载体 | 每个组件一个 Settings 类:webapp / auth-server / ocrworker / i3worker 各自独立 |
| 实测环境 | 《Papermerge 3.5.3 Docker Compose 部署指南》六服务栈,Web 入口 :8138 |
| 示例凭据 | admin / q1w2e3r4(首启由 PAPERMERGE__AUTH__* 自动创建) |
3.x 与 2.x 的配置体系完全不同:2.x 是 Django 时代的 settings.py,3.x 重写后没有任何用户可直接编辑的配置文件,全部配置经由环境变量注入各组件的 pydantic-settings Settings 类,代码默认值内置在镜像内的 config.py 里。本文的"参数详解"因此以镜像内 config.py 原文 + 实测回显为准,官方文档(docs.papermerge.io settings/*,页脚 June 1, 2026,查询日期 2026-11-01)作为对照。
二、前置条件
- 已按《Papermerge 3.5.3 Docker Compose 部署指南》把六服务栈部署起来且
docker compose ps全部 Up。 - 宿主机可对服务执行
docker exec(本文的查看/演示命令都通过它读容器内文件与进程配置)。 - 本文只讲配置参数;上传/OCR/检索的业务闭环不在重复,见部署指南 4.7。
三、参数查看与修改方式
3.1 配置分层机制
每个组件启动时,pydantic-settings 按"环境变量覆盖代码默认值"的规则装配出一份 Settings:
- 字段名与变量名一一对应:字段
papermerge__database__url↔ 变量PAPERMERGE__DATABASE__URL(大小写不敏感,双下划线分节); - 变量未设置 → 保留 config.py 里的代码默认值;
- 变量设置为空串 → 生效为空串(如本栈
PAPERMERGE__MAIN__API_PREFIX=显式置空); - 配置在进程启动瞬间读取,改 compose 里的变量必须重建容器才生效(见第七章问题 5)。
变量在启动链路中的消费位置(webapp 镜像 /entrypoint.sh 原文节选,实测读取):
#!/bin/sh
CMD="$1"
mkdir -p /db # default database is /db/db.sqlite3
...
exec_createsuperuser() {
cd /auth_server_app && poetry run auth-cli users create --superuser
}
exec_index_schema_apply() {
echo "exec_index_schema_apply"
if [ -n "${PAPERMERGE__SEARCH__URL}" ]; then
即 entrypoint 序列:migrate → paper-cli perms sync → 按 PAPERMERGE__AUTH__USERNAME/PASSWORD/EMAIL 自动建超级用户(仅当 PAPERMERGE__SEARCH__URL 非空才做索引 schema apply)→ 生成前端 runtime-config.js → supervisord 拉起 nginx + uvicorn + auth-server。首启建号日志实测为 User admin created(见部署指南 4.4)。
3.2 查看方式一:进程环境变量
看一个服务实际收到了哪些配置变量:
docker exec papermerge-353-stack-webapp-1 sh -c \
'env | grep PAPERMERGE | sed "s/SECRET_KEY=.*/SECRET_KEY=<REDACTED>/" | sort'
实测回显(本栈 webapp):
PAPERMERGE__AUTH__EMAIL=admin@example.com
PAPERMERGE__AUTH__PASSWORD=q1w2e3r4
PAPERMERGE__AUTH__USERNAME=admin
PAPERMERGE__DATABASE__URL=postgresql://pmuser:q1w2e3r4@db:5432/pmgdb
PAPERMERGE__MAIN__API_PREFIX=
PAPERMERGE__MAIN__MEDIA_ROOT=/var/media/pmg
PAPERMERGE__OCR__AUTOMATIC=false
PAPERMERGE__OCR__DEFAULT_LANG_CODE=deu
PAPERMERGE__OCR__LANG_CODES=deu,eng,ron
PAPERMERGE__REDIS__URL=redis://redis:6379/0
PAPERMERGE__SEARCH__URL=solr://solr:8983/pmg
PAPERMERGE__SECURITY__SECRET_KEY=<REDACTED>
注意两点:PAPERMERGE__OCR__AUTOMATIC=false 是镜像内置默认(compose 并未设置它,env 里却存在);PAPERMERGE__OCR__LANG_CODES 虽被设置,实测在 3.5.3 无任何消费代码(见 5.4 与第七章问题 1)。
3.3 查看方式二:读组件 config.py 原文
各组件的配置文件路径(均在镜像内,实测可 sed/cat 直接读):
| 组件 | 镜像 | 配置文件 |
|---|---|---|
| webapp | papermerge/papermerge:3.5.3 | /core_app/papermerge/core/config.py |
| auth-server(webapp 内置) | 同上 | /auth_server_app/auth_server/config.py |
| ocrworker | papermerge/ocrworker:0.3.1 | /app/ocrworker/config.py |
| i3worker | papermerge/i3worker:0.3 | /app/i3worker/config.py |
docker exec papermerge-353-stack-webapp-1 sed -n '1,80p' /core_app/papermerge/core/config.py
实测回显(webapp Settings 类全文,即默认值的权威出处):
class FileServer(str, Enum):
LOCAL = 'local'
S3 = 's3'
class Settings(BaseSettings):
papermerge__main__logging_cfg: Path | None = Path("/etc/papermerge/logging.yaml")
papermerge__main__media_root: Path = Path("media")
papermerge__main__api_prefix: str = ''
papermerge__main__prefix: str = ''
papermerge__main__file_server: FileServer = FileServer.LOCAL
papermerge__main__cf_sign_url_private_key: str | None = None
papermerge__main__cf_sign_url_key_id: str | None = None
papermerge__main__cf_domain: str | None = None
papermerge__main__timezone: str = 'Europe/Berlin'
papermerge__main__cache_enabled: bool = False
papermerge__database__url: str = "sqlite:////db/db.sqlite3"
papermerge__redis__url: str | None = None
papermerge__ocr__default_lang_code: str = 'deu'
papermerge__preview__page_size_sm: int = 200 # pixels
papermerge__ocr__automatic: bool = False
papermerge__search__url: str | None = None
settings = Settings()
3.4 查看方式三:打印运行时生效值
读 config.py 只能看到默认值;要看"当前进程真正生效的配置",直接在 webapp 内实例化 Settings 打印:
docker exec -i papermerge-353-stack-webapp-1 sh -c 'cd /core_app && poetry run python' <<'PY'
from papermerge.core.config import settings as s
print(s.papermerge__database__url)
print(s.papermerge__search__url)
print(s.papermerge__main__timezone)
PY
实测回显(完整键清单):
papermerge__main__logging_cfg = /etc/papermerge/logging.yaml
papermerge__main__media_root = /var/media/pmg
papermerge__main__api_prefix =
papermerge__main__prefix =
papermerge__main__file_server = FileServer.LOCAL
papermerge__main__timezone = Europe/Berlin
papermerge__main__cache_enabled = False
papermerge__database__url = postgresql://pmuser:q1w2e3r4@db:5432/pmgdb
papermerge__redis__url = redis://redis:6379/0
papermerge__search__url = solr://solr:8983/pmg
papermerge__ocr__default_lang_code = deu
papermerge__ocr__automatic = False
papermerge__preview__page_size_sm = 200
i3worker 更省事,官方自带 i3 config 子命令直接打印它生效的四个键(实测回显):
docker exec papermerge-353-stack-i3worker-1 sh -c 'cd /app && poetry run i3 config'
{
"papermerge__search__url": "solr://solr:8983/pmg",
"papermerge__redis__url": "redis://redis:6379/0",
"papermerge__main__logging_cfg": null,
"papermerge__database__url": "postgresql://pmuser:q1w2e3r4@db:5432/pmgdb"
}
3.5 修改方式与分层证据
持久修改:写进 compose 的 environment:(或 docker run -e),然后 docker compose up -d 重建受影响服务。这是唯一推荐的生产改法。
一次性修改:docker exec -e 只影响那一条命令的进程,用于验证参数效果,不落盘。实测分层证据三连:
1)同一进程环境下去掉业务变量,看代码默认形态:
docker exec -i papermerge-353-stack-webapp-1 sh -c \
'cd /core_app && env -u PAPERMERGE__DATABASE__URL -u PAPERMERGE__SEARCH__URL \
-u PAPERMERGE__REDIS__URL -u PAPERMERGE__MAIN__MEDIA_ROOT poetry run python' <<'PY'
from papermerge.core.config import settings as s
print(s.papermerge__database__url)
PY
实测回显(节选,与 3.4 对照):
papermerge__main__media_root = media
papermerge__database__url = sqlite:////db/db.sqlite3
papermerge__redis__url = None
papermerge__search__url = None
——数据库立刻回落到 SQLite 默认、检索回落为未配置,证明"未设 env 保留代码默认"。
2)给单条命令临时注入变量,验证覆盖生效:
docker exec -i -e PAPERMERGE__MAIN__TIMEZONE=Asia/Shanghai \
-e PAPERMERGE__OCR__DEFAULT_LANG_CODE=eng \
papermerge-353-stack-webapp-1 sh -c 'cd /core_app && poetry run python' <<'PY'
from papermerge.core.config import settings as s
print(s.papermerge__main__timezone)
print(s.papermerge__ocr__default_lang_code)
PY
实测回显:
papermerge__main__timezone = Asia/Shanghai
papermerge__ocr__default_lang_code = eng
3)i3worker 的 i3 config 同样演示 env 覆盖(实测回显):
docker exec -e PAPERMERGE__SEARCH__URL='solr://solr:8983/demo2' \
papermerge-353-stack-i3worker-1 sh -c 'cd /app && poetry run i3 config'
{
"papermerge__search__url": "solr://solr:8983/demo2",
"papermerge__redis__url": "redis://redis:6379/0",
"papermerge__main__logging_cfg": null,
"papermerge__database__url": "postgresql://pmuser:q1w2e3r4@db:5432/pmgdb"
}
四、参数总览
下表汇总四个组件 Settings 类的全部字段(默认值列 = 3.3 读到的 config.py 原文;"文档"列为官方 docs.papermerge.io settings/* 的说法,查询日期 2026-11-01):
| 变量(省略 PAPERMERGE__ 前缀) | 消费组件 | 代码默认值 | 作用 |
|---|---|---|---|
| SECURITY__SECRET_KEY | auth-server | 必填,无默认 | JWT 签名密钥(官方文档:必填) |
| SECURITY__TOKEN_ALGORITHM | auth-server | HS256 | JWT 算法(HS/RS/ES 256/384/512) |
| SECURITY__TOKEN_EXPIRE_MINUTES | auth-server | 360 | token 有效期(分钟) |
| SECURITY__COOKIE_NAME | auth-server | access_token | 会话 Cookie 名 |
| AUTH__USERNAME / PASSWORD / EMAIL | entrypoint 建号 | admin / 必填 / admin@example.com | 首启自动创建超级用户 |
| AUTH__OIDC_*(5 字段) | auth-server | None | OIDC 接入(client_secret/client_id/access_token_url/user_info_url/introspect_url) |
| AUTH__LDAP_*(5 字段) | auth-server | url None / use_ssl True / dn_format None / email_attr mail / fallback example-ldap.com | LDAP 接入 |
| DATABASE__URL | webapp / ocrworker / i3worker | sqlite:////db/db.sqlite3 | 元数据库;三组件必须一致 |
| DATABASE__POOL_SIZE | (Tivoli 专用) | 5 | 官方文档:仅内部 JWT 校验组件 Tivoli 生效 |
| REDIS__URL | webapp / ocrworker / i3worker | None | Celery broker;webapp 与 worker 必须一致 |
| SEARCH__URL | webapp / i3worker | None(文档称 xapian:////index_db) | 检索后端;webapp 与 i3worker 必须一致 |
| MAIN__MEDIA_ROOT | webapp / ocrworker | media | 文件存储根目录;两者共享同一挂载 |
| MAIN__TIMEZONE | webapp | Europe/Berlin | 时区 |
| MAIN__CACHE_ENABLED | webapp | False | 缓存开关 |
| MAIN__FILE_SERVER | webapp | local | local / s3(s3 走 CloudFront 签名 URL) |
| MAIN__CF_SIGN_URL_PRIVATE_KEY / CF_SIGN_URL_KEY_ID / CF_DOMAIN | webapp | None | FILE_SERVER=s3 时必填的 CloudFront 三件套 |
| MAIN__API_PREFIX / MAIN__PREFIX | 各组件 | '' / '' | API 前缀 / 队列名前缀(多实例共存用) |
| MAIN__LOGGING_CFG | 各组件 | /etc/papermerge/logging.yaml(worker 侧 None) | 日志配置 YAML 路径 |
| OCR__DEFAULT_LANG_CODE | webapp | deu | OCR 默认语言(AUTOMATIC=false 时参与 UI) |
| OCR__AUTOMATIC | webapp | False | 是否自动 OCR |
| OCR__LANG_CODES | (无消费代码) | —(文档默认 deu,eng,ron) | 官方定位 UI 下拉;实测 3.5.3 死配置(问题 1) |
| PREVIEW__PAGE_SIZE_SM | webapp | 200 | 缩略图像素 |
| OCR_WORKER_ARGS | ocrworker 启动脚本 | — | celery 参数,如 -Q ocr -c 2 |
| I3_WORKER_ARGS | i3worker 启动脚本 | — | celery 参数,如 -Q i3 -c 2 |
| aws_access_key_id / aws_secret_access_key / aws_region_name / S3__BUCKET_NAME | ocrworker | None | ocrworker 的 S3 存储后端 |
官方文档口径(settings/overview,查询日期 2026-11-01):全部变量里只有 PAPERMERGE__SECURITY__SECRET_KEY 与 PAPERMERGE__AUTH__PASSWORD 是必填——与实测一致:auth-server 的 config.py 里 secret_key 与 database_url 无默认值,缺失即启动失败;其余都有代码默认。
五、核心参数分类详解
5.1 DATABASE__URL:SQLite ↔ PostgreSQL 切换
三种格式(官方文档 + 本文实测):
postgresql://USER:PASSWORD@HOST:PORT/NAME
mysql://myuser:mypass@db:3306/paperdb
sqlite:////db/db.sqlite3 (代码默认,注意四斜杠=绝对路径)
- 不设该变量时 webapp 生效值即
sqlite:////db/db.sqlite3(3.5 实测回显),entrypoint 还会mkdir -p /db——这就是"单容器快速演示"形态的落库方式; - 生产切换只需在 webapp/ocr_worker/i3worker 三个服务里设置同一个 URL(官方文档三处 Note 反复强调)。本栈 compose 对三者统一设置
postgresql://pmuser:q1w2e3r4@db:5432/pmgdb,3.4 打印的生效值证实 webapp 与 i3worker 均已切到 PostgreSQL; - 切换后首次启动自动跑 alembic 迁移(部署指南 4.4 日志),空库直接可用;SQLite→PostgreSQL 的存量迁移 3.x 未提供官方工具,需自行导出导入。
DATABASE__POOL_SIZE默认 5,官方文档明确仅对 Tivoli(内部 JWT 校验组件,SQLAlchemy ORM)生效,webapp 的 Django ORM 不受它影响。
5.2 SEARCH__URL:xapian ↔ solr 切换
两种后端(官方文档 settings/search,查询日期 2026-11-01):
xapian:///PATH 例:xapian:////index_db(文档称默认值)
solr://HOST:PORT/INDEX 例:solr://solr:8983/pmg
实测要点:
- 代码默认与文档不一致:webapp config.py 里
papermerge__search__url: str | None = None(3.3 原文),3.5 实测去掉 env 后打印的也是None;官方文档"默认 xapian:////index_db"是部署形态描述(entrypoint 仅当该变量非空才做索引 schema apply)。以代码为准。 - i3worker 的 SEARCH__URL 是必填字段(config.py 原文
papermerge__search__url: str,无默认),且镜像内没有 xapian 后端——实测给 i3worker 设PAPERMERGE__SEARCH__URL=xapian:////tmp/idx后i3 config直接崩:
ModuleNotFoundError: No module named 'salinic.backends.xapian'
结论:用 i3worker 就必须用 Solr;xapian 只存在于 webapp 侧的本地检索形态。
3. webapp 与 i3worker 必须同值(官方 Note;本栈两处 compose env 同为 solr://solr:8983/pmg,3.4 的 i3 config 打印与 webapp 生效值互证)。
4. 切到 Solr 后 core 的 schema 有坑(copyField 缺失导致全文检索恒 0 命中),补丁做法见部署指南 4.1 与第九章问题 4。
5.3 REDIS__URL
格式 redis://HOST:PORT/NUMBER(例 redis://redis:6379/0)。webapp/ocrworker/i3worker 三方必须一致(官方 Note + 本栈 compose 统一设置,3.4/3.5 打印互证)。Redis 是 Celery broker 兼任务结果存储:OCR/i3 任务状态以 celery-task-meta-* 键落在其中(部署指南 8.5)。
5.4 OCR 三参数与"真实白名单"
- OCR__AUTOMATIC(默认 False):False=OCR 由用户手动调度(上传时勾选或事后触发
POST /api/tasks/ocr);True=后台调度自动跑。官方文档原文提醒 False 才适合"终端用户即管理员"的小实例。本栈 compose 显式设 false。 - OCR__DEFAULT_LANG_CODE(默认 deu):手动 OCR 时的默认语言。实测确有消费代码(webapp 内 grep):
/core_app/papermerge/core/features/nodes/router.py:123: pynode.lang = settings.papermerge__ocr__default_lang_code
/core_app/papermerge/core/config.py:24: papermerge__ocr__default_lang_code: str = 'deu'
- OCR__LANG_CODES:官方文档定位是"UI 下拉展示哪些语言,worker 里有没有由你负责",默认
deu,eng,ron。实测 3.5.3 是死配置——webapp 全代码树 greplang_codes(大小写不敏感)零命中:
docker exec papermerge-353-stack-webapp-1 sh -c \
'grep -rni "lang_codes" /core_app/papermerge | grep -v ".pyc" | head -20'
# 实测回显:(空)
ocrworker、i3worker 同样零命中。写了不报错、也不起作用(第七章问题 1)。
OCR 语言的真实约束是两层(均实测):
- API 校验白名单:
POST /api/tasks/ocr的lang只接受 schema 硬编码的 24 个 ISO 639-2 码,传zzz实测 422:
{"detail":[{"type":"literal_error","loc":["body","lang"],"msg":"Input should be 'ces', 'dan', 'deu', 'ell', 'eng', 'fas', 'fin', 'fra', 'guj', 'heb', 'hin', 'ita', 'jpn', 'kor', 'lit', 'nld', 'nor', 'pol', 'por', 'ron', 'san', 'spa', 'kaz' or 'rus'","input":"zzz","ctx":{"expected":"'ces', 'dan', 'deu', 'ell', 'eng', 'fas', 'fin', 'fra', 'guj', 'heb', 'hin', 'ita', 'jpn', 'kor', 'lit', 'nld', 'nor', 'pol', 'por', 'ron', 'san', 'spa', 'kaz' or 'rus'"}}]}
- 镜像内 tesseract 语言包:ocrworker 实测只有 5 个:
List of available languages in "/usr/share/tesseract-ocr/5/tessdata/" (5):
deu
eng
osd
ron
spa
两层取交集,本镜像实际可用 OCR 语言 = deu / eng / ron / spa。白名单内但缺语言包的码(如 jpn):API 受理(返回 null),运行时 ocrmypdf 报 MissingDependencyError → celery 任务 FAILURE——"受理≠能跑"。
5.5 SECURITY 与 AUTH(auth-server)
auth-server 的 Settings 原文(/auth_server_app/auth_server/config.py,实测读取):
class Settings(BaseSettings):
papermerge__security__secret_key: str
papermerge__security__token_algorithm: Algs = Algs.HS256
papermerge__security__token_expire_minutes: int = 360
papermerge__security__cookie_name: str = "access_token"
# database where to read user table from
papermerge__database__url: str
要点:
SECURITY__SECRET_KEY必填无默认(官方文档:大随机值、用于签发 JWT,泄露即可伪造登录态)。官方文档示例变量名写作PAPERMERGE__SECRET__SECRET_KEY,与代码字段papermerge__security__secret_key不符——以代码为准,本栈用PAPERMERGE__SECURITY__SECRET_KEY实测有效。SECURITY__TOKEN_EXPIRE_MINUTES默认 360:实测新签 token 的exp与签发时刻差21599秒 ≈ 359 分钟(解码误差内吻合)。改 7 天即PAPERMERGE__SECURITY__TOKEN_EXPIRE_MINUTES=10080(官方文档示例)。AUTH__USERNAME/PASSWORD/EMAIL:首启 entrypoint 建超级用户用(3.1),密码必填;实测日志User admin created。- OIDC:代码字段 5 个(client_secret/client_id/access_token_url/user_info_url/introspect_url),官方文档另列 authorize_url/logout_url/scope/redirect_url 等键;接 Keycloak/Authelia 属 Cloud/进阶形态,本文未实测。
- LDAP:代码字段 5 个——
ldap_url(非空即启用 LDAP 认证,不带 ldap:// 前缀)、ldap_use_ssl(默认 True)、ldap_user_dn_format(uid={username},ou=...占位格式)、ldap_email_attr(默认 mail)、ldap_user_email_domain_fallback(默认 example-ldap.com,取不到邮箱时拼<username>@<fallback>)。 - REMOTE:官方文档另有
AUTH__REMOTE头/Cookie 透传认证(Remote-User 等),配合外置反代认证使用,本文未实测。
5.6 MAIN 节
MAIN__MEDIA_ROOT:默认相对路径media(3.5 实测),生产必须给绝对路径并与 ocrworker 共享同一挂载(本栈/var/media/pmg↔ bind mount./data/media)。盘上按 UUID 前 4 hex 两级分片:原件在docvers/xx/yy/<版本UUID>/,OCR 产物在ocr/pages/xx/yy/<页UUID>/page.pdf+page.txt(布局实测见部署指南第五章)。MAIN__TIMEZONE:默认Europe/Berlin(官方文档示例同值),中文环境建议改Asia/Shanghai(3.5 已演示覆盖生效)。MAIN__FILE_SERVER:local(默认,webapp 直接发文件)或s3(AWS CloudFront 签名 URL 分发,需同时配CF_SIGN_URL_PRIVATE_KEY/CF_SIGN_URL_KEY_ID/CF_DOMAIN三键,官方文档明示目前仅支持 CloudFront)。MAIN__API_PREFIX/MAIN__PREFIX:前者影响 REST 路径前缀(本栈显式置空),后者影响 Celery 队列名前缀——设PREFIX=demo时队列变demo_ocr/demo_i3,worker 的-Q参数要跟着改(官方文档 ocrworker/i3worker 页 Note)。MAIN__CACHE_ENABLED:默认 False。PREVIEW__PAGE_SIZE_SM:默认 200 像素(列表缩略图尺寸)。MAIN__LOGGING_CFG:默认/etc/papermerge/logging.yaml,镜像内该文件实测全文:
version: 1
disable_existing_loggers: false
formatters:
verbose:
format: '%(levelname)s %(asctime)s %(module)s %(message)s'
handlers:
console:
level: INFO
class: logging.StreamHandler
formatter: verbose
loggers:
auth_server:
level: INFO
handlers: [console]
papermerge.search.tasks:
level: INFO
handlers: [console]
propagate: no
要调日志级别/输出,bind mount 一份自己的 YAML 并把 LOGGING_CFG 指过去即可(标准 Python logging dictConfig 格式)。
5.7 worker 专属参数
OCR_WORKER_ARGS/I3_WORKER_ARGS:不是 PAPERMERGE__ 变量,而是原样传给 celery worker 的启动参数。官方文档建议"-Q ocr -c 2"/"-Q i3 -c 2"(队列名ocr/i3,与MAIN__PREFIX联动)。本栈实测启动横幅[queues] .> ocr exchange=ocr(direct) key=ocr(部署指南 4.4)。- ocrworker 的 S3 存储四键(
aws_access_key_id/aws_secret_access_key/aws_region_name/S3__BUCKET_NAME,config.py 原文见第四章表):ocrworker 支持本地图或 S3 两种存储后端(官方文档 settings/ocrworker),配了就走 S3,本文未实测。 - i3worker 的 config.py 全文只有四个字段(
search__url必填、redis__url、logging_cfg、database__url),职责单一:把数据库内容同步进索引。
六、生产配置模板
综合实测结论,生产最小正确集(六服务 compose 的 environment: 摘录,与部署指南 4.2 一致):
# webapp / ocr_worker / i3worker 三者必须一致的键
PAPERMERGE__DATABASE__URL: postgresql://<user>:<pass>@db:5432/pmgdb
PAPERMERGE__REDIS__URL: redis://redis:6379/0
# webapp / i3worker 必须一致
PAPERMERGE__SEARCH__URL: solr://solr:8983/pmg
# webapp / ocr_worker 必须一致且为绝对路径
PAPERMERGE__MAIN__MEDIA_ROOT: /var/media/pmg
# 必填
PAPERMERGE__SECURITY__SECRET_KEY: <64位随机串>
PAPERMERGE__AUTH__PASSWORD: <强密码>
# 建议按环境调整
PAPERMERGE__MAIN__TIMEZONE: Asia/Shanghai
PAPERMERGE__OCR__DEFAULT_LANG_CODE: <你的主要文档语言>
OCR_WORKER_ARGS: "-Q ocr -c 2"
I3_WORKER_ARGS: "-Q i3 -c 2"
一致性矩阵(错配的典型后果):
| 键 | 必须同步的组件 | 错配后果 |
|---|---|---|
| DATABASE__URL | webapp、ocr_worker、i3worker | worker 读写错库,OCR 结果不可见 |
| REDIS__URL | webapp、ocr_worker、i3worker | 任务投递进空队列,OCR 永不执行 |
| SEARCH__URL | webapp、i3worker | 一边查 A 核一边写 B 核,检索恒 0 命中 |
| MAIN__MEDIA_ROOT | webapp、ocr_worker | OCR worker 找不到原件文件 |
| MAIN__PREFIX | 全部 + WORKER_ARGS 的 -Q | 队列名对不上,同上 |
七、常见问题
问题 1:PAPERMERGE__OCR__LANG_CODES 配了没效果
3.5.3 实测三个组件代码树 grep lang_codes 全部零命中(5.4),它是死配置:不报错、不生效。官方文档把它定位为"UI 下拉展示",且明确语言可用性由 worker 自担责任。实际约束在 API 硬编码 24 码白名单 + 镜像 tesseract 语言包(5.4),可用交集为 deu/eng/ron/spa。要加语言,得往 ocrworker 镜像里补 tessdata 并确认码在 24 白名单内。
问题 2:OCR 任务返回 null 但没出文本
POST /api/tasks/ocr 受理即返回 null(HTTP 200),不代表能跑成功。实测传白名单内但缺语言包的 jpn:任务被 celery 接收后 ocrmypdf 报 MissingDependencyError,Redis celery-task-meta-* 状态 FAILURE。排查顺序:先核对 5.4 的两层白名单,再看 Redis 任务元数据与 media 盘产物(部署指南 8.5)。
问题 3:i3worker 配 xapian 起不来
i3worker 的 SEARCH__URL 必填且镜像未安装 xapian 后端,实测设 xapian:////tmp/idx 直接 ModuleNotFoundError: No module named 'salinic.backends.xapian'(5.2)。部署了 i3worker(要 Solr 全文检索)就只能用 solr://。
问题 4:官方文档默认值与代码默认值不一致
两处实测不一致:SEARCH__URL(文档 xapian:////index_db vs 代码 None)、SECURITY__SECRET_KEY 的示例变量名(文档 PAPERMERGE__SECRET__SECRET_KEY vs 代码字段 security 节)。以镜像内 config.py 为准(3.3 的读法),文档当导读。
问题 5:改了 compose 环境变量但"没生效"
pydantic-settings 只在进程启动时读一次 env。改完必须 docker compose up -d(变量变化会重建对应容器);docker exec -e 是一次性的(3.5),不会改变常驻进程的配置。验证生效用 3.4 的打印法,别看 compose 文件猜。
问题 6:token 6 小时就过期
默认 TOKEN_EXPIRE_MINUTES=360(5.5 实测吻合)。长任务脚本要么按周期重登 POST /api/token,要么调大该变量(如 10080=7 天,官方文档示例)。注意它属于 auth-server 配置,改后需重建 webapp 容器。
八、参考链接
- 官方配置文档总览:https://docs.papermerge.io/latest/settings/overview/ (PAPERMERGE__ 命名约定与必填项,页脚 June 1, 2026,查询日期 2026-11-01)
- 各节文档:https://docs.papermerge.io/latest/settings/database/ 、settings/search/ 、settings/redis/ 、settings/ocr/ 、settings/main/ 、settings/security/ 、settings/auth/ 、settings/ocrworker/ 、settings/i3worker/ (同站,查询日期 2026-11-01)
- 官方版本矩阵:https://docs.papermerge.io/latest/admin-manual/version-matrix/
- GitHub 仓库:https://github.com/papermerge/papermerge-core
- 站内参考:《Papermerge 介绍与选型指南》《Papermerge 3.5.3 Docker Compose 部署指南》《Papermerge 3.5.3 API 使用详解》