首页
/ Paperless-ngx 运维管理指南:备份、升级与全套管理命令实战

Paperless-ngx 运维管理指南:备份、升级与全套管理命令实战

2026-09-07 17:43:55作者:谭伦延

本文基于 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.ymlvolumes: 段可以看到 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 升级路径

  1. 确保没有正在运行的活动进程(如 consume),并先做备份
  2. 停止 paperless:
$ cd /path/to/paperless
$ docker compose down
  1. 从 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。解压新包前应移除旧源码树(保留 mediadataconsume 目录和 paperless.conf/.env),或解压到全新目录再迁移持久化数据与配置。通过 git pull 更新的干净检出仓库不受此影响,因为 Git 会删除上游已不存在的文件。

完整步骤:

  1. 更新系统依赖:新版本可能要求额外依赖,裸机安装所需依赖见 setup.md
  2. 更新 Python 依赖(先激活虚拟环境):
pip install -r requirements.txt

有时依赖会从 requirements 中移除,对照版本并清理不再需要的依赖可保持环境干净;

  1. 迁移数据库
cd src
python3 manage.py migrate   # 可能需要 sudo -Hu <paperless_user>

并非每个新版本都带新迁移,此命令可能什么都不做;

  1. 如需要重建搜索索引
cd src
python3 manage.py document_index reindex --if-needed

索引已是最新时这是 no-op,因此每次升级都可以安全执行;

  1. 如需要迁移 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 按性质分目录导出:archiveoriginalsthumbnailsjson
-sm, --split-manifest 每份文档信息写入独立 json 文件;主 manifest.json 仍含应用级信息(tags、correspondent、document type 等)
-z, --zip 导出为 zip 文件,默认按当前本地日期命名,可用 -zn/--zip-name 指定
--zip-compression zip 压缩方式:storeddeflated(默认)、bzip2lzmazstd
--zip-compression-level 压缩级别:deflated 0–9、bzip2 1–9、zstd -22–22;storedlzma 忽略此参数。两者都要求 -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_thumbnailsdocument_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.jsoniter_manifest_records),避免一次性把整个清单载入内存;记录通过 bulk_create 批量插入,多对多关系在批量保存后统一应用,这正是 --batch-size 能控制峰值内存的机制。口令解密由 CryptMixinsrc/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.pysrc/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 的运维体系可以归纳为三条主线:

  1. 备份:优先使用 document_exporter(支持增量更新与 rsync 配合),Docker 环境可直接备份 media/data/pgdata/dbdata 卷;
  2. 升级:Docker 用户只需 pull/build + up,容器 s6 初始化流程会自动完成数据库迁移、搜索索引按需重建(init-search-index)和 LLM 索引迁移(init-llmindex-migrate);裸机用户按"依赖 → migrate → document_index reindex --if-neededdocument_llmindex migrate"四步走;
  3. 日常维护document_sanity_checker 定期体检、document_fuzzy_match 去重、invalidate_cachalot 保护读缓存一致性、mail_fetcher/document_archiver 等按需触发。

所有命令在 src/documents/management/commands/ 有对应源码,相关行为可由 src/documents/tests/ 下的测试用例(如 test_management_exporter.pytest_management_fuzzy.pytest_management_sanity_checker.py)进一步验证。

登录后查看全文
热门项目推荐
相关项目推荐