外观
Paperless-ngx:纸质文档归档
完成后,把扫描仪或手机拍的纸质文档丢进一个共享文件夹,Paperless-ngx 会自动做 OCR(包括中文)、归档、打标签,之后可以全文搜索。你也清楚数据库和文档该怎么备份。
适合谁
- 有一堆合同、发票、账单、证件要整理,希望搜得到。
- 有扫描仪,或者愿意用手机扫描 App 把文件传到 NAS 的共享文件夹里。
- 能接受它吃 CPU:OCR 很耗资源,官方有专门的低配设备章节。
应用信息
| 项 | 内容 |
|---|---|
| 示例清单 | 有 paperless-ngx,示例文件日期 2026-03-30,缺少 v3 必填的两个变量,见下 |
| 容器 | broker(Redis)、db(PostgreSQL)、webserver(Paperless-ngx) |
| 示例里的端口 | 8000(示例注释里写的是 8010,以 ports 的实际值为准) |
| 数据 | 文档原件和归档版本在 media;搜索索引在 data;导出放在 export;投递目录 consume |
| 官方文档 | docs.paperless-ngx.com |
示例没有 v3 要求的两个变量
Paperless-ngx 现在的最新发布是 v3.x,而示例的镜像用 latest。官方的 v3 迁移指南明确:
PAPERLESS_SECRET_KEY变成必填项,用于签名,应该是一个很长的随机值。- PostgreSQL 必须显式写
PAPERLESS_DBENGINE: postgresql。v3 不再根据PAPERLESS_DBHOST推断数据库类型。
示例里两者都没有。没有密钥,官方文档说 Paperless 会拒绝启动;没有 PAPERLESS_DBENGINE,数据库类型默认是 sqlite,示例里那个 PostgreSQL 容器就白跑了。下面的版本补上了这两项。示例里的数据库密码 paperless 也是默认值,建议换掉。
部署
准备这些共享文件夹,名字自己取:
| 共享文件夹 | 用途 |
|---|---|
appdata | Redis、PostgreSQL 的数据,Paperless 的 data。放在 SSD 上更快 |
paperless | 文档原件 media 和导出目录 export。放大盘 |
scans | 投递目录,扫描仪和手机用 SMB 往里放文件。需要给扫描用的用户写权限,见常见权限方案 |
专用用户 appuser 对它们有读写权限,见容器权限:PUID、PGID 与共享文件夹。
服务 → Compose → 文件(Services → Compose → Files)→ 添加 → 从模板添加,选 paperless-ngx,添加后 编辑。改成这样:
yaml
services:
broker:
image: docker.io/library/redis:8
restart: unless-stopped
volumes:
- ${{ sf:"appdata" }}/paperless-ngx/redis:/data
db:
image: docker.io/library/postgres:17
restart: unless-stopped
volumes:
- ${{ sf:"appdata" }}/paperless-ngx/postgres:/var/lib/postgresql
environment:
POSTGRES_DB: paperless
POSTGRES_USER: paperless
POSTGRES_PASSWORD: <数据库密码>
webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:latest
restart: unless-stopped
depends_on:
- db
- broker
ports:
- "8000:8000"
volumes:
- ${{ sf:"appdata" }}/paperless-ngx/data:/usr/src/paperless/data
- ${{ sf:"paperless" }}/media:/usr/src/paperless/media
- ${{ sf:"paperless" }}/export:/usr/src/paperless/export
- ${{ sf:"scans" }}:/usr/src/paperless/consume
environment:
PAPERLESS_REDIS: redis://broker:6379
PAPERLESS_DBHOST: db
PAPERLESS_DBENGINE: postgresql
PAPERLESS_DBPASS: <数据库密码>
PAPERLESS_SECRET_KEY: <随机密钥>
PAPERLESS_TIME_ZONE: ${{ tz }}
PAPERLESS_OCR_LANGUAGE: chi_sim+eng
PAPERLESS_OCR_LANGUAGES: chi-sim
USERMAP_UID: ${{ uid:"appuser" }}
USERMAP_GID: ${{ gid:"users" }}改动的说明:
<数据库密码>要在db和webserver里写成同一个值,不然连不上数据库。compose 文件默认只有 root 能读。<随机密钥>用官方的办法生成:在你的电脑或 OMV 的 shell 里运行python3 -c "import secrets; print(secrets.token_urlsafe(64))"。- PostgreSQL 版本:示例用 17,官方当前的 compose 用 18。新装两个都可以,装好之后别改大版本:PostgreSQL 大版本之间的数据目录不兼容,Paperless 的官方做法是先备份,再用导出和导入配合新建的数据库,见官方文档的 Database Upgrades 一节。
PAPERLESS_OCR_LANGUAGES是要安装的语言包,空格分隔,这里写chi-sim;PAPERLESS_OCR_LANGUAGE是识别时使用的语言,用 Tesseract 的三位代码,名字里的-要写成_,所以是chi_sim,多个语言用+连接。繁体中文是chi-tra和chi_tra。语言越多,CPU 耗得越多。 另外官方说明,指定了额外语言就不能用 rootless 容器。USERMAP_UID、USERMAP_GID决定 Paperless 用哪个用户读写投递目录,要对上appuser和users。- 通过反向代理用域名访问时,还要设
PAPERLESS_URL,见反向代理与 HTTPS。 - 示例的
.env文件里有一处拼写错误(APERLESS_REDIS),不影响,因为上面的environment里已经写了PAPERLESS_REDIS。
点 保存,检查,上线。第一次要下载镜像,数据库和索引初始化也要一会儿。
首次使用
- 浏览器打开
http://<NAS 的 IP>:8000。官方文档说,第一次打开网页会提示创建超级用户。没有出现提示的话,在 OMV 的 shell 里(root)运行omv-compose-run paperless-ngx exec webserver createsuperuser,按提示创建。 - 超级用户拥有所有文档的权限,官方建议再建一个日常使用的普通账号。
- 把一个 PDF 放进
scans共享文件夹,等一会儿,它会从投递目录消失,出现在 Paperless 里。处理完的文件会被移走,所以别把唯一的一份原件直接放进投递目录。
投递目录在 NFS 这类不支持 inotify 的网络文件系统上时,新文件不会被发现,要设 PAPERLESS_CONSUMER_POLLING_INTERVAL 为一个正数来启用轮询。scans 是 NAS 本地的共享文件夹,不受影响。
备份:数据库和文档怎么备份才安全
别指望不停机的热备份
Paperless 把文档的元数据、标签、对应关系都放在 PostgreSQL 里。数据库文件在写入时被复制,拷贝可能损坏。
- 影响范围:数据库坏了,文档原件还在,但标签、通信方、自定义字段这些整理工作全部丢失,要重新整理。
- 前置条件:不要给它的计划备份勾选 跳过容器停止 / 启动,见更新与备份容器。
- 怎么回退:已经热备份过的,当作不可靠,按下面的方式补做一份导出。
官方给的应用自带的备份是 文档导出器(document_exporter):它把所有文档、缩略图、数据库里的全部元数据导出到一个目录,里面有 manifest.json。
sh
omv-compose-run paperless-ngx exec -T webserver document_exporter ../export- 这条命令在 OMV 的 shell 里以 root 运行。
-T不分配终端,用在定时任务里不会报错。../export是容器里的路径,它对应你挂载的paperless/export。 - 目标目录里已有内容时,它只更新有变化的文件,不会删除已有的文件。想把已删除文档对应的文件也清掉,加
-d,目标目录里有别的文件时要小心。 - 把这条命令放进
系统 → 计划任务(System → Scheduled Tasks),每天夜里跑一次,见计划任务。 - 官方提醒备份前最好确认没有在导入文档。
然后把这些东西用文件备份工具备份到别处,见rsync 任务:
| 内容 | 位置 |
|---|---|
| 导出目录 | paperless/export |
| 文档原件 | paperless/media |
| compose 文件 | 插件的计划备份会带上 |
要点:
- 导出只能被同版本的 Paperless-ngx 导入。 官方说:导出里是数据库的一个精确镜像,迁移可能改变表结构,所以不同版本之间导入可能失败。恢复时,装一个和导出时相同版本的全新实例。
- 导出不含 API 令牌,恢复后要重新生成。
- 导入器应该在一个完全空的 Paperless-ngx 上运行,用
document_importer,具体步骤按官方的管理文档,别凭记忆敲命令。 - 不用导出器的方案是直接备份 Docker 卷或目录,数据库也要一起,并且要先停容器。这就是插件默认的「停止 → 备份 → 启动」,但注意插件默认只备份 1 GB 以内的卷,
media要加# BACKUP或用文件备份工具。
升级
- v3 有破坏性改动。 官方的迁移指南说,升级到 v3 只能从 2.20.15 开始,并且有一批变量要改:消费者的轮询变量改名、重复文档默认不再拒绝、OCR 模式的取值变了、搜索索引会重建、预处理脚本不再收到位置参数等。升级前读完迁移指南。
- 升级前先停容器,做一次备份(导出加停机备份)。
- 官方说明镜像可以固定到一个发布系列,写成
3.3这类系列标签,只升补丁版本,不跨系列自动升级。把数字换成你当前的系列。latest永远指向最新稳定版。 - 手动更新:拉取、上线,见更新与备份容器。别放进计划自动更新。
检查结果
- 在 OMV 的 shell 里(root)运行
omv-compose-run paperless-ngx ps,broker、db、webserver都在运行。 http://<NAS 的 IP>:8000能登录。- 在 SMB 客户端往
scans放一个含中文的扫描件,几分钟内出现在 Paperless 里,搜索其中的中文词能搜到。 - 手动运行一次导出命令,
paperless/export里出现manifest.json。 - 重启 NAS,应用自己回来了。
常见问题
容器起不来,日志提到 SECRET_KEY 或者数据库连接。 先查是不是缺了 PAPERLESS_SECRET_KEY 或 PAPERLESS_DBENGINE;再看两处数据库密码是否一致。
投递目录里的文件没动静。 检查 USERMAP_UID、USERMAP_GID 对上了目录的属主,扫描仪写进来的文件是否还在被写入,再看日志。
中文识别不出来。 没安装语言包,或者没设识别语言。两个变量都要设,改完下线再上线重建容器,装语言包需要联网。
导入文档时 CPU 一直满载。 OCR 本来就耗 CPU,多语言更耗。大量导入时放在夜里做。
导入后提示重复文档。 v3 默认允许重复,只是标出来。要拒绝重复,设 PAPERLESS_CONSUMER_DELETE_DUPLICATES=true。