Docker 环境下 Paperless-ngx 中文增强版部署实战

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 refused

2️⃣ 中文 OCR 报错的真正原因

复制代码
The selected ocr language chi_sim is not installed

不是 Paperless 配置问题,而是:

❌ 官方镜像默认 不包含中文 OCR 语言包

所以必须 自定义 Dockerfile


三、自定义 Dockerfile(中文 OCR 核心)

dockerfile 复制代码
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 主服务(关键点)

yaml 复制代码
depends_on:
  db:
    condition: service_healthy
  broker:
    condition: service_healthy
  gotenberg:
    condition: service_healthy
  tika:
    condition: service_healthy

这是解决 Connection refused 的核心配置

Paperless 一定要在:

  • Tika
  • Gotenberg
  • Redis
  • PostgreSQL

全部健康之后再启动

yaml 复制代码
在这里插入代码片

3️⃣ Word / OCR 相关核心环境变量

yaml 复制代码
PAPERLESS_TIKA_ENABLED: "1"
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000

PAPERLESS_OCR_LANGUAGE: chi_sim+eng
PAPERLESS_OCR_MODE: skip

含义说明:

  • skip:已有文本层不重复 OCR(效率 + 质量)
  • 中文 Word → PDF → OCR 完整链路

4️⃣ UID / GID(踩坑最多的一点)

yaml 复制代码
PAPERLESS_UID: 1000
PAPERLESS_GID: 1000

⚠️ 千万不要用 root(0:0)

否则你会看到:

复制代码
usermod: user paperless is currently used by process 1
fatal: stopping the container

5️⃣ 完成文件

yaml 复制代码
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)

yaml 复制代码
networks:
  paperless-network:
    driver: bridge
    name: paperless-net
    ipam:
      config:
        - subnet: 172.28.0.0/16
          gateway: 172.28.0.1

为什么要显式指定网络?

  • 避免 CentOS / iptables 残留规则冲突
  • 避免 Docker 默认网络创建失败
  • 彻底解决 [Errno 101] Network is unreachable

六、部署步骤(可直接执行)

bash 复制代码
# 1. 构建镜像
docker compose build

# 2. 启动服务
docker compose up -d

# 3. 查看状态
docker compose ps

访问:

复制代码
http://服务器IP:8000

七、最终效果验证

✔ 支持 doc / docx 上传

✔ 支持宋体 / 楷体 / 黑体中文 OCR

✔ 中文全文搜索

✔ 自动分类训练

✔ 稳定运行,无随机失败


八、总结(踩坑后的结论)

Paperless-ngx 想稳定支持中文 Word,不是装个 LibreOffice 就完事。

真正关键的是:

  1. Tika + Gotenberg 服务完整
  2. 正确的启动顺序(healthcheck)
  3. 中文 OCR 语言包
  4. 非 root 用户运行
  5. 稳定的 Docker 网络

这套方案,已经在 CentOS 7 / Windows Docker / 生产环境 全部验证通过。

可以放心直接用。

相关推荐
努力搬砖的咸鱼2 小时前
Kubernetes 核心对象详解:Pod、Deployment、Service
微服务·云原生·容器·架构·kubernetes
南烟斋..3 小时前
嵌入式系统(51单片机)核心外设详解:UART通信与DS18B20温度采集
linux·运维·网络
e***98573 小时前
跨平台虚拟机网络故障排查指南
运维·网络
重生之绝世牛码3 小时前
Linux软件安装 —— SSH免密登录
大数据·linux·运维·ssh·软件安装·免密登录
AI殉道师3 小时前
Vercel 重磅发布 agent-browser:AI Agent 浏览器自动化的新纪元来了
运维·人工智能·自动化
计算机C9硕士_算法工程师3 小时前
基于深度学习风力叶片缺陷检测系统 无人机自动巡检风电场 - 风电运维智能诊断平台 - 缺陷生命周期追踪系统
运维·深度学习·无人机
Kiyra3 小时前
阅读 Netty 源码关于 NioEventLoop 和 Channel 初始化部分的思考
运维·服务器·前端
初听于你4 小时前
IP地址与路由器地址
linux·运维·服务器·网络·tcp/ip·计算机网络·智能路由器
hanyi_qwe4 小时前
Kubernetes 集群调度 【K8S (五)】
云原生·容器·kubernetes