Docker 环境下 Paperless-ngx 中文增强版部署实战
本文基于本人真实生产环境反复踩坑与验证,整理出一套可以直接部署、稳定运行、完整支持 Word(doc/docx)+ 中文 OCR(宋体 / 楷体等)的 Paperless-ngx Docker Compose 方案。
如果你遇到过以下问题:
- Word(docx)上传直接报不支持文件类型
- 中文 OCR 提示
chi_sim is not installed Error while converting document to PDF: Connection refused- Docker 网络、权限、用户映射导致容器反复自杀
那么这篇文章就是为你写的。
一、整体架构设计说明
本方案并不是简单拉一个 paperless-ngx 官方镜像,而是构建了一个完整、稳定、可维护的文档处理流水线:
┌──────────────┐ │ Browser │ └──────┬───────┘ │ ┌──────▼───────────┐ │ paperless-ngx │ │ (主服务) │ └───┬─────────┬────┘ │ │ ┌───▼───┐ ┌───▼──────┐ │ Redis │ │PostgreSQL│ └───────┘ └──────────┘ │ ┌───▼────────────┐ │ Apache Tika │ → 文档解析(doc/docx) └───┬────────────┘ │ ┌───▼────────────┐ │ Gotenberg │ → Word → PDF(LibreOffice) └────────────────┘为什么一定要Tika + Gotenberg?
这是Paperless 官方推荐、也是线上环境唯一稳定方案。
- Tika:识别 Word / Excel / 文本内容
- Gotenberg:负责 LibreOffice 转 PDF
- Paperless 本体只做编排与 OCR
少任何一个,Word 支持都会不完整。
二、核心问题与解决思路(重点)
1️⃣ Word(docx)无法上传的根因
并不是:
- 文件类型没加
- LibreOffice 没装
而是:
❌Word → PDF 转换服务不可达(网络 / 依赖服务未就绪)
最终表现为:
Error while converting document to PDF: [Errno 111] Connection refused2️⃣ 中文 OCR 报错的真正原因
The selected ocr language chi_sim is not installed不是 Paperless 配置问题,而是:
❌ 官方镜像默认不包含中文 OCR 语言包
所以必须自定义 Dockerfile。
三、自定义 Dockerfile(中文 OCR 核心)
FROM ghcr.io/paperless-ngx/paperless-ngx:latest USER root # 安装中文 OCR 语言包 RUN apt-get update && \ apt-get install -y --no-install-recommends \ tesseract-ocr-chi-sim \ tesseract-ocr-chi-tra && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* USER paperless说明:
chi_sim:简体中文(宋体、黑体等)chi_tra:繁体中文- 不切回
paperless用户,容器会直接启动失败
四、docker-compose.yml 完整方案解析
1️⃣ 数据库 & Redis
- PostgreSQL 15(稳定、性能好)
- Redis 7(任务队列)
- 全部启用 healthcheck,避免 Paperless 抢跑
2️⃣ Paperless-ngx 主服务(关键点)
depends_on:db:condition:service_healthybroker:condition:service_healthygotenberg:condition:service_healthytika:condition:service_healthy这是解决
Connection refused的核心配置。
Paperless 一定要在:
- Tika
- Gotenberg
- Redis
- PostgreSQL
全部健康之后再启动。
在这里插入代码片3️⃣ Word / OCR 相关核心环境变量
PAPERLESS_TIKA_ENABLED:"1"PAPERLESS_TIKA_ENDPOINT:http://tika:9998PAPERLESS_TIKA_GOTENBERG_ENDPOINT:http://gotenberg:3000PAPERLESS_OCR_LANGUAGE:chi_sim+engPAPERLESS_OCR_MODE:skip含义说明:
skip:已有文本层不重复 OCR(效率 + 质量)- 中文 Word → PDF → OCR完整链路
4️⃣ UID / GID(踩坑最多的一点)
PAPERLESS_UID:1000PAPERLESS_GID:1000⚠️千万不要用 root(0:0)
否则你会看到:
usermod: user paperless is currently used by process 1 fatal: stopping the container5️⃣ 完成文件
services:# ===== Redis 消息队列服务 =====broker:image:redis:7# 使用 Redis 7 版本作为消息代理container_name:paperless-redis# 容器名称restart:unless-stopped# 容器退出时自动重启(除非手动停止)command:redis-server--maxmemory 512mb--maxmemory-policy allkeys-lru# 限制内存512MB,LRU淘汰策略networks:-paperless-network# 连接到自定义网络healthcheck:# 健康检查配置test:["CMD","redis-cli","ping"]# 使用 redis-cli ping 命令检查服务状态interval:30s# 每30秒检查一次timeout:3s# 超时时间3秒retries:3# 失败3次后标记为不健康start_period:10s# 容器启动后10秒开始健康检查# ===== PostgreSQL 数据库服务 =====db:image:postgres:15# 使用 PostgreSQL 15 版本container_name:paperless-db# 容器名称restart:unless-stopped# 容器退出时自动重启(除非手动停止)environment:POSTGRES_DB:paperless# 数据库名称POSTGRES_USER:paperless# 数据库用户名POSTGRES_PASSWORD:paperless# 数据库密码volumes:-./data/postgres:/var/lib/postgresql/data# 数据库数据持久化目录映射networks:-paperless-network# 连接到自定义网络healthcheck:# 健康检查配置test:["CMD-SHELL","pg_isready -U paperless -d paperless"]# 检查数据库是否就绪interval:30s# 每30秒检查一次timeout:5s# 超时时间5秒retries:3# 失败3次后标记为不健康start_period:30s# 容器启动后30秒开始健康检查(数据库启动较慢)# ===== Paperless-ngx 主服务 =====webserver:# image: ghcr.io/paperless-ngx/paperless-ngx:latest # 官方镜像(已注释)build:context:.# 构建上下文为当前目录dockerfile:Dockerfile# 使用自定义 Dockerfile 构建image:paperless-ngx-zh:latest# 自定义镜像名称(支持中文)container_name:paperless-web# 容器名称restart:unless-stopped# 容器退出时自动重启(除非手动停止)depends_on:# 依赖服务,这些服务会优先启动db:condition:service_healthy# 等待数据库健康检查通过broker:condition:service_healthy# 等待 Redis 健康检查通过gotenberg:condition:service_healthy# 等待 Gotenberg 健康检查通过tika:condition:service_healthy# 等待 Tika 健康检查通过ports:-"8000:8000"# 端口映射:宿主机8000端口 -> 容器8000端口environment:# ----- 数据库连接配置 -----PAPERLESS_REDIS:redis://broker:6379# Redis 连接地址PAPERLESS_DBENGINE:postgresql# 数据库引擎类型PAPERLESS_DBHOST:db# 数据库主机地址(容器名)PAPERLESS_DBNAME:paperless# 数据库名称PAPERLESS_DBUSER:paperless# 数据库用户名PAPERLESS_DBPASS:paperless# 数据库密码# ===== 文档处理核心配置 =====PAPERLESS_TIKA_ENABLED:"1"# 启用 Tika 文档解析服务(支持更多文档格式)PAPERLESS_TIKA_GOTENBERG_ENDPOINT:http://gotenberg:3000# Gotenberg PDF 转换服务地址PAPERLESS_TIKA_ENDPOINT:http://tika:9998# Tika 文档解析服务地址# ----- OCR 光学字符识别配置 -----# OCR(中文建议开启)PAPERLESS_OCR_LANGUAGE:chi_sim+eng# OCR 识别语言:简体中文+英文PAPERLESS_OCR_MODE:skip# OCR 模式:跳过已有文本层的文档(避免重复识别)# ----- 系统性能与安全配置 -----# 安全 & 性能PAPERLESS_TASK_WORKERS:2# 任务处理工作进程数量PAPERLESS_THREADS_PER_WORKER:2# 每个工作进程的线程数PAPERLESS_TIME_ZONE:Asia/Shanghai# 系统时区设置为上海时区# ----- 任务调度优化配置 -----PAPERLESS_TRAIN_TASK_CRON:"5 */1 * * *"# 每小时第5分钟自动训练分类器(提高自动分类准确度)PAPERLESS_INDEX_TASK_CRON:"15 0 * * *"# 每天午夜00:15进行索引优化(提高搜索速度)PAPERLESS_SANITY_TASK_CRON:"30 0 * * 0"# 每周日午夜00:30进行完整性检查(检查文档一致性)# ----- 文件权限配置 -----# 宿主机用户和分组PAPERLESS_UID:1000# 容器内文件所有者的用户ID(对应宿主机用户)PAPERLESS_GID:1000# 容器内文件所有者的组ID(对应宿主机用户组)volumes:# 数据卷映射(持久化存储)-./data/data:/usr/src/paperless/data# 应用数据目录(索引、缓存等)-./data/media:/usr/src/paperless/media# 文档存储目录(原始文件和归档文件)-./data/export:/usr/src/paperless/export# 导出目录(用于导出文档)-./data/consume:/usr/src/paperless/consume# 消费目录(监控此目录自动导入文档)networks:-paperless-network# 连接到自定义网络healthcheck:# 健康检查配置test:["CMD","curl","-f","http://localhost:8000"]# 检查 Web 服务是否响应interval:30s# 每30秒检查一次timeout:10s# 超时时间10秒retries:3# 失败3次后标记为不健康start_period:60s# 容器启动后60秒开始健康检查(应用启动较慢)# ===== Gotenberg PDF 转换服务 =====gotenberg:image:gotenberg/gotenberg:8# 使用 Gotenberg 8 版本container_name:paperless-gotenberg# 容器名称restart:unless-stopped# 容器退出时自动重启(除非手动停止)command:# 容器启动命令参数-gotenberg# 主程序---chromium-disable-javascript=true# 禁用 Chromium 的 JavaScript(提高安全性和性能)---libreoffice-start-timeout=60s# LibreOffice 启动超时时间设置为60秒---api-timeout=300s# API 请求超时时间300秒environment:DISABLE_GOOGLE_CHROME:"1"# 禁用 Google Chrome(使用 Chromium 代替)networks:-paperless-network# 连接到自定义网络healthcheck:# 健康检查配置test:["CMD","curl","-f","http://localhost:3000/health"]# 检查 Gotenberg 健康状态interval:30s# 每30秒检查一次timeout:10s# 超时时间10秒retries:3# 失败3次后标记为不健康start_period:40s# 容器启动后40秒开始健康检查(LibreOffice 启动较慢)# ===== Apache Tika 文档解析服务 =====tika:image:apache/tika:latest# 使用 Apache Tika 最新版本container_name:paperless-tika# 容器名称restart:unless-stopped# 容器退出时自动重启(除非手动停止)networks:-paperless-network# 连接到自定义网络healthcheck:# 健康检查配置 - 简化为 TCP 端口检查test:["CMD-SHELL","timeout 5 bash -c '</dev/tcp/localhost/9998' || exit 1"]# 检查 9998 端口是否可访问interval:30s# 每30秒检查一次timeout:10s# 超时时间10秒retries:5# 失败5次后标记为不健康(增加容错)start_period:60s# 容器启动后60秒开始健康检查(Tika 启动较慢)# ===== 网络配置 =====networks:paperless-network:# 自定义网络名称driver:bridge# 使用桥接网络驱动name:paperless-net# 网络显示名称ipam:# IP 地址管理配置driver:default# 使用默认 IPAM 驱动config:-subnet:172.28.0.0/16# 子网地址范围gateway:172.28.0.1# 网关地址五、网络配置(解决 Network unreachable)
networks:paperless-network:driver:bridgename:paperless-netipam:config:-subnet:172.28.0.0/16gateway:172.28.0.1为什么要显式指定网络?
- 避免 CentOS / iptables 残留规则冲突
- 避免 Docker 默认网络创建失败
- 彻底解决
[Errno 101] Network is unreachable
六、部署步骤(可直接执行)
# 1. 构建镜像dockercompose build# 2. 启动服务dockercompose up -d# 3. 查看状态dockercomposeps访问:
http://服务器IP:8000七、最终效果验证
✔ 支持 doc / docx 上传
✔ 支持宋体 / 楷体 / 黑体中文 OCR
✔ 中文全文搜索
✔ 自动分类训练
✔ 稳定运行,无随机失败
八、总结(踩坑后的结论)
Paperless-ngx 想稳定支持中文 Word,不是装个 LibreOffice 就完事。
真正关键的是:
- Tika + Gotenberg 服务完整
- 正确的启动顺序(healthcheck)
- 中文 OCR 语言包
- 非 root 用户运行
- 稳定的 Docker 网络
这套方案,已经在CentOS 7 / Windows Docker / 生产环境全部验证通过。
可以放心直接用。