Paperless-ngx 实践指南:用 Docker 部署自托管数字文档管理系统
Paperless-ngx 是一个社区驱动的开源文档管理系统,把纸质文档变成可搜索的在线档案:扫描、OCR 识别、自动归档、全文检索一站式完成。本文以仓库 README 为主体,结合 安装脚本、Docker Compose 模板、Dockerfile 与 s6-overlay 服务定义,系统讲解它的核心功能、容器化部署架构、一键安装脚本的完整行为以及关键配置项,帮助你从零搭建并理解一个可用的自托管文档档案系统。
一、项目定位: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.ymldocker-compose.postgres.yml/docker-compose.postgres-tika.ymldocker-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-folders → init-modify-user(按 USERMAP 调整用户)→ init-tesseract-langs(安装 OCR 语言包)→ init-wait-for-db / init-wait-for-redis(等待依赖)→ init-migrations(数据库迁移)→ init-search-index → init-llmindex-migrate → init-superuser → init-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时直接退出); - 必须安装
wget、docker,且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. 文件生成与改造逻辑
确认之后,脚本的核心操作是:
- 按
数据库后端[-tika]规则选取模板,下载对应的docker-compose.<版本>.yml重命名为docker-compose.yml,并下载.env文件; - 生成 64 字节随机
SECRET_KEY(tr -dc ... < /dev/urandom | dd bs=1 count=64)写入docker-compose.env; - OCR 语言码转换:
OCR_LANG(环境变量)使用下划线(-全部替换为_);而需要额外安装语言包时则转换为空格分隔的列表(_→-,+→ 空格),只有当所选语言不在内置语言deu eng fra ita spa中时才写入PAPERLESS_OCR_LANGUAGES; - 用
sed把docker-compose.yml中的8000:8000端口、consume 挂载路径替换为用户所选值;若指定了 media/data/database 目录,则将对应的具名卷(media:、data:、pgdata:/dbdata:)替换为 bind mount 并删除卷声明; docker compose pull拉取镜像;- postgres/mariadb 后端特殊处理:先单独
docker compose up --detach db启动数据库、sleep 15等待初始化完成,再docker compose stop,避免 webserver 与数据库初始化竞态; - 通过
docker compose run --rm -e DJANGO_SUPERUSER_PASSWORD="$PASSWORD" webserver createsuperuser --noinput --username "$USERNAME" --email "$EMAIL"创建超级用户; - 最终
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_LANGUAGE与PAPERLESS_OCR_LANGUAGES的区别:前者是"OCR 时识别成什么语言",后者是"额外往容器里装哪些语言包"。默认已装deu eng fra ita spa;- Docker secrets:docs/setup.md 提到任何配置项都可加
_FILE后缀改用文件注入,例如PAPERLESS_DBUSER_FILE=/var/run/secrets/password.txt; - 完整的可配置项清单见 docs/configuration.md。
手动 Docker Compose 安装的等价步骤
不走脚本时,README 与 docs/setup.md 给出的标准流程是:
- 从 /docker/compose 下载对应后端的
docker-compose.*.yml保存为docker-compose.yml,同时下载docker-compose.env和.env到同一目录(需要 Office 文档支持就选带-tika的文件); - 按需修改 compose 文件:把
- ./consume:/usr/src/paperless/consume冒号前的路径改为本地目录,把端口改为- 8010:8000之类; - 按 docs/configuration.md 修改
docker-compose.env(含USERMAP_UID/USERMAP_GID,用id -u、id -g查询); docker compose pull(默认从 GitHub 容器仓库拉取,也可把 image 行改为 Docker Hub 镜像);docker compose up -d;- 访问
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.md 与 docs/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.env 与 docs/configuration.md)。理解这套契约与容器内 s6 初始化链,是排障和深度定制的基础。
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 StartedRust0623
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
