如果你的电脑、手机和网盘里散落着发票、合同、收据、证件扫描件,真正麻烦的通常不是存储空间,而是以后找不到。Paperless-ngx 可以把扫描文件导入 VPS,自动 OCR,识别日期、标题和联系人,再用标签、文档类型和全文搜索统一管理。
它和普通网盘的思路不一样:网盘解决“文件放在哪里”,Paperless-ngx 更像一个可搜索的数字档案柜。原始文件会保留,系统会生成归档副本和索引;你可以从消费目录、网页上传或邮件工作流导入文档。
本文使用 Paperless-ngx v3.0.5,采用官方 Docker Compose 结构:Paperless-ngx、PostgreSQL 18 和 Valkey 9。重点放在可长期运行的配置,包括中文 OCR、HTTPS、目录权限、数据库备份、升级回滚和故障排查。默认假设 VPS 由你自己管理,不把管理端口直接暴露给全网。
适合的场景:
- 家庭发票、保修单、保险单和租房合同归档;
- 个体经营者保存报销凭证、供应商账单和税务材料;
- 小团队共享项目文档,但需要按标签和权限管理;
- 从扫描仪、手机或邮件持续收集 PDF、JPEG、PNG、TIFF 文件;
- 想用 OCR 搜索扫描件里的文字,而不是手动翻文件夹。
不适合的场景:
- 只想同步照片和普通文件,完全不需要 OCR;
- 需要多人实时编辑 Office 文档;
- 需要企业级电子签章、复杂审批和合规审计;
- 没有稳定备份,却打算把唯一的原始合同放在一台 VPS 上。
Paperless-ngx 不会替代备份系统。它的媒体目录、数据库和消费目录都属于重要数据,必须和 VPS 快照、对象存储或另一台机器配合使用。
| 方案 | 主要解决的问题 | OCR 与归档 | 适合谁 |
|---|---|---|---|
| Paperless-ngx | 文档归档和检索 | 原生支持 OCR、标签和全文搜索 | 发票、合同、扫描件管理 |
| Nextcloud | 文件同步、共享和协作 | 需要额外应用和配置 | 多设备文件与团队协作 |
| 普通网盘 | 文件存储和分享 | 通常依赖平台内置搜索 | 不想自己维护服务的人 |
| Git | 文本版本管理 | 不适合扫描件和附件 | 代码、配置和纯文本 |
如果你已经在使用 Nextcloud,可以把 Paperless-ngx 作为文档归档层,而不是再建一个“万能网盘”。两者可以共存,但不要让多个程序同时写同一个媒体目录,否则很容易出现权限、重复导入和索引不一致。
本文按 2026 年 8 月核对的官方稳定版编写:
Paperless-ngx v3.0.5
PostgreSQL 18
Valkey 9
Docker Compose v2
服务关系如下:
浏览器 / 手机扫描 App
│ HTTPS
▼
反向代理(Nginx Proxy Manager)
│ http://webserver:8000
▼
Paperless-ngx Web + Celery Worker
├── PostgreSQL:用户、标签、文档索引元数据
├── Valkey:任务队列和缓存
└── data/media/consume/export:文件、索引和导入导出目录
Paperless-ngx 的 OCR 和缩略图处理是后台任务。浏览器上传成功,不代表 OCR 已经完成;需要检查任务队列和消费日志。
建议先按文档数量和 OCR 频率估算,不要只看 CPU 核数:
| 规模 | 推荐配置 | 说明 |
|---|---|---|
| 个人试用,少于 1000 份 | 2 核 2GB、40GB SSD | 适合低频上传和少量 OCR |
| 家庭档案,1000-5000 份 | 2-4 核 4GB、80GB SSD | OCR、缩略图和数据库更顺畅 |
| 小团队或高频扫描 | 4 核 8GB、160GB+ SSD | 重点看磁盘 I/O 和备份窗口 |
磁盘比内存更容易成为瓶颈。原始 PDF、归档文件、缩略图、OCR 中间文件和数据库会共同增长。不要把 20GB 磁盘当作长期档案库,先统计现有文档总量,再预留至少 30% 的升级和临时空间。
如果 VPS 只有 1GB 内存,Paperless-ngx 可能可以启动,但 OCR 和 PostgreSQL 高峰时容易触发 OOM。低内存机器可以参考 VPS 低内存 ZRAM 和 Swap 优化教程,但 Swap 只能缓解峰值,不能替代足够的内存。
先确认 Docker 与 Compose:
docker version
docker compose version
如果系统没有 Docker,可以参考 Docker 部署实战指南。创建专用目录,并把消费目录权限交给容器使用的 UID:
sudo mkdir -p /opt/paperless/data /opt/paperless/media /opt/paperless/consume
sudo mkdir -p /opt/paperless/export /opt/paperless/postgres /opt/paperless/valkey
sudo chown -R "$USER":"$USER" /opt/paperless
sudo chmod 750 /opt/paperless
cd /opt/paperless
上面的目录职责是:
- data:应用运行数据、搜索索引和任务相关文件;
- media:已经归档的原始文件、缩略图和文档附件;
- consume:待导入文件,Paperless-ngx 会自动读取并移动它们;
- export:导出归档包和恢复时使用的临时目录;
- postgres:PostgreSQL 数据库;
- valkey:队列和缓存数据。
Paperless-ngx 的 PAPERLESS_SECRET_KEY 用于会话签名和安全令牌。不要把示例值 change-me 留在生产环境,也不要把 .env 提交到公开仓库。
python3 -c 'import secrets; print(secrets.token_urlsafe(64))'
创建 /opt/paperless/.env:
PAPERLESS_SECRET_KEY=替换为上面生成的长随机字符串
PAPERLESS_URL=https://paperless.example.com
PAPERLESS_TIME_ZONE=Asia/Shanghai
PAPERLESS_OCR_LANGUAGE=chi_sim+eng
PAPERLESS_OCR_LANGUAGES=chi_sim chi_tra
USERMAP_UID=1000
USERMAP_GID=1000
POSTGRES_DB=paperless
POSTGRES_USER=paperless
POSTGRES_PASSWORD=替换为独立的数据库密码
中文 OCR 要注意两件事:PAPERLESS_OCR_LANGUAGE 指定主要识别语言,PAPERLESS_OCR_LANGUAGES 负责让容器安装额外语言包。简体中文通常使用 chi_sim,繁体中文使用 chi_tra;实际识别效果还和扫描清晰度、字体和版式有关。
如果文档基本是英文,可以改成 eng,减少镜像和运行时开销。修改 OCR 语言后,已经完成的文档不会自动全部重做 OCR,需要按批次重新处理。
限制环境文件权限:
chmod 600 /opt/paperless/.env
创建 /opt/paperless/compose.yaml:
services:
broker:
image: docker.io/valkey/valkey:9-alpine
container_name: paperless-broker
restart: unless-stopped
volumes:
- ./valkey:/data
db:
image: docker.io/library/postgres:18
container_name: paperless-db
restart: unless-stopped
volumes:
- ./postgres:/var/lib/postgresql
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:3.0.5
container_name: paperless-webserver
restart: unless-stopped
depends_on:
- db
- broker
ports:
- "127.0.0.1:8000:8000"
volumes:
- ./data:/usr/src/paperless/data
- ./media:/usr/src/paperless/media
- ./consume:/usr/src/paperless/consume
- ./export:/usr/src/paperless/export
env_file:
- .env
environment:
PAPERLESS_REDIS: redis://broker:6379
PAPERLESS_DBHOST: db
PAPERLESS_DBENGINE: postgresql
volumes: {}
官方当前 Compose 示例把 PostgreSQL 18 数据挂载到 /var/lib/postgresql,不要机械地沿用旧教程里的 /var/lib/postgresql/data。PostgreSQL 官方镜像在大版本升级时调整过数据目录布局,错误的挂载路径可能让你以为“数据已经持久化”,实际上容器重建后找不到数据库。
这里把 Paperless-ngx 只绑定到 127.0.0.1:8000。公网访问交给反向代理,数据库和 Valkey 没有映射到宿主机端口。
先检查 Compose 和环境变量:
cd /opt/paperless
docker compose config --quiet
确认没有输出后启动:
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=150 webserver
首次启动需要执行数据库迁移、创建索引和初始化任务,几分钟内看到短暂的 unhealthy 不一定代表失败。持续观察日志:
docker compose logs -f --tail=200 webserver
看到 Web 服务开始监听后,在 VPS 本机测试:
curl -I http://127.0.0.1:8000
如果返回 502,先确认容器是否还在启动;如果返回连接拒绝,再检查端口映射和容器日志,不要直接把 8000 改成公网监听。
进入 Web 容器创建管理员账号:
docker compose exec webserver python manage.py createsuperuser
按提示输入邮箱、用户名和独立密码。不要使用 VPS 的 root 密码,也不要把管理员账号写进 Compose 文件。
如果你暂时还没有域名,可以通过 SSH 隧道访问本机端口:
ssh -L 8000:127.0.0.1:8000 your_user@your_vps_ip
然后在自己的电脑打开:
http://127.0.0.1:8000
这适合首次初始化。长期使用仍建议配置域名和 HTTPS,因为扫描件、合同和登录凭据都不应该在明文 HTTP 上传输。
如果你已经有 Nginx Proxy Manager,可以新增一个 Proxy Host:
Domain Names: paperless.example.com
Forward Hostname / IP: 127.0.0.1
Forward Port: 8000
Scheme: http
Websockets Support: 开启
Block Common Exploits: 开启
申请 Let’s Encrypt 证书后启用 HTTPS,并强制 HTTP 跳转 HTTPS。部署前可以先阅读 Nginx Proxy Manager 反向代理与 HTTPS 教程。
如果反向代理运行在同一个 Docker 网络,Forward Hostname 应该使用 webserver,而不是 127.0.0.1。容器里的 127.0.0.1 指向代理容器自身,这是非常常见的 502 原因。
Paperless-ngx 的 PAPERLESS_URL 必须与公开访问的 HTTPS 地址一致:
PAPERLESS_URL=https://paperless.example.com
修改 .env 后重建 Web 容器:
docker compose up -d --force-recreate webserver
如果源站不希望暴露公网端口,也可以让 Paperless-ngx 只监听回环地址,再通过 Cloudflare Tunnel 或 VPN 提供访问。相关边界可参考 Cloudflare Tunnel 隐藏源站 IP 教程。
Paperless-ngx 常见的三种导入方式:
- 在网页中上传文件;
- 把文件复制到 consume 目录;
- 通过邮件规则或扫描程序自动投递。
先复制一个测试 PDF:
cp ~/Downloads/test-invoice.pdf /opt/paperless/consume/
查看消费日志:
docker compose logs -f --tail=200 webserver | grep -Ei 'consumer|ocr|document'
处理完成后,原始文件会进入媒体存储,消费目录里的文件通常会被移动或删除。不要把 consume 当作长期备份目录,也不要直接手动修改 media 下的文件名。
如果消费目录一直没有处理,依次检查:
ls -la /opt/paperless/consume
stat /opt/paperless/consume/test-invoice.pdf
docker compose exec webserver id
docker compose exec webserver ls -la /usr/src/paperless/consume
宿主机目录的 UID/GID 必须允许容器读取和移动文件。env 中的 USERMAP_UID、USERMAP_GID 应与宿主机实际用户一致,可以用下面命令确认:
id -u
id -g
修改 UID/GID 后重建服务:
docker compose up -d --force-recreate webserver
Paperless-ngx 的元数据决定了以后能不能快速找到文件。建议先建立少量稳定分类:
- 文档类型:发票、合同、保单、收据、证件、说明书;
- 联系人:银行、运营商、房东、供应商、客户;
- 标签:待报销、已付款、待续期、重要、家庭、工作;
- 自定义字段:金额、合同到期日、订单号或资产编号。
不要为每一张文件创建一个新标签。标签应该表达可复用的筛选条件,文档类型和联系人则负责描述来源与用途。
可以在管理界面配置匹配规则,让文件名或 OCR 文本自动填入元数据。例如文件名包含“电费”,自动设置文档类型为“账单”;来自某个邮箱地址的附件,自动设置联系人和标签。
规则上线前先用 5-10 份测试文件验证。自动规则一旦过于宽泛,可能把合同误归类,之后还要逐份修正。
上传扫描 PDF 后,Paperless-ngx 会在后台执行 OCR。OCR 失败的原因通常不是 Paperless-ngx 本身,而是:
- 扫描分辨率太低或图片严重倾斜;
- 容器缺少对应语言包;
- OCR 任务排队,尚未处理完成;
- 文件是加密 PDF 或损坏 PDF;
- 内存不足,worker 被系统杀掉。
查看最近任务:
docker compose logs --tail=300 webserver | grep -Ei 'ocr|tesseract|celery|task|error'
docker stats --no-stream
中文和中英混排文档建议使用 chi_sim+eng,繁体文档按需要加入 chi_tra。如果搜索结果仍然不完整,可以先下载一份原始文件确认是否真的包含可识别文本,再判断是扫描质量还是语言配置问题。
Paperless-ngx 的全文搜索依赖索引。刚导入的文件可能需要等待后台任务,不能上传后立刻以“搜不到”为理由重复导入。先查看任务状态和日志,再等待索引完成。
你可以给 Paperless-ngx 配置专用收件地址,让账单附件自动进入消费流程。但邮件自动化会扩大攻击面:陌生发件人可能发送超大附件、恶意文件或大量垃圾邮件。
建议的安全边界:
- 使用独立邮箱,不要把个人主邮箱密码写进容器;
- 只允许可信发件人,或先转发到人工审核邮箱;
- 限制附件大小和允许的文件类型;
- 给消费目录和邮件任务设置磁盘监控;
- 自动规则上线前保留人工复核步骤。
如果只是偶尔归档文件,网页上传或手动复制到 consume 更容易排查,也不需要额外维护邮件连接。
Paperless-ngx 至少有三类必须保护的数据:
- media:原始文档、归档 PDF、缩略图和附件;
- postgres:用户、标签、规则、权限和文档元数据;
- data:搜索索引、任务状态和应用运行数据。
consume 和 export 也应该纳入备份范围,尤其是消费目录里尚未处理的文件。Valkey 主要是队列和缓存,通常不承担长期事实数据,但备份它可以减少恢复后的任务丢失。
先停止 Web 服务和 worker,再执行数据库转储:
cd /opt/paperless
docker compose stop webserver
mkdir -p export/backup-$(date +%F)
docker compose exec -T db pg_dump -U paperless paperless > export/backup-$(date +%F)/paperless.sql
tar -czf export/backup-$(date +%F)/paperless-files.tar.gz data media consume .env compose.yaml
docker compose start webserver
上面的命令会把敏感环境文件和文档打包在一起,必须限制权限:
chmod 600 export/backup-*/paperless.sql
chmod 600 export/backup-*/paperless-files.tar.gz
把备份复制到另一台机器或对象存储,不能只留在同一个 VPS。备份策略可以参考 VPS restic、rclone 和数据库恢复演练。
恢复不是把 tar 包解开就结束。建议在临时目录或备用 VPS 做一次演练:
docker compose down
tar -xzf paperless-files.tar.gz -C /opt/paperless
cat paperless.sql | docker compose exec -T db psql -U paperless paperless
docker compose up -d
docker compose logs --tail=200 webserver
实际恢复前先确认数据库为空或使用专用测试实例,避免把旧数据和新数据混在一起。恢复后随机打开几份文档,检查搜索、标签、权限和 OCR 附件,而不是只检查首页能否登录。
生产环境不要长期使用 latest。先在 Compose 中固定版本,例如:
webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:3.0.5
broker:
image: docker.io/valkey/valkey:9-alpine
db:
image: docker.io/library/postgres:18
升级前执行:
cd /opt/paperless
docker compose config > export/compose.before-upgrade.yaml
docker compose exec -T db pg_dump -U paperless paperless > export/paperless-before-upgrade.sql
docker compose pull
确认镜像下载完成后再重建:
docker compose up -d
docker compose ps
docker compose logs --tail=300 webserver
升级后至少检查:
- 管理员登录和 HTTPS 跳转;
- 新文件能否导入和完成 OCR;
- 中文全文搜索是否返回结果;
- 标签、规则和权限是否保留;
- 数据库磁盘占用是否异常增长。
Paperless-ngx v3 有迁移注意事项,跨大版本前要阅读官方 migration 文档。不要只回退应用镜像而不恢复数据库;应用代码和数据库结构必须保持兼容。
先绕过反向代理:
curl -I http://127.0.0.1:8000
docker compose ps
docker compose logs --tail=200 webserver
如果本机 8000 正常,检查 Nginx Proxy Manager 的目标地址。代理容器和 Paperless-ngx 不在同一网络时,127.0.0.1 通常指向错误的容器。
检查目录挂载、UID/GID 和 worker 日志:
docker compose exec webserver ls -la /usr/src/paperless/consume
docker compose exec webserver id
docker compose logs --tail=300 webserver | grep -Ei 'consumer|permission|error'
如果容器能看到文件但不能移动,修正宿主机目录权限;如果容器根本看不到文件,检查 Compose 的相对路径和当前工作目录。
确认环境变量和语言包:
docker compose exec webserver env | grep PAPERLESS_OCR
docker compose exec webserver tesseract --list-langs
如果没有 chi_sim,重新拉取或重建镜像,并确认 PAPERLESS_OCR_LANGUAGES 使用的是 Tesseract 语言代码。已经归档的文件可能需要重新触发 OCR,不会因为修改环境变量而自动全部重建索引。
先看任务日志,确认 OCR 和索引任务已完成。对于本来就有文字层的 PDF,可以下载原文件确认文本是否存在;对于扫描件,必须等待 OCR。
如果只有部分文档搜索不到,检查是否使用了错误的语言包、文档是否加密,以及数据库和 data 索引目录是否有权限写入。
Compose 内部连接使用服务名 db,不是 localhost:
docker compose ps db
docker compose logs --tail=200 db
docker compose exec webserver env | grep PAPERLESS_DB
确认 POSTGRES_DB、POSTGRES_USER、POSTGRES_PASSWORD 在 .env 和数据库初始化时一致。已经初始化过的 PostgreSQL 不会因为你修改环境变量就自动修改现有用户密码。
检查 Docker、媒体目录、数据库和日志:
df -h
du -sh /opt/paperless/*
docker system df
不要直接删除 media 或 postgres 下的文件。先确认是否存在重复导入、过多缩略图、失败任务和无期限日志,再通过 Paperless-ngx 的导出、清理和保留策略处理。
- .env 使用独立随机密钥,权限设为 600;
- Paperless-ngx 只监听回环地址或私网,不直接暴露 8000;
- 反向代理启用 HTTPS、强密码和常见攻击拦截;
- PostgreSQL、Valkey 不映射到公网端口;
- 消费目录不对所有系统用户开放写权限;
- 邮件导入只接受可信来源并限制附件大小;
- 备份至少保留一份异地副本,并定期恢复演练;
- 升级前固定版本、导出数据库并保留回滚镜像;
- 不把合同、证件等文件提交到公开 Git 仓库;
- 团队使用时按角色授予最小权限;
- 监控磁盘、数据库、OCR 队列和容器重启次数。
不能完全替代。它专注于文档归档和检索,不是实时协作、照片同步或大文件分享平台。可以让它负责结构化文档,把其他文件交给网盘或对象存储。
导入流程会把消费目录里的文件移动到媒体存储,并生成归档版本。原始文件仍属于媒体数据的一部分,不能把消费目录当作备份;首次部署时应先用副本测试流程。
不一定。扫描清晰度、字体、表格布局、印章和倾斜都会影响结果。OCR 适合提升检索效率,不应直接当作合同金额和身份证信息的唯一来源。
本文按官方当前 Compose 示例使用 PostgreSQL 18。新部署建议保持示例一致;已有旧实例升级时要先阅读数据库大版本迁移说明,不要直接更换镜像标签。
个人用户可以从 2 核 2GB、80GB SSD、Paperless-ngx v3.0.5 和中文 OCR 开始。先导入十份测试文件,确认归档规则、全文搜索、HTTPS 和备份恢复都正常,再批量迁移历史资料。
Paperless-ngx 的价值不在于把文件“放到 VPS”,而在于让多年积累的文档能够按内容被找回。只要把媒体、数据库、索引和密钥一起备份,并把消费目录权限和升级流程固定下来,它就能成为一套稳定的个人数字档案系统。
