Paperless-ngx 运维管理指南:备份、升级与全套管理命令实战
本文基于 paperless-ngx 仓库的 docs/administration.md 编写,覆盖 Paperless-ngx 实例管理的三大核心主题:备份与恢复策略、Docker/裸机两条升级路径,以及 14 个内置管理命令(exporter、importer、retagger、sanity checker、archiver 等)的完整参数说明。结合仓库源码,本文进一步解释了导出增量机制、ZIP 压缩实现细节、模糊去重的 rapidfuzz 算法与容器启动时自动迁移/重建索引的 s6 初始化流程,帮助你在生产环境中安全地备份、升级和长期维护一个 Paperless-ngx 文档管理系统。
备份策略:从导出器到卷备份
备份的核心前提是:备份时确保 Paperless 没有在消费(consume)文档,否则可能出现文件与数据库状态不一致。根据文档和仓库中的 Docker Compose 配置,备份选项分为三类:
使用 document_exporter 备份(所有安装方式通用)
文档导出器 将全部文档、缩略图、元数据和数据库内容导出到一个指定目录。它有两个重要特性:
- 支持增量更新:exporter 可以更新一份已存在的导出,因此配合
rsync完全可行; - 不包含 API Token:导入后需要重新生成 API Token。
注意:不能用某个版本的 paperless 生成的导出来导入另一个版本的 paperless。导出包含数据库的精确镜像,而数据库迁移(migration)可能改变数据库布局。
Docker 安装:备份 Docker 卷
对于 Docker 部署,可以直接备份主机上的卷(通常位于 /var/lib/docker/volumes,需要 root 权限)。从 docker/compose/docker-compose.postgres.yml 的 volumes: 段可以看到 Paperless 使用的卷定义:
paperless_media:文档存储位置;paperless_data:辅助数据,如果使用 SQLite,SQLite 数据库也在此卷中;paperless_pgdata:仅在使用 PostgreSQL 时存在,存放数据库;paperless_dbdata:仅在使用 MariaDB 时存在,存放数据库。
Compose 文件中还可以看到 ./export:/usr/src/paperless/export 的挂载(见 docker-compose.postgres.yml 第 53 行),这为 exporter 提供了标准化的导出目录。
裸机/非 Docker 安装:备份整个目录
直接备份整个 paperless 安装目录,实例崩溃或磁盘故障时把目录拷回去即可恢复。若使用 PostgreSQL 或 MariaDB,还需额外备份数据库。
恢复
如果用的是 document exporter 备份,恢复就是用 document importer 导入;其他备份策略则恢复对应的卷、目录和数据库副本。
升级 Paperless
警告:升级至 v3.0 前必须阅读 migration-v3.md,其中包含需要手动干预的破坏性变更。另外,升级到 v3 会清空既有任务历史(已完成/失败/已确认的任务不再显示),无需任何操作。
Docker 升级路径
- 确保没有正在运行的活动进程(如 consume),并先做备份;
- 停止 paperless:
$ cd /path/to/paperless
$ docker compose down
- 从 Docker Hub 拉取镜像的用户:
docker compose pull
docker compose up
Docker Compose 文件引用的是 latest 版本,始终指向最新稳定版(可对照 docker/compose/ 下的各 compose 文件)。
自行构建镜像的用户:
git pull
docker compose build
docker compose up
docker compose up 会同时应用新的数据库迁移。确认一切正常后,按一次 CTRL+C 优雅停止,再用 -d 转入后台运行。
两个值得注意的版本行为:
- 0.9.14 起:compose 文件改用
latest标签,pull即可升级;更早版本需把image: ghcr.io/paperless-ngx/paperless-ngx:0.9.x改为:latest; - 1.7.1 起:镜像可固定到发布系列(release series),例如
image: ghcr.io/paperless-ngx/paperless-ngx:1.7,常与 Watchtower 等自动更新器组合使用,只自动接收 bugfix 更新。即便如此仍建议升级前阅读 release notes。
裸机升级路径
警告:把新版压缩包解压覆盖到已有安装目录(如
tar -xf paperless-ngx-vX.Y.Z.tar.xz -C /opt/paperless)只会新增和覆盖文件,不会删除新版本中已移除的文件。旧版本遗留的文件(如已被取代的数据库迁移)可能残留在磁盘上,导致manage.py migrate时出现NodeNotFoundError。解压新包前应移除旧源码树(保留media、data、consume目录和paperless.conf/.env),或解压到全新目录再迁移持久化数据与配置。通过git pull更新的干净检出仓库不受此影响,因为 Git 会删除上游已不存在的文件。
完整步骤:
- 更新系统依赖:新版本可能要求额外依赖,裸机安装所需依赖见 setup.md;
- 更新 Python 依赖(先激活虚拟环境):
pip install -r requirements.txt
有时依赖会从 requirements 中移除,对照版本并清理不再需要的依赖可保持环境干净;
- 迁移数据库:
cd src
python3 manage.py migrate # 可能需要 sudo -Hu <paperless_user>
并非每个新版本都带新迁移,此命令可能什么都不做;
- 如需要重建搜索索引:
cd src
python3 manage.py document_index reindex --if-needed
索引已是最新时这是 no-op,因此每次升级都可以安全执行;
- 如需要迁移 LLM 索引:
cd src
python3 manage.py document_llmindex migrate
同样在索引 schema 已最新时为 no-op,适合每次升级时例行执行。
数据库升级
Paperless-ngx 兼容 Django 所支持的 PostgreSQL 与 MariaDB 版本,升级到更高版本数据库通常安全,但务必先备份,并遵循数据库官方文档的主版本升级流程(PostgreSQL 参考官方 "Upgrading a PostgreSQL Cluster",MariaDB 参考官方 "Upgrading MariaDB")。自 v2.18 起,最低支持的 PostgreSQL 版本为 14。
也可以在新版数据库中先建库,再用 exporter/importer 的 --data-only 标志迁移纯数据——此时不要改动任何配置尤其是路径,否则有数据丢失风险。
管理命令(Management Utilities)
Paperless 提供了一系列管理命令执行维护任务。调用方式因部署方式而异:
Docker Compose(paperless 运行时):
$ cd /path/to/paperless
$ docker compose exec webserver <command> <arguments>
Docker 原生(paperless 运行时):
$ docker exec -it <container-name> <command> <arguments>
裸机:
$ cd /path/to/paperless/src
$ python3 manage.py <command> <arguments> # 可能需要 sudo -Hu <paperless_user>
所有命令都内置帮助:加 --help 参数即可查看。
Document exporter
document_exporter 将全部数据(含配置和数据库内容)导出到目录,用于备份或迁移到其他 DMS。所有命令源码位于 src/documents/management/commands/ 目录。
如果放在 cronjob 中定时备份,可在 exec 后加 -T 标志抑制 "The input device is not a TTY" 错误,例如:
docker compose exec -T webserver document_exporter ../export
完整参数列表:
document_exporter target [-c] [-cj] [-d] [-f] [-na] [-nt] [-p] [-sm] [-z] [-zn]
[--zip-compression] [--zip-compression-level]
[--data-only] [--no-progress-bar] [--passphrase]
| 选项 | 说明 |
|---|---|
target |
导出目标目录,包含文档、缩略图和 manifest.json(内含数据库中全部元数据:correspondent、tag 等) |
-c, --compare-checksums |
用校验和而非"修改时间+大小"判断文件是否变化,更慢但更可靠 |
-cj, --compare-json |
manifest 和元数据 json 也按内容比较,默认总是重写 |
-d, --delete |
删除导出目录中不属于当前导出的文件(如已删文档的文件),指向已有其他文件的目录时要小心 |
-f, --use-filename-format |
导出文件名使用 PAPERLESS_FILENAME_FORMAT 而非默认的 [创建日期] [correspondent] [标题].[扩展名] |
-na, --no-archive |
不导出归档(archive)文件,只导出原件 |
-nt, --no-thumbnail |
不导出缩略图 |
-p, --use-folder-prefix |
按性质分目录导出:archive、originals、thumbnails、json |
-sm, --split-manifest |
每份文档信息写入独立 json 文件;主 manifest.json 仍含应用级信息(tags、correspondent、document type 等) |
-z, --zip |
导出为 zip 文件,默认按当前本地日期命名,可用 -zn/--zip-name 指定 |
--zip-compression |
zip 压缩方式:stored、deflated(默认)、bzip2、lzma 或 zstd |
--zip-compression-level |
压缩级别:deflated 0–9、bzip2 1–9、zstd -22–22;stored 与 lzma 忽略此参数。两者都要求 -z |
--data-only |
只导出数据库,便于数据库升级而无需清理 media 目录 |
--no-progress-bar |
隐藏进度条,适合 crontab 等脚本场景 |
--passphrase |
加密导出中的敏感字段;导入时必须提供,丢失则导出无法导入 |
使用官方 compose 脚本时,target 指定 ../export——容器内该路径会自动挂载到宿主机的 export 目录。
增量导出的判定逻辑:若目标目录已存在且含文件,paperless 会将其视为上一次的导出并尝试更新,只导出有变化和新增的文件;默认依据文件的"修改时间"和"大小"判断,不满足时可用 -c 改为比较校验和。paperless 不会主动删除导出目录中的既有文件。
源码层面的压缩实现:src/documents/export/compression.py 定义了 COMPRESSION_CHOICES 与各级别边界(LEVEL_BOUNDS)。其中 zstd 仅在 Python 3.14+(PEP 784 的 ZIP_ZSTANDARD)上可用,compression_available() 会探测当前解释器能否使用该压缩器;因此 zstd 压缩要求创建导出和导入导出的两台机器都运行 Python 3.14 或更高版本,否则导入端会以明确错误拒绝该压缩包。默认的 deflated 则任何环境都可读。
另外两点注意事项:使用 -f/文件名格式导出时可能触发操作系统最大路径长度限制,可调整导出目标或放弃文件名格式;使用 -na/-nt 后,导入方需要先用 document_thumbnails 或 document_archiver 重新生成缺失文件,在此之前 sanity checker 会持续告警——但省略这些文件备份也合理,因为其内容和校验和可能随归档算法变化而变化,会在去重备份中占用额外空间。
Document importer
document importer 接收 exporter 生成的导出并导入 paperless,用法与 exporter 对称——指向导出目录或生成的 zip 文件即可:
document_importer source
| 选项 | 必填 | 默认 | 说明 |
|---|---|---|---|
source |
是 | N/A | 包含导出的目录(或 zip 文件) |
--no-progress-bar |
否 | False | 隐藏进度条 |
--data-only |
否 | False | 只导入数据,不导入文档文件和缩略图 |
--passphrase |
否 | N/A | 若导出用口令加密过则必须提供 |
--batch-size |
否 | 500 | 每批写入数据库的记录数;大型部署可设小以降低峰值内存 |
使用官方 compose 脚本时,把导出放进源码目录的 export 文件夹,source 指定 ../export。
注意:从旧版本导入可能可行,但版本一致效果最佳。
警告:importer 应针对完全空的 Paperless-ngx 安装(数据库和目录均为空)运行;
--data-only导入时只需数据库为空。
源码佐证:src/documents/management/commands/document_importer.py 使用 ijson 逐条流式解析 manifest.json(iter_manifest_records),避免一次性把整个清单载入内存;记录通过 bulk_create 批量插入,多对多关系在批量保存后统一应用,这正是 --batch-size 能控制峰值内存的机制。口令解密由 CryptMixin(src/documents/management/commands/mixins.py)统一处理。
Document retagger
导入数百份文档后想新增 tag 或 correspondent 并让匹配规则作用于存量文档,就用到 retagger:
document_retagger [-h] [-c] [-T] [-t] [-s] [-i] [--id-range] [--use-first] [-f]
在修改或新增匹配规则之后运行。它会遍历数据库中所有文档,按新规则尝试匹配。要点:
- 必须指定
-c(correspondent)、-T(tags)、-t(document_type)、-s(storage_path)的任意组合来决定对哪种元数据执行匹配;一个都不指定则什么都不做; -i, --inbox-only:只处理打了 inbox tag 的文档,避免干扰已处理完毕的文档;--id-range 1 100:只处理指定 id 区间的文档,方便先在小范围测试规则;--use-first:多个 correspondent/type 同时匹配同一文档时默认不分配,加此参数则采用找到的第一个(对 tags 无效,tag 数量不限);-f, --overwrite:覆盖已分配的 correspondent/type/tags。默认行为是不覆盖已有 correspondent/type;对 tags 则默认只追加不删除,加-f后不再匹配的 tag 也会被移除。
管理自动匹配(机器学习分类器)
Auto 匹配算法依赖一个训练好的神经网络,数据变化后需要更新。Docker 镜像通过任务调度器自动处理;裸机可手动执行:
document_create_classifier
该命令不接受参数,实现见 src/documents/management/commands/document_create_classifier.py。
Document thumbnails
重建文档缩略图:
document_thumbnails [--document {id}] [--processes N]
--document {id}:只为指定文档生成缩略图;--processes:控制生成缩略图所用进程数,默认使用可用处理器核数的四分之一。
管理文档搜索索引
搜索索引负责为网站提供搜索结果,文档增删改时会自动更新;但当搜索返回不存在的文档或搜不到任何内容时,可能需要手动重建:
document_index {reindex,optimize} [--recreate] [--if-needed]
reindex:从数据库中所有文档重建索引,可能耗时较长;--recreate:重建前先清空现有索引,适用于索引损坏或需要完全干净重建的场景;--if-needed:索引已是最新(schema 版本和搜索语言一致)时跳过重建,可安全用于每次启动或升级;optimize:优化索引,任务调度器会定期调用。注意:optimize子命令已弃用,现在是 no-op——Tantivy 会自行管理 segment 合并,无需手动优化。
Docker 用户:每次容器启动时会自动运行 document_index reindex --if-needed,schema 变化、语言变化、索引缺失都会在 webserver 启动前被检测并重建。从 docker/rootfs/etc/s6-overlay/s6-rc.d/ 可以看到容器通过 s6-overlay 编排了一系列初始化单元,init-search-index 即负责这一步,另有 init-migrations(数据库迁移)和 init-llmindex-migrate(LLM 索引迁移)——这正是"Docker 升级无需手动步骤"的底层依据。
裸机用户:每次升级后(以及修改 PAPERLESS_SEARCH_LANGUAGE 后)执行:
cd src
python3 manage.py document_index reindex --if-needed
索引已是最新时为 no-op。
管理 LLM(AI)向量索引
启用 AI 功能 并配置了 embedding 后端时,Paperless-ngx 会维护一个文档向量索引,用于 RAG、相似文档检索和文档聊天。索引按 PAPERLESS_LLM_INDEX_TASK_CRON 设定的计划自动更新,也可手动管理:
document_llmindex {rebuild,update,compact,migrate}
rebuild:从全部文档从零重建;首次启用、或更换 embedding 后端/模型时使用;update:增量索引新增和变更的文档,即计划任务执行的内容;compact:回收空间并优化磁盘上的向量存储;migrate:升级后迁移索引 schema(升级流程第 5 步已提及)。
注意:AI 未启用或未配置 embedding 后端时这些命令无效果。实现位于 src/documents/management/commands/document_llmindex.py 与 src/paperless_ai/ 模块。
清空数据库读缓存
若启用了数据库读缓存,只要你在应用上下文之外修改了数据库(恢复备份、执行 UPDATE/INSERT/DELETE/ALTER/CREATE/DROP 等 SQL),就必须运行:
python3 manage.py invalidate_cachalot
缓存失效不彻底会导致脏数据,可能造成数据损坏或不一致行为。该缓存基于 Django-Cachalot 实现。
管理文件名(renamer)
若使用了 自定义文档命名 功能,修改命名方案后用此命令批量移动所有文件:
document_renamer
命令不接受参数,一次性处理全部文档。
警告:此命令会移动你的文档,建议先做备份。重命名逻辑健壮,永远不会覆盖或删除文件——但备份总不嫌多。
Sanity checker
内置的完整性检查器扫描文档集合中的问题。检测项包括:
- 原件文件缺失;
- 归档文件缺失;
- 原件/归档文件因权限问题不可访问;
- 原件/归档文件损坏(与数据库中存储的校验和比对);
- 缩略图缺失、缩略图权限不可访问;
- 无内容的文档(warning);
- media 目录中的孤儿文件(warning)——不被任何文档引用的文件。
document_sanity_checker
不接受参数,耗时取决于文档库规模。实现见 src/documents/sanity_checker.py,命令以 Rich 表格按 ERROR/WARN/INFO 分级输出结果(见 document_sanity_checker.py)。
抓取邮件
Paperless 默认每 10 分钟自动抓取邮件。手动触发邮件消费者:
mail_fetcher
不接受参数,处理所有邮件账户和规则。实现位于 src/paperless_mail/management/commands/mail_fetcher.py。
提示:要使用 OAuth 访问令牌抓取邮件,在创建/编辑邮件账户时勾选"密码实际上是 token"选项。令牌创建方式取决于邮件服务商。
创建归档文档(archiver)
Paperless 在原件旁存储 PDF/A 归档文档,图片类原件的归档版包含可选中的文本。原件始终不做修改。从旧版本升级来的文档可能没有归档版本,此命令可为它们生成:
document_archiver --overwrite --document <id>
- 默认只在尚无归档版本时尝试创建,加
--overwrite才重建已有归档版本; --document <id>限定只处理该文档。
从 document_archiver.py 源码看,命令通过 process_parallel 并行调用 update_document_content_maybe_archive_file 任务,按 doc.has_archive_version 过滤待处理文档,且可随任意时刻取消——重跑时会跳过已归档的版本。
两点注意:
- 该命令实质上会按当前设置对全部文档重新执行 OCR,
PAPERLESS_OCR_MODE=redo下可能运行极长时间; - 部分文档(如加密 PDF)无法转换为 PDF/A,archiver 每次遇到都会跳过。
检测重复文档(fuzzy duplicate)
Paperless-ngx 会捕获并警告完全一致的重复文档,但同一文档的重新扫描往往不会产生逐位重复——内容应接近但不完全相同,这正是模糊匹配的用武之地。该工具对文档内容做模糊匹配,按给定相似度比例报告接近的文档对(目前不考虑 correspondent、type 等其他元数据):
document_fuzzy_match [--ratio] [--processes N] [--delete] [--url]
| 选项 | 必填 | 默认 | 说明 |
|---|---|---|---|
--ratio |
否 | 85.0 | 0–100 的数值,数值越高要求越相似 |
--processes |
否 | 系统核数 1/4 | 匹配所用进程数,设为 1 则禁用多进程 |
--delete |
否 | False | 对超过阈值的匹配对,删除其中一份(需配合确认) |
--url |
否 | 空 | 提供实例 URL 时,结果表格显示可点击的文档链接而非 ID 与标题 |
警告:使用
--delete前强烈建议做好备份。虽然实现上已尽力保证正确性,但总存在误删所需文件的可能。
源码佐证:document_fuzzy_match.py 使用 rapidfuzz.fuzz.ratio 计算相似度,并把 --ratio 作为 score_cutoff 传入以提前剪枝;多进程通过 PaperlessCommand.process_parallel 分发 _WorkPackage;结果以 Rich 表格呈现,相似度按 97%+/92%+/88%+ 分档着色,--url 模式下渲染为指向 <url>/documents/<id>/details 的链接。
清理审计日志(audit log)
启用审计日志后,Paperless-ngx 会记录所有文档变更。虽然已加入自动清理已删文档条目的功能,但该功能启用前产生的条目不会被自动移除。此命令可手动修剪不再需要的条目:
prune_audit_logs
实现见 src/documents/management/commands/prune_audit_logs.py。
创建超级用户
需要创建超级用户时:
createsuperuser
对应 src/documents/management/commands/manage_superuser.py。
总结
Paperless-ngx 的运维体系可以归纳为三条主线:
- 备份:优先使用
document_exporter(支持增量更新与rsync配合),Docker 环境可直接备份media/data/pgdata/dbdata卷; - 升级:Docker 用户只需
pull/build+up,容器 s6 初始化流程会自动完成数据库迁移、搜索索引按需重建(init-search-index)和 LLM 索引迁移(init-llmindex-migrate);裸机用户按"依赖 → migrate →document_index reindex --if-needed→document_llmindex migrate"四步走; - 日常维护:
document_sanity_checker定期体检、document_fuzzy_match去重、invalidate_cachalot保护读缓存一致性、mail_fetcher/document_archiver等按需触发。
所有命令在 src/documents/management/commands/ 有对应源码,相关行为可由 src/documents/tests/ 下的测试用例(如 test_management_exporter.py、test_management_fuzzy.py、test_management_sanity_checker.py)进一步验证。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00