首页
/ Paperless-ngx 实践指南:用 Docker 部署自托管数字文档管理系统

Paperless-ngx 实践指南:用 Docker 部署自托管数字文档管理系统

2026-09-05 13:26:32作者:柯茵沙

Paperless-ngx 是一个社区驱动的开源文档管理系统,把纸质文档变成可搜索的在线档案:扫描、OCR 识别、自动归档、全文检索一站式完成。本文以仓库 README 为主体,结合 安装脚本Docker Compose 模板Dockerfile 与 s6-overlay 服务定义,系统讲解它的核心功能、容器化部署架构、一键安装脚本的完整行为以及关键配置项,帮助你从零搭建并理解一个可用的自托管文档档案系统。

Paperless-ngx 文档列表界面截图

一、项目定位:Paperless 系列的官方继任者

README 的核心定位描述是:

Paperless-ngx is a document management system that transforms your physical documents into a searchable online archive so you can keep, well, less paper.

从源码与文档结构看,它是原 Paperless 与 Paperless-ng 两个项目的官方继任者,目标是把推进与支持项目的责任分散到一支多人团队(frontend、ci/cd 等多个 team)中协作完成,而非依赖单一维护者。仓库 docs/index.md 还记录了两个前身项目向 Paperless-ngx 过渡的背景讨论。

项目以自托管为设计前提:数据保存在你自己的服务器上,不对外传输。这一点直接引出了 README 末尾最重要的安全声明,部署前必须理解(见第六节)。

二、核心功能全景

README 将完整功能列表指向官方文档,而 docs/index.md 给出了详细清单。结合仓库实现,核心能力可归纳为以下几类:

1. 摄取与 OCR

  • 对文档执行 OCR,即使扫描件只有纯图像也能生成可搜索、可选择的文本,底层使用开源 Tesseract 引擎,支持 100 多种语言;
  • 支持 PDF、图像、纯文本文件,以及(可选,依赖 Apache Tika)Office 文档(Word、Excel、PowerPoint 与 LibreOffice 对应格式);
  • 支持远程 OCR(Azure AI,可选开启);
  • 文档以 PDF/A 格式保存(面向长期存档的标准),同时保留未修改的原始文件;
  • 多核心优化:可并行消费多份文档。

2. 组织与检索

  • 用标签(tags)、来源(correspondents)、类型(types)等对象组织并索引文档;
  • 机器学习自动为文档添加标签、来源和类型(对应 src/documents/classifier.py);
  • 全文搜索支持自动补全、按相关性排序、命中高亮,以及"类似文档"(More like this)检索;
  • 一个文档条目下可保存多个版本的源文件并共享一套元数据(对应迁移文件 0012_document_root_document.py 引入的 root document 概念)。

3. Web 应用特性

  • 可自定义的统计仪表盘;
  • 按标签/来源/类型等多维过滤;
  • 批量编辑(bulk edit)标签、来源、类型等;
  • 全站拖拽上传;
  • 可保存的自定义视图(可展示在仪表盘和侧边栏);
  • 多种数据类型的自定义字段(custom fields);
  • 带可选过期时间的公开分享链接。

4. 邮件与流程

  • 邮件摄取:可配置多个邮件账户及各自的规则,处理后可执行标记已读、删除等动作(实现见 src/paperless_mail/);
  • 工作流系统(workflows):对文档管道做更精细的控制并触发动作(实现见 src/documents/workflows/)。

5. 权限与健康检查

  • 内置多用户权限系统,同时支持"全局"权限与按文档/对象粒度设置;
  • 内置 sanity checker(完整性检查器)确保档案库处于健康状态(实现见 src/documents/sanity_checker.py)。

6. 可选 AI 能力

README 特别标注的新特性:Paperless-ngx 可选地利用大语言模型(LLM)做文档建议、与文档对话、相似文档检索,这些能力默认关闭、按需开启(实现集中在 src/paperless_ai/ 模块)。

三、部署架构:Docker Compose 与容器内部服务

README 明确:最容易的部署方式是 docker compose/docker/compose 目录下的文件被配置为从 GitHub 容器镜像仓库拉取镜像。该目录提供了按数据库后端与是否启用 Tika 区分的模板:

  • docker-compose.sqlite.yml / docker-compose.sqlite-tika.yml
  • docker-compose.postgres.yml / docker-compose.postgres-tika.yml
  • docker-compose.mariadb.yml / docker-compose.mariadb-tika.yml
  • 以及 Portainer 专用变体 docker-compose.portainer.yml

docker-compose.postgres.yml 为例,其服务编排如下:

services:
  broker:
    image: docker.io/valkey/valkey:9-alpine   # 任务队列的消息代理
    restart: unless-stopped
    volumes:
      - redisdata:/data
  db:
    image: docker.io/library/postgres:18      # 数据库(SQLite 变体中不存在此服务)
    restart: unless-stopped
    volumes:
      - pgdata:/var/lib/postgresql
    environment:
      POSTGRES_DB: paperless
      POSTGRES_USER: paperless
      POSTGRES_PASSWORD: paperless
  webserver:
    image: ghcr.io/paperless-ngx/paperless-ngx:latest
    restart: unless-stopped
    depends_on:
      - db
      - broker
    ports:
      - "8000:8000"        # 容器内固定 8000,宿主机端口可按需修改
    volumes:
      - data:/usr/src/paperless/data      # 搜索索引等数据
      - media:/usr/src/paperless/media    # 文档源文件
      - ./export:/usr/src/paperless/export
      - ./consume:/usr/src/paperless/consume  # 待摄取目录
    env_file: docker-compose.env
    environment:
      PAPERLESS_REDIS: redis://broker:6379
      PAPERLESS_DBHOST: db
      PAPERLESS_DBENGINE: postgresql
volumes:
  data:
  media:
  pgdata:
  redisdata:

从文件头部注释可以看到该模板的共同约定:容器配置为系统启动时自恢复(restart: unless-stopped);数据卷由 Docker 管理;consume/export 目录与 compose 文件同目录创建;Web 服务监听 8000 端口。官方建议新安装优先使用 PostgreSQL 后端;SQLite 更适合树莓派等资源受限设备。

容器内部:s6-overlay 多进程编排

Paperless-ngx 不是单进程应用。从 Dockerfile 可以看到镜像构建分多个阶段:前端(Angular,源码在 src-ui/)用 Node 24 + pnpm 编译;运行时基于 uv + Python 3.14,并安装 s6-overlay 作为进程监管器(注意:文章外部链接仅为说明,镜像内已固化 s6-overlay 3.2.2.0)。

真正揭示容器内运行哪些进程的,是 docker/rootfs/etc/s6-overlay/s6-rc.d/ 下的服务定义,包括:

服务 作用(从命名与项目结构推断)
svc-webserver Django Web 服务,对外提供 API 与界面
svc-consumer 文档摄取器,监听 consume 目录并处理新文档(实现见 src/documents/consumer.py
svc-worker Celery 任务 worker,执行后台任务(见 src/documents/tasks.py
svc-scheduler 定时任务调度(邮件轮询等周期性工作)
svc-flower Celery 任务队列监控面板(可选)

启动阶段还有一串 init-* 链式任务,构成容器启动流水线:init-env-file(加载环境变量)→ init-foldersinit-modify-user(按 USERMAP 调整用户)→ init-tesseract-langs(安装 OCR 语言包)→ init-wait-for-db / init-wait-for-redis(等待依赖)→ init-migrations(数据库迁移)→ init-search-indexinit-llmindex-migrateinit-superuserinit-start。仓库中的 init-flow.drawio.png 正是这张初始化流程图的源文件。这套机制解释了为什么 docker compose up -d 之后无需任何手工步骤,系统即可完成迁移、建索引并进入就绪状态。

四、一键安装脚本:install-paperless-ngx.sh 全流程解析

README 给出的快速开始命令是:

bash -c "$(curl -L https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)"

官方文档(docs/setup.md)特别提醒:如果直接 curl 管道执行让你不安,可以先审查 install-paperless-ngx.sh 源码。下面基于脚本源码逐段说明它的实际行为。

1. 前置检查

脚本依次检查:

  • 不能以 root 运行(id -u == 0 时直接退出);
  • 必须安装 wgetdocker,且 docker compose 插件可用;
  • docker stats --no-stream 试探当前用户是否有 Docker 权限,无权限时打印 sudo usermod -aG docker $USER 提示;
  • 时区探测:优先 timedatectl,回退到 busybox 系(如 QNAP)的 /etc/TZ + /etc/tzlist 解析,最后兜底 Etc/UTC

2. 交互式配置问题

脚本依次询问以下参数(括号内为默认值):

问题 默认值 说明
URL 对外访问地址,仅公网暴露时必填,如 https://paperless.example.com
Port 8000 Web 服务宿主机端口
Current time zone 系统时区 必须配置正确,否则文档日期可能偏差一天
Database backend postgres 可选 postgres / sqlite / mariadb
Enable Apache Tika? no 启用后支持 Office/LibreOffice 文档,但资源占用更高
OCR language eng ISO 639-2(T) 语言码,可用 + 组合多语言,如 deu+eng
User ID / Group ID 当前用户 容器运行身份,容器还会据此调整 data、media、consume 目录属主
Target folder $(pwd)/paperless-ngx 存放配置文件的目录,安装后仍需长期保留
Consume folder $TARGET_FOLDER/consume 扫描器投放新文档的目录,必须为 /./ 开头的路径
Media folder 文档存储位置,留空则由 Docker 卷管理
Data folder 搜索索引等数据位置(SQLite 模式下含数据库文件),留空由 Docker 管理
Database folder 仅 postgres/mariadb 时询问,留空由 Docker 管理
Username / Password / Email 用户名默认当前系统用户 初始登录凭据,邮件地址不会被实际使用

所有答案会先以 Summary 汇总展示,按任意键确认后才真正安装。

3. 文件生成与改造逻辑

确认之后,脚本的核心操作是:

  1. 数据库后端[-tika] 规则选取模板,下载对应的 docker-compose.<版本>.yml 重命名为 docker-compose.yml,并下载 .env 文件;
  2. 生成 64 字节随机 SECRET_KEYtr -dc ... < /dev/urandom | dd bs=1 count=64)写入 docker-compose.env
  3. OCR 语言码转换:OCR_LANG(环境变量)使用下划线(- 全部替换为 _);而需要额外安装语言包时则转换为空格分隔的列表(_-+ → 空格),只有当所选语言不在内置语言 deu eng fra ita spa 中时才写入 PAPERLESS_OCR_LANGUAGES
  4. seddocker-compose.yml 中的 8000:8000 端口、consume 挂载路径替换为用户所选值;若指定了 media/data/database 目录,则将对应的具名卷(media:data:pgdata:/dbdata:)替换为 bind mount 并删除卷声明;
  5. docker compose pull 拉取镜像;
  6. postgres/mariadb 后端特殊处理:先单独 docker compose up --detach db 启动数据库、sleep 15 等待初始化完成,再 docker compose stop,避免 webserver 与数据库初始化竞态;
  7. 通过 docker compose run --rm -e DJANGO_SUPERUSER_PASSWORD="$PASSWORD" webserver createsuperuser --noinput --username "$USERNAME" --email "$EMAIL" 创建超级用户;
  8. 最终 docker compose up --detach 启动整套服务。

这一步解释了 README 中"配置一个 docker compose 环境"的实质:脚本只是把第五节的手动 compose 安装自动化了。

五、关键配置参数:docker-compose.env

docker-compose.env 是安装后最常改动的文件,其中预置了最常用的注释示例:

# 容器内运行 paperless 的用户 UID/GID。应设置为主机上你的
# UID/GID,使消费目录具备写权限。
#USERMAP_UID=1000
#USERMAP_GID=1000

# 暴露到公网域名时必填(同时建议加反向代理等安全措施)
#PAPERLESS_URL=https://paperless.example.com

# 必填。会话令牌与签名用的唯一密钥。
# 生成方式:python3 -c "import secrets; print(secrets.token_urlsafe(64))"
PAPERLESS_SECRET_KEY=change-me

# 容器时区,默认 UTC
#PAPERLESS_TIME_ZONE=America/Los_Angeles

# OCR 默认语言(ISO 639-2)
#PAPERLESS_OCR_LANGUAGE=eng

# 额外安装的语言包(空格分隔),区别于上面"使用"的语言;
# 容器默认已内置英语、德语、意大利语、西班牙语、法语
#PAPERLESS_OCR_LANGUAGES=tur ces

需要注意的取值细节(与安装脚本行为相互印证):

  • PAPERLESS_SECRET_KEY:模板中是占位值 change-me,安装脚本会生成随机 64 字节字符串覆盖;这是会话签名的基础,必须唯一且保密;
  • PAPERLESS_TIME_ZONE:脚本注释明确警告时区错误会导致"文档日期偏差一天",这与消费/归档按日期组织文件的逻辑直接相关;
  • USERMAP_UID / USERMAP_GID:与宿主机用户一致后,consume 目录写入权限问题即可避免;多数系统首个普通用户即为 1000,开箱可用。脚本仅在非 1000 时才写入该变量;
  • PAPERLESS_OCR_LANGUAGEPAPERLESS_OCR_LANGUAGES 的区别:前者是"OCR 时识别成什么语言",后者是"额外往容器里装哪些语言包"。默认已装 deu eng fra ita spa
  • Docker secretsdocs/setup.md 提到任何配置项都可加 _FILE 后缀改用文件注入,例如 PAPERLESS_DBUSER_FILE=/var/run/secrets/password.txt
  • 完整的可配置项清单见 docs/configuration.md

手动 Docker Compose 安装的等价步骤

不走脚本时,README 与 docs/setup.md 给出的标准流程是:

  1. /docker/compose 下载对应后端的 docker-compose.*.yml 保存为 docker-compose.yml,同时下载 docker-compose.env.env 到同一目录(需要 Office 文档支持就选带 -tika 的文件);
  2. 按需修改 compose 文件:把 - ./consume:/usr/src/paperless/consume 冒号前的路径改为本地目录,把端口改为 - 8010:8000 之类;
  3. docs/configuration.md 修改 docker-compose.env(含 USERMAP_UID/USERMAP_GID,用 id -uid -g 查询);
  4. docker compose pull(默认从 GitHub 容器仓库拉取,也可把 image 行改为 Docker Hub 镜像);
  5. docker compose up -d
  6. 访问 http://127.0.0.1:8000,首次进入时按提示创建超级用户(脚本路径则已代为创建)。

文档还给出两个高级场景:rootless 容器(在 compose 中显式设置 user: '1000:1000',且不能与 USERMAP_* 混用,指定额外 OCR 语言时不可 rootless);以及 NFS 等不支持 inotify 的文件系统上需改用轮询式消费间隔(PAPERLESS_CONSUMER_POLLING_INTERVAL)。

六、从 Paperless-ng 迁移与安全须知

迁移:README 说明从 Paperless-ng 迁移"很容易,直接换用新 Docker 镜像即可",具体步骤在 docs/setup.md 的迁移章节,v3 版本的数据迁移细节另有 docs/migration-v3.md

安全声明(README "Important Note",部署决策必读)

文档扫描仪通常用于扫描敏感文档(社保号、税务记录、发票等)。Paperless-ngx 绝不应运行在不可信的主机上,因为信息以明文(无加密)存储。不对其安全性作任何保证。 运行 Paperless-ngx 最安全的方式是在你自己家里的本地服务器上运行,并做好备份。

这一声明与源码结构一致:文档以原始文件 + PDF/A 双份形式平铺在 media 目录(见 src/documents/file_handling.py 与 compose 中的 media: 卷),权限系统(src/documents/permissions.py)解决的是"谁能看哪些文档",而非静态加密。因此对外暴露时,README 与文档都建议配合反向代理及相应安全措施(如设置 PAPERLESS_URL、强 PAPERLESS_SECRET_KEY),并自行规划 media/data 目录的备份策略。

七、社区参与与相关资源

README 的贡献指引(对应 CONTRIBUTING.mddocs/development.md):

  • 社区支持:有意长期参与者在 GitHub 和 Matrix 房间(#paperless:matrix.org)联系即可,项目按 frontend、ci/cd 等 team 划分职责,欢迎持续贡献者加入;
  • 翻译:界面翻译在 Crowdin 上协调,仓库中 src/locale/ 覆盖 50+ 语言目录,前端对应 src-ui/src/locale/ 下的 messages 文件;
  • 功能请求:通过 GitHub Discussions 的 feature-requests 分类提交、搜索和投票;
  • Bug 报告:直接开 issue 或发起讨论;
  • 相关项目:用户维护的兼容软件与相关项目清单见项目 wiki(Related Projects)。

小结

README 为主线,Paperless-ngx 的技术画像可以概括为:以 Docker Compose 为交付形态(webserver/consumer/worker/scheduler 由 s6-overlay 在单镜像内编排,PostgreSQL/SQLite/MariaDB 三后端可选,Tika 可选扩展),消费目录驱动摄取、Tesseract 驱动 OCR、PDF/A 保证长期存档,并以权限、工作流、邮件、版本化和可选 LLM 能力构成完整的文档生命周期管理。部署路径按投入排序是:安装脚本(最低成本)→ 手动 compose 模板 → 裸机部署(见 docs/setup.md),三者最终落地的是同一套环境变量契约(docker-compose.envdocs/configuration.md)。理解这套契约与容器内 s6 初始化链,是排障和深度定制的基础。

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