Docspell Docker Compose 部署指南

Docspell 0.43.0 多服务栈(restserver+joex+dsc+PostgreSQL+Solr)Docker Compose 部署全流程:实测回显、环境变量映射表、JVM 堆配置与两则排障实录

DocspellDocspellDockerPostgreSQLSolrJVM文档管理自托管2026/11/01

Docspell Docker Compose 部署指南

目标:在 Ubuntu 26.04 服务器上用 Docker Compose 从零部署 Docspell 0.43.0 完整功能栈(restserver + joex + dsc 目录监视 + PostgreSQL + Solr 全文检索),完成注册、上传、检索、目录摄取的全链路验证,并沉淀本批部署实际踩过的坑与排障方案。

适用版本:Docspell v0.43.0(2025-03-15 构建)。文中所有命令与回显均为 2026-11-01 实测。

一、环境信息

本指南基于以下真实服务器环境实测,所有命令与输出均逐条验证:

项目值验证命令
操作系统Ubuntu 26.04.1 LTScat /etc/os-release
内核7.0.0-38-genericuname -r
CPU / 内存6 核 / 15 GiBnproc / free -h
Docker29.9.2, build a82e528docker --version
Docker Composev5.6.1docker compose version
Docspellv0.43.0(builtAtString 2025-03-15 16:46:56.280+0100,gitCommit 6b4e03ac3a2ac013783ec42245c01b7c0ff0dca9)curl http://localhost:8137/api/info/version

Docker 引擎实测回显:

$ docker --version
Docker version 29.9.2, build a82e528
$ docker compose version
Docker Compose version v5.6.1

Docspell 栈对外仅暴露 restserver 的 Web/API 端口(本例宿主映射 8137,组件内部端口 7880),PostgreSQL、Solr、joex 均不对外发布端口,仅通过 Compose 内部网络 docspell-net(固定网段 10.89.59.0/24)互通。

二、镜像选型说明

Docspell 官方镜像发布在 GitHub 容器组织的 docspell 名下(ghcr.io),CLI 工具 dsc 同时发布在 Docker Hub(来源:docspell.org/docs/install/docker 页 "Docker Images" 一节,查询日期 2026-11-01):

镜像作用实测大小说明
ghcr.io/docspell/restserver:v0.43.0HTTP 服务(Web UI + REST API)1.43 GB内嵌 OpenJDK 21(java -version 实测 21.0.11)
ghcr.io/docspell/joex:v0.43.0作业执行器6.13 GB已捆绑全部外部处理工具(ocrmypdf、unoconv、ghostscript、tesseract 等),无需另装
docspell/dsc:latest命令行客户端(目录监视 watch)34.8 MB镜像不定义 CMD/ENTRYPOINT,必须在 compose 里显式给出 command
postgres:18.6元数据与文件存储650 MB官方 compose 示例同款
solr:10全文检索引擎1.23 GB官方 compose 示例同款

官方镜像标签策略(来源:同上 Docker 页,查询日期 2026-11-01):

  • latest 恒指向最新 release;每个 release 同时打对应版本号标签(如 v0.43.0);
  • 另有 nightly 标签由 master 分支构建,官方明确提示 "should be used with care, because things might break in between"。

选型结论:生产部署应钉死版本号标签(本例 v0.43.0),不要用 latest/nightly——Docspell 不支持降级(官方 Docker 页 Upgrading 一节原文 "Since downgrading is not supported"),latest 漂移会直接撞上不可回退的升级。

💡 技术拓展:Docspell 官方提供多种部署形态,不止 Compose 一种——

形态特点适用场景
docker run 手工组网官方最小示例用 H2 内嵌库,无全文检索快速尝鲜,不适合生产
Docker Compose一条命令拉起 PostgreSQL + Solr 完整栈单服务器生产(本文方案)
Helm Chart官方仓库 charts/docspell,StatefulSet 形态Kubernetes 集群
手动安装(二进制 + systemd)自行管理 JDK/数据库/外部工具无 Docker 的环境

本文采用官方推荐的 Docker Compose 形态,因其自带 FTS 与 PostgreSQL 且仅一条启动命令。

三、前置条件

部署前先建好目录骨架。compose 文件用相对路径挂载数据与摄取目录,本例统一放在 /opt/docspell:

$ mkdir -p /opt/docspell/{data,import/admin}
$ cd /opt/docspell

两个必须注意的前置点(均为本批实测踩坑,详见第十一章):

  1. import/admin/ 子目录:dsc watch 摄取目录时,监视根目录下必须存在以 collective 名命名的子目录(本例注册 collective 为 admin),否则文件不会被摄取,日志报 Error finding collective…Make sure there is a subdirectory with the name of the collective。
  2. JVM 堆内存:restserver 与 joex 都是 Scala/JVM 进程,官方 joex 默认配置在启用 NLP full 模式时要求 -Xmx1400M 以上;小内存服务器应通过 JAVA_OPTS 限堆(本例 -Xms256m -Xmx512m)并关闭 NLP 模式,见第七章。

四、部署步骤

4.1 准备 compose 文件

将下列内容保存为 /opt/docspell/docker-compose.yml。这是本批实测终稿(在官方 docker-compose 示例基础上:钉死 v0.43.0 版本、注入 JAVA_OPTS 堆限制、joex 关闭 NLP、solr 补 hostname、命名卷改 bind 挂载、固定网段):

name: docspell-0.43.0-stack
services:
  restserver:
    image: ghcr.io/docspell/restserver:v0.43.0
    hostname: docspell-restserver
    container_name: docspell-0.43.0-restserver
    restart: unless-stopped
    ports:
      - "8137:7880"
    environment:
      TZ: 'Asia/Shanghai'
      JAVA_OPTS: '-Xms256m -Xmx512m'
      DOCSPELL_SERVER_INTERNAL__URL: 'http://docspell-restserver:7880'
      DOCSPELL_SERVER_ADMIN__ENDPOINT_SECRET: 'q1w2e3r4'
      DOCSPELL_SERVER_AUTH_SERVER__SECRET: 'q1w2e3r4'
      DOCSPELL_SERVER_BACKEND_JDBC_PASSWORD: 'q1w2e3r4'
      DOCSPELL_SERVER_BACKEND_JDBC_URL: 'jdbc:postgresql://db:5432/docspell'
      DOCSPELL_SERVER_BACKEND_JDBC_USER: 'docspell'
      DOCSPELL_SERVER_BIND_ADDRESS: '0.0.0.0'
      DOCSPELL_SERVER_FULL__TEXT__SEARCH_ENABLED: 'true'
      DOCSPELL_SERVER_FULL__TEXT__SEARCH_SOLR_URL: 'http://docspell-solr:8983/solr/docspell'
      DOCSPELL_SERVER_INTEGRATION__ENDPOINT_ENABLED: 'true'
      DOCSPELL_SERVER_INTEGRATION__ENDPOINT_HTTP__HEADER_ENABLED: 'true'
      DOCSPELL_SERVER_INTEGRATION__ENDPOINT_HTTP__HEADER_HEADER__VALUE: 'q1w2e3r4'
      DOCSPELL_SERVER_BACKEND_SIGNUP_MODE: 'open'
      DOCSPELL_SERVER_BACKEND_SIGNUP_NEW__INVITE__PASSWORD: ''
      DOCSPELL_SERVER_BACKEND_ADDONS_ENABLED: 'false'
    networks:
      - docspell-net
    depends_on:
      - db

  joex:
    image: ghcr.io/docspell/joex:v0.43.0
    hostname: docspell-joex
    container_name: docspell-0.43.0-joex
    restart: unless-stopped
    environment:
      TZ: 'Asia/Shanghai'
      JAVA_OPTS: '-Xms256m -Xmx512m'
      DOCSPELL_JOEX_APP__ID: 'joex1'
      DOCSPELL_JOEX_PERIODIC__SCHEDULER_NAME: 'joex1'
      DOCSPELL_JOEX_SCHEDULER_NAME: 'joex1'
      DOCSPELL_JOEX_BASE__URL: 'http://docspell-joex:7878'
      DOCSPELL_JOEX_BIND_ADDRESS: '0.0.0.0'
      DOCSPELL_JOEX_FULL__TEXT__SEARCH_ENABLED: 'true'
      DOCSPELL_JOEX_FULL__TEXT__SEARCH_SOLR_URL: 'http://docspell-solr:8983/solr/docspell'
      DOCSPELL_JOEX_JDBC_PASSWORD: 'q1w2e3r4'
      DOCSPELL_JOEX_JDBC_URL: 'jdbc:postgresql://db:5432/docspell'
      DOCSPELL_JOEX_JDBC_USER: 'docspell'
      DOCSPELL_JOEX_ADDONS_EXECUTOR__CONFIG_RUNNER: 'docker,trivial'
      DOCSPELL_JOEX_CONVERT_HTML__CONVERTER: 'weasyprint'
      DOCSPELL_JOEX_TEXT__ANALYSIS_NLP_MODE: 'disabled'
    networks:
      - docspell-net
    depends_on:
      - db

  consumedir:
    image: docspell/dsc:latest
    container_name: docspell-0.43.0-consumedir
    command:
      - dsc
      - "-d"
      - "http://docspell-restserver:7880"
      - "watch"
      - "--delete"
      - "-ir"
      - "--not-matches"
      - "**/.*"
      - "--header"
      - "Docspell-Integration:q1w2e3r4"
      - "/opt/docs"
    restart: unless-stopped
    volumes:
      - ./import:/opt/docs
    networks:
      - docspell-net
    depends_on:
      - restserver

  db:
    image: postgres:18.6
    container_name: docspell-0.43.0-db
    restart: unless-stopped
    volumes:
      - ./data/postgres:/var/lib/postgresql
    environment:
      POSTGRES_USER: 'docspell'
      POSTGRES_PASSWORD: 'q1w2e3r4'
      POSTGRES_DB: 'docspell'
    networks:
      - docspell-net

  solr:
    image: solr:10
    hostname: docspell-solr
    container_name: docspell-0.43.0-solr
    restart: unless-stopped
    volumes:
      - ./data/solr:/var/solr
    environment:
      SOLR_OPTS: "-Dsolr.modules=analysis-extras"
    command:
      - bash
      - -c
      - 'precreate-core docspell; exec solr start -f --user-managed'
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8983/solr/docspell/admin/ping"]
      interval: 1m
      timeout: 10s
      retries: 2
      start_period: 30s
    networks:
      - docspell-net

networks:
  docspell-net:
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.59.0/24

关键结构解读:

  • 五个服务各司其职:restserver(对外 Web/API,宿主 8137→内部 7880)、joex(异步作业:OCR/文本抽取/索引,内部 7878 不对外)、consumedir(dsc watch 摄取目录)、db(PostgreSQL,schema 首启自动建表)、solr(全文检索 core 名为 docspell,由 precreate-core 预建)。
  • 三处 hostname 是服务间寻址的关键:DOCSPELL_SERVER_INTERNAL__URL、DOCSPELL_JOEX_BASE__URL、两个 FTS 的 SOLR_URL 都按 hostname 寻址,compose 网络 DNS 必须能解析 docspell-restserver / docspell-joex / docspell-solr 这三个名字(官方示例靠 container_name 恰好同名,本例容器名带版本前缀,故 solr 显式加 hostname: docspell-solr——漏掉它就是第十一章问题 2)。
  • integration 密钥两处必须一致:restserver 的 DOCSPELL_SERVER_INTEGRATION__ENDPOINT_HTTP__HEADER_HEADER__VALUE 与 consumedir 命令行 --header Docspell-Integration:… 是同一把钥匙(官方 compose 注释原文 "both values must match")。
  • DOCSPELL_JOEX_TEXT__ANALYSIS_NLP_MODE: 'disabled':512 MB 堆下的官方取舍,原因与代价见第七章与第十一章问题 1。
  • 演示口令统一 q1w2e3r4;生产环境务必替换三处 secret(ADMIN__ENDPOINT_SECRET、AUTH_SERVER__SECRET、integration header 值)。

4.2 拉取镜像

$ docker compose pull
 Image postgres:18.6 Pulling
 Image ghcr.io/docspell/restserver:v0.43.0 Pulling
 Image ghcr.io/docspell/joex:v0.43.0 Pulling
 Image docspell/dsc:latest Pulling
 Image solr:10 Pulling
 Image postgres:18.6 Pulled
 Image ghcr.io/docspell/joex:v0.43.0 Pulled
 Image ghcr.io/docspell/restserver:v0.43.0 Pulled
 Image docspell/dsc:latest Pulled
 …(层下载进度,输出节选(实测首尾))
 Image solr:10 Pulled

五个镜像合计约 9.5 GB(见第二章实测大小表),其中 joex 一个镜像就占 6.13 GB——因为它捆绑了 LibreOffice/OCR 全链路工具,首次拉取耗时最长,属正常现象。

4.3 启动

$ docker compose up -d
 Container docspell-0.43.0-restserver Running
 Container docspell-0.43.0-joex Running
 Container docspell-0.43.0-consumedir Running
 Container docspell-0.43.0-db Running
 Container docspell-0.43.0-solr Recreate
 Container docspell-0.43.0-solr Recreated
 Container docspell-0.43.0-solr Starting
 Container docspell-0.43.0-solr Started

(上为配置变更后一次真实 up -d 回显:未变的服务显示 Running,compose 检测到 solr 配置变化自动 Recreate——这正是 up -d 幂等增量生效的行为。)

4.4 验证服务状态

$ docker compose ps
NAME                         IMAGE                                 COMMAND                  SERVICE      CREATED          STATUS                    PORTS
docspell-0.43.0-consumedir   docspell/dsc:latest                   "dsc -d http://docsp…"   consumedir   44 minutes ago   Up 21 minutes
docspell-0.43.0-db           postgres:18.6                         "docker-entrypoint.s…"   db           44 minutes ago   Up 44 minutes             5432/tcp
docspell-0.43.0-joex         ghcr.io/docspell/joex:v0.43.0         "/opt/joex-entrypoin…"   joex         28 minutes ago   Up 10 minutes             7878/tcp
docspell-0.43.0-restserver   ghcr.io/docspell/restserver:v0.43.0   "/opt/docspell-rests…"   restserver   44 minutes ago   Up 10 minutes             0.0.0.0:8137->7880/tcp, [::]:8137->7880/tcp
docspell-0.43.0-solr         solr:10                               "docker-entrypoint.s…"   solr         14 minutes ago   Up 14 minutes (healthy)   8983/tcp

五个服务全部 Up,solr 带 healthcheck 状态 (healthy),仅 restserver 对外发布端口。端口监听复核:

$ ss -ltn | grep 8137
LISTEN 0      4096         0.0.0.0:8137       0.0.0.0:*
LISTEN 0      4096            [::]:8137          [::]:*

版本端点复核(注意:版本端点不在 /api/v1 前缀下,实测路径为 /api/info/version):

$ curl -s http://localhost:8137/api/info/version
{"version":"0.43.0","builtAtMillis":1742053616280,"builtAtString":"2025-03-15 16:46:56.280+0100","gitCommit":"6b4e03ac3a2ac013783ec42245c01b7c0ff0dca9","gitVersion":"0.43.0"}

Web UI 入口复核:根路径 / 返回 404,应用挂在 /app 下:

$ curl -s -I http://localhost:8137/ | head -1
HTTP/1.1 404 Not Found
$ curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8137/app
200

浏览器访问 http://<服务器IP>:8137/app 即见登录页。

4.5 注册首个账户

compose 环境变量 DOCSPELL_SERVER_BACKEND_SIGNUP_MODE: 'open' 允许自助注册。官方文档建议注册时 collective 名与用户名取同一个(来源:docspell.org/docs/install/docker 页,查询日期 2026-11-01),后续登录只用这一个名字。用 API 注册(演示账号 admin / q1w2e3r4):

$ curl -s -X POST http://localhost:8137/api/v1/open/signup/register \
    -H "Content-Type: application/json" \
    -d '{"collectiveName": "admin", "login": "admin", "password": "q1w2e3r4"}'
{"success":true,"message":"Signup successful"}

登录取 token(后续调用都带 X-Docspell-Auth 头;token 有效期 validMs: 300000,即 5 分钟):

$ curl -s -X POST http://localhost:8137/api/v1/open/auth/login \
    -H "Content-Type: application/json" \
    -d '{"account": "admin", "password": "q1w2e3r4"}'
{"collective":"admin","user":"admin","success":true,"message":"Login successful","token":"1793535919263-MS9hZG1pbi9IRDZaNkJEUFEzai1BWWJpbVRWMXlXRi1tSlVidzhVZWhEdy1QS1RXeWJlZ1RvNS9hZG1pbg==-false-$2a$10$QhJTQpsU9gXdRtSdVlcRIe-pesNo6DW0D0TbNlMIaMOYP24xLA=","validMs":300000,"requireSecondFactor":false}

$ TOKEN=<上面返回的 token 值>

注册完成后建议把 signup mode 改为 closed 或 invite(官方 compose 注释原话,见第十一章问题 6)。

4.6 上传与检索验证

上传一份文本文件(meta 与 file 两个 multipart 部分):

$ curl -s -X POST http://localhost:8137/api/v1/sec/upload/item \
    -H "X-Docspell-Auth: $TOKEN" \
    -F 'meta={"multiple": true};type=application/json' \
    -F "file=@import-note.txt"
{"success":true,"message":"Files submitted."}

上传是异步处理:文件先入队,由 joex 完成格式转换/文本抽取/索引。稍候按条件检索(结构化查询,q= 为查询表达式):

$ curl -s -H "X-Docspell-Auth: $TOKEN" "http://localhost:8137/api/v1/sec/item/search?q=&withDetails=true"
{
    "groups": [
        {
            "name": "2026-11",
            "items": [
                {
                    "id": "DRBnvpvRfGV-oqdwHc1Jjpi-CW9MzZ3DeN2-Nby6RLJ5M59",
                    "name": "import-note.txt",
                    "state": "created",
                    "source": "webapp",
                    "direction": "incoming",
                    "attachments": [
                        {
                            "id": "7D9MRpPC1Nn-ukzRVAmb5bk-UZ6EkwB9262-vpDbdQVwJ3v",
                            "position": 0,
                            "name": "import-note.converted.pdf",
                            "pageCount": 1
                        }
                    ],
                    "tags": []
                    …(其余空字段略,输出节选(实测首尾))
                }
            ]
        }
    ],
    "limit": 200,
    "offset": 0,
    "limitCapped": false
}

条目已生成(state: created),且 joex 已把上传的 txt 自动转成了 import-note.converted.pdf 附件——这就是处理流水线跑通的标志。

Solr 全文检索验证(FTS 查询必须用 content: 字段前缀,裸词会被查询解析器拒绝):

$ curl -s -H "X-Docspell-Auth: $TOKEN" --get --data-urlencode 'q=content:"cloud services"' \
    http://localhost:8137/api/v1/sec/item/search
groups: [('Results', ['import-note.txt'])]

4.7 目录监视摄取验证

向 import/admin/(collective 名子目录)放入新文件,dsc watch 自动经 integration 端点上传并删除源文件(实测回显):

$ echo 'consume3 watch test' > import/admin/consume3.txt
$ ls -l import/admin/
total 8
-rw-r--r-- 1 root root 73 Nov  1 20:44 consume-note.txt
-rw-r--r-- 1 root root 20 Nov  1 21:21 consume3.txt
$ sleep 20; ls -l import/admin/
total 4
-rw-r--r-- 1 root root 73 Nov  1 20:44 consume-note.txt

$ docker compose logs --tail=3 consumedir
docspell-0.43.0-consumedir  | Sending request …
docspell-0.43.0-consumedir  | Deleted file
docspell-0.43.0-consumedir  | Server: Files submitted.

新文件 consume3.txt 被摄取并因 --delete 删除;目录里更早存在的 consume-note.txt 纹丝不动——印证 watch 只响应新文件事件、不补扫已存在文件(见第十一章问题 3)。检索验证全链路(watch → integration 上传 → joex 转换 → Solr 索引):

$ curl -s -H "X-Docspell-Auth: $TOKEN" --get --data-urlencode 'q=content:consume3' \
    http://localhost:8137/api/v1/sec/item/search
{"groups":[{"name":"Results","items":[{"id":"X5aQqkdnXR5-2w7t5GZKR8F-jXzBaXX4YNu-aXs1BDo1uQ","name":"consume3.txt","state":"created","date":1793539278167,"dueDate":null,"source":"integration","direction":"incoming","corrOrg":null,"corrPerson":null,"concPerson":null,"concEquipment":null,"folder":null,"attachments":[],"tags":[],"customfields":[],"relatedItems":[],"notes":null,"highlighting":[{"name":"consume3.converted.pdf","lines":["**consume3**.converted.pdf","**consume3** watch test"]},{"name":"item","lines":["**consume3**.txt"]}]}]}],"limit":200,"offset":0,"limitCapped":false}

条目 source: integration 标记其来自目录摄取通道,highlighting 返回全文命中高亮。

五、数据持久化说明

本方案用 bind 挂载把全部状态落在 compose 同级的 data/ 目录(官方示例用命名卷,bind 化后备份与迁移更直观):

挂载宿主机路径内容实测占用
db → /var/lib/postgresql./data/postgresPostgreSQL 数据目录(含 18 主版本子目录)68 MB
solr → /var/solr./data/solrSolr core 数据与 schema1.7 MB
consumedir → /opt/docs./import摄取暂存目录(须含 collective 子目录)—
$ ls -l data/
total 8
drwxr-xr-x 3 root root 4096 Nov  1 20:23 postgres
drwxr-xr-x 4 8983 8983 4096 Nov  1 20:23 solr
$ du -sh data/*
68M     data/postgres
1.7M    data/solr

要点:Docspell 默认文件后端是 database——文档附件的二进制内容也存进 PostgreSQL(本例 data/postgres 68 MB 中即含 3 份测试文档),Solr 里只有索引。因此备份 PostgreSQL 就保住了全部档案,Solr 数据可随时用重建索引找回(见第十章)。

六、环境变量表

Docspell 用 Typesafe Config,环境变量名按固定规则映射到 HOCON 配置路径:前缀 DOCSPELL_,单个 _ 对应配置层级的 .,连续双 __ 对应配置键中的 -(连字符)。例:

环境变量对应配置项
DOCSPELL_SERVER_BACKEND_JDBC_URLdocspell.server.backend.jdbc.url
DOCSPELL_SERVER_ADMIN__ENDPOINT_SECRETdocspell.server.admin-endpoint.secret
DOCSPELL_JOEX_TEXT__ANALYSIS_NLP_MODEdocspell.joex.text-analysis.nlp.mode
DOCSPELL_SERVER_FULL__TEXT__SEARCH_SOLR_URLdocspell.server.full-text-search.solr-url

本 compose 各服务变量一览(restserver,docspell.server.*):

环境变量本例取值含义
JAVA_OPTS-Xms256m -Xmx512mJVM 堆限制(非 Docspell 配置,由镜像启动脚本读取)
DOCSPELL_SERVER_INTERNAL__URLhttp://docspell-restserver:7880内部自寻址 URL(通知 joex 等用)
DOCSPELL_SERVER_ADMIN__ENDPOINT_SECRETq1w2e3r4管理端点口令(Docspell-Admin-Secret 头)
DOCSPELL_SERVER_AUTH_SERVER__SECRETq1w2e3r4登录 token 签名密钥
DOCSPELL_SERVER_BACKEND_JDBC_URLjdbc:postgresql://db:5432/docspell元数据库连接
DOCSPELL_SERVER_BACKEND_JDBC_USER / _PASSWORDdocspell / q1w2e3r4数据库账号
DOCSPELL_SERVER_BIND_ADDRESS0.0.0.0监听全部接口(默认只监听 127.0.0.1,容器内必须放开)
DOCSPELL_SERVER_FULL__TEXT__SEARCH_ENABLEDtrue开启 Solr 全文检索
DOCSPELL_SERVER_FULL__TEXT__SEARCH_SOLR_URLhttp://docspell-solr:8983/solr/docspellSolr core 地址
DOCSPELL_SERVER_INTEGRATION__ENDPOINT_ENABLEDtrue开启 integration 上传端点
DOCSPELL_SERVER_INTEGRATION__ENDPOINT_HTTP__HEADER_ENABLEDtrueintegration 用 HTTP 头认证
DOCSPELL_SERVER_INTEGRATION__ENDPOINT_HTTP__HEADER_HEADER__VALUEq1w2e3r4integration 口令(须与 consumedir --header 一致)
DOCSPELL_SERVER_BACKEND_SIGNUP_MODEopen注册模式:open/invite/closed
DOCSPELL_SERVER_BACKEND_SIGNUP_NEW__INVITE__PASSWORD''invite 模式的邀请口令(open 模式留空)
DOCSPELL_SERVER_BACKEND_ADDONS_ENABLEDfalse附加插件(addon)开关

joex 服务变量(docspell.joex.*):

环境变量本例取值含义
JAVA_OPTS-Xms256m -Xmx512mJVM 堆限制
DOCSPELL_JOEX_APP__ID / SCHEDULER_NAME / PERIODIC__SCHEDULER_NAMEjoex1执行器与调度器标识(多 joex 实例须互异)
DOCSPELL_JOEX_BASE__URLhttp://docspell-joex:7878restserver 通知 joex 新作业用的地址
DOCSPELL_JOEX_BIND_ADDRESS0.0.0.0监听全部接口
DOCSPELL_JOEX_FULL__TEXT__SEARCH_ENABLED / SOLR_URLtrue / http://docspell-solr:8983/solr/docspelljoex 侧写索引
DOCSPELL_JOEX_JDBC_URL / _USER / _PASSWORD同 restserver 指向同一库作业队列与元数据
DOCSPELL_JOEX_ADDONS_EXECUTOR__CONFIG_RUNNERdocker,trivialaddon 运行器
DOCSPELL_JOEX_CONVERT_HTML__CONVERTERweasyprintHTML 转 PDF 用 weasyprint(官方 compose 同款)
DOCSPELL_JOEX_TEXT__ANALYSIS_NLP_MODEdisabled关闭 Stanford NLP(512 MB 堆取舍,见第七章)

💡 技术拓展:joex 的 NLP 分析模式共四档(来源:joex reference.conf 0.43.0 注释,查询日期 2026-11-01)——

mode能力资源要求
full加载 Stanford NLP 实体识别模型(德/英/法…)官方注释要求 joex 堆 ≥1400 MB
basic仅部分轻量 NLP 功能介于 full 与 regexonly 之间
regexonly只用正则抽取日期/金额等,不加载 NLP 模型低
disabled完全不做文本分析最低

本部署限堆 512 MB,选 disabled(full 模式实测 OOM 崩溃循环,见第十一章问题 1)。

七、配置参数说明(JVM 堆专节)

restserver/joex 的 JVM 参数通过镜像启动脚本读取环境变量 JAVA_OPTS 注入,compose 中位置即各服务的 environment: 段:

    environment:
      JAVA_OPTS: '-Xms256m -Xmx512m'

修改后必须实测确认生效,用进程命令行复核(两个 JVM 服务分别执行):

$ docker exec docspell-0.43.0-joex ps -ef | grep java
root           8       1  0 20:57 ?        00:00:08 java -Xms256m -Xmx512m -Dconfig.file=/opt/docspell-joex/bin/../conf/docspell-joex.conf -cp /opt/docspell-joex/lib/com.github.eikek.docspell-joex-0.43.0-classpath.jar docspell.joex.Main

$ docker exec docspell-0.43.0-restserver ps -ef | grep java
root           1       0  0 20:57 ?        00:00:08 java -Xms256m -Xmx512m -Dconfig.file=/opt/docspell-restserver/bin/../conf/docspell-server.conf -cp /opt/docspell-restserver/lib/com.github.eikek.docspell-restserver-0.43.0-classpath.jar docspell.restserver.Main

回显中 -Xms256m -Xmx512m 即实际生效堆参数。两点提示:

  1. -Dconfig.file=… 显示镜像默认加载自带的 conf/docspell-{joex,server}.conf(其内容即官方 reference.conf 加环境变量覆盖),要换成自定义配置文件见第八章。
  2. joex 若要用 NLP full 模式,JAVA_OPTS 至少 -Xmx1400m(官方 reference.conf 注释原文),否则启动即 OOM——本批实测踩过,见第十一章问题 1。

功能配置项的完整清单与默认值不在本文展开(官方 docspell.server.* / docspell.joex.* 数百项),常用键的含义已在第六章列出。

八、配置文件挂载

环境变量适合少量关键项;参数多时官方推荐挂一个 HOCON 配置文件,把文件路径作为启动命令的参数传给镜像(来源:docspell.org/docs/install/docker 页,查询日期 2026-11-01)。实测流程:

$ cat > /tmp/ds-b2.conf <<'EOF'
docspell.server {
  bind.address = "0.0.0.0"
  internal-url = "http://docspell-restserver:7880"
  backend.jdbc.url = "jdbc:postgresql://db:5432/docspell"
  backend.jdbc.user = "docspell"
  backend.jdbc.password = "q1w2e3r4"
  auth.server-secret = "q1w2e3r4"
}
EOF
$ docker run -d --name docspell-0.43.0-conftest \
    --network docspell-0430-stack_docspell-net \
    -v /tmp/ds-b2.conf:/opt/docspell.conf \
    -e JAVA_OPTS='-Xms256m -Xmx512m' \
    ghcr.io/docspell/restserver:v0.43.0 /opt/docspell.conf
78050fa613c9ec995862b29a4ff3dd550b01f934a44928b635db349ba42ae4f3

等待启动后验证(容器 IP 由 docker inspect 取得,实测 10.89.59.7):

$ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docspell-0.43.0-conftest
10.89.59.7
$ docker logs docspell-0.43.0-conftest 2>&1 | grep 'bound to address'
2026.11.01 13:23:00:0000 [io-comp...] [INFO ] org.http4s.ember.server.EmberServerBuilderCompanionPlatform - Ember-Server service bound to address: [::]:7880
$ curl -s http://10.89.59.7:7880/api/info/version
{"version":"0.43.0","builtAtMillis":1742053616280,"builtAtString":"2025-03-15 16:46:56.280+0100","gitCommit":"6b4e03ac3a2ac013783ec42245c01b7c0ff0dca9","gitVersion":"0.43.0"}

restserver 以挂载的 /opt/docspell.conf 为配置成功启动并响应 API。落到 compose 的写法(官方文档原话:给服务加 command: 传入配置文件路径):

  restserver:
    volumes:
      - ./docspell.conf:/opt/docspell.conf
    command:
      - /opt/docspell.conf

注意:command 传配置文件后,环境变量这一整层会被完全忽略(服务回落 reference.conf 默认:内嵌 H2 库 + localhost 监听),并非"环境变量作覆盖层"——配置文件必须自包含全部必需键。实测过程与逐键验证见《Docspell 0.43.0 配置参数详解》3.2/3.4;本批终稿 compose 未用此形态(纯环境变量),此处为独立实测验证。

九、等价 docker run

官方 Docker 页的最小示例用 docker run 手工组网(H2 内嵌库、无 FTS),三条命令形态如下(来源:docspell.org/docs/install/docker 页 Examples 一节,查询日期 2026-11-01):

$ docker network create --subnet 10.4.3.0/24 dsnet
$ docker run -d --name ds-restserver --network dsnet --ip 10.4.3.3 \
    -p 127.0.0.1:7880:7880 -v /tmp/testdb:/var/docspell \
    -v /tmp/docspell.conf:/opt/docspell.conf docspell/restserver:latest /opt/docspell.conf
$ docker run -d --name ds-joex --network dsnet --ip 10.4.3.2 \
    -v /tmp/testdb:/var/docspell -v /tmp/docspell.conf:/opt/docspell.conf \
    docspell/joex:latest /opt/docspell.conf

本文 compose 栈中 restserver 服务的等价 docker run 实测(复用 compose 网络与 PostgreSQL):

$ docker run -d --name docspell-0.43.0-runtest \
    --network docspell-0430-stack_docspell-net \
    -e JAVA_OPTS='-Xms256m -Xmx512m' \
    -e DOCSPELL_SERVER_BACKEND_JDBC_URL='jdbc:postgresql://db:5432/docspell' \
    -e DOCSPELL_SERVER_BACKEND_JDBC_USER=docspell \
    -e DOCSPELL_SERVER_BACKEND_JDBC_PASSWORD=q1w2e3r4 \
    -e DOCSPELL_SERVER_DEFAULTS_NEW_CONFIG_USER_PASSWORD=q1w2e3r4 \
    -e DOCSPELL_SERVER_AUTH_ADMIN_API_TOKEN=q1w2e3r4 \
    -e DOCSPELL_SERVER_APP_EXTERNAL_BASE_URL='http://localhost:8137' \
    -e DOCSPELL_SERVER_BIND_ADDRESS=0.0.0.0 \
    ghcr.io/docspell/restserver:v0.43.0
6361b0d3e4826b0319ddfa77595fcee19a603250442bbc96dbb85c8ca05e7c53

$ docker ps --filter name=runtest --format '{{.Names}} {{.Status}}'
docspell-0.43.0-runtest Up 32 seconds

$ docker logs docspell-0.43.0-runtest 2>&1 | tail -1
2026.11.01 13:10:40:0001 [io-comp...] [INFO ] org.http4s.ember.server.EmberServerBuilderCompanionPlatform - Ember-Server service bound to address: [::]:7880

$ curl -s http://10.89.59.7:7880/api/info/version
{"version":"0.43.0","builtAtMillis":1742053616280,"builtAtString":"2025-03-15 16:46:56.280+0100","gitCommit":"6b4e03ac3a2ac013783ec42245c01b7c0ff0dca9","gitVersion":"0.43.0"}

⚠️ 容器内没有 curl:docker exec docspell-0.43.0-runtest curl … 实测报 exec: "curl": executable file not found in $PATH(restserver/joex 镜像为精简 JRE 环境)。验证服务请用 docker logs 看绑定日志,或从宿主机直接 curl 容器 IP(如上面的 10.89.59.7)。

十、常用运维命令

状态与日志(实测回显):

$ docker compose logs --tail=2 restserver
docspell-0.43.0-restserver  | 2026.11.01 21:08:03:0000 [io-comp...] [INFO ] org.http4s.server.middleware.Logger - HTTP/1.1 GET /app
docspell-0.43.0-restserver  | 2026.11.01 21:08:03:0001 [io-comp...] [INFO ] org.http4s.server.middleware.Logger - HTTP/1.1 200 OK

restserver 默认把每条 HTTP 请求打进日志(如上面 GET /app → 200),排障时 docker compose logs -f <服务> 跟踪即可。

单服务重建(改配置后增量生效,up -d 只重建受影响服务,见 4.3 回显):

$ docker compose up -d solr
$ docker compose restart joex

数据库备份(pg_dump 直连 db 服务,实测):

$ docker exec docspell-0.43.0-db pg_dump -U docspell docspell > docspell-backup.sql
$ wc -l docspell-backup.sql
4377 docspell-backup.sql
$ grep -c 'CREATE TABLE' docspell-backup.sql
60

3 份测试文档的库导出 4377 行、60 张表。官方另提供 compose override 挂备份目录、以 docker-compose run 调 pg_dump 的备份流程(来源:docspell.org/docs/install/docker 页 Backups 一节,查询日期 2026-11-01),效果等价。

升级(官方 Docker 页 Upgrading 一节三步,注意先备份、不可降级):

$ docker compose down
$ docker compose pull
$ docker compose up --force-recreate -d

全文索引重建(Solr 数据丢失或换引擎后,用 API 触发,token 认证为 collective 级):

$ curl -s -X POST -H "X-Docspell-Auth: $TOKEN" http://localhost:8137/api/v1/sec/fts/reIndex
{"success":true,"message":"Full-text index will be re-created."}

十一、常见问题

问题 1:joex 反复 Restarting,日志报 OutOfMemoryError

现象:docker compose ps 显示 joex 状态 Restarting (1) 循环;日志尾部:

docspell.analysis.nlp.StanfordNerAnnotator.makePipeline:39 - Creating german Stanford NLP NER classifier...
Exception in thread "io-compute-blocker-3" java.lang.OutOfMemoryError: Java heap space
    at edu.stanford.nlp.ie.crf.CRFClassifier.loadClassifier(CRFClassifier.java:2601)

定位:joex 默认 docspell.joex.text-analysis.nlp.mode = full,加载 Stanford NLP 德语 NER 分类器需要大堆(官方 reference.conf 注释要求 -Xmx1400M 起),本部署 -Xmx512m 直接堆溢出 → 进程崩溃 → 积压 process-item 作业重试 → 循环崩溃。

解决(官方取舍,不加大堆):给 joex 注入环境变量 DOCSPELL_JOEX_TEXT__ANALYSIS_NLP_MODE: 'disabled',docker compose up -d joex 重建。验证:不再重启,积压作业重跑成功,日志出现 Text-Analysis finished in 108 ms → Job execution successful。代价:失去 NLP 实体建议(correspondent/concerned 等 proposals 改由 regex 路径产出)。低堆环境也可退一档用 regexonly/basic。

问题 2:开了 Solr 但 content: 检索报 HTTP 500

现象一:GET /api/v1/sec/item/search?q=content:consume2 返回 HTTP 500 空体,restserver 日志:

java.net.UnknownHostException: docspell-solr: Temporary failure in name resolution

定位与解决:FTS URL 指向 http://docspell-solr:8983,但 compose 里 solr 服务只设了 container_name: docspell-0.43.0-solr,网络 DNS 解析不到 docspell-solr。给 solr 服务补 hostname: docspell-solr 并重建。

现象二:DNS 修好仍 500,日志变为 400 Bad Request for request POST http://docspell-solr:8983/solr/docspell/query(joex 侧 full-text-reindex 作业对 /update 同样 400)。

定位与解决:core 由 precreate-core docspell 以默认 _default 示例 schema 创建,没有 docspell 字段。官方文档说明 "If Docspell detects an empty core it will run a schema setup on start automatically",但首次启动时 solr 不可达(DNS 未修),自动 schema 初始化被静默跳过。修复 DNS 后必须 docker compose restart restserver joex 让 JVM 服务重新检测空 core 并自动建 schema(实测建出 38 个字段),再 POST /api/v1/sec/fts/reIndex 重建索引。验证:q=content:consume2 返回 200 且命中条目、高亮显示 **consume2**.converted.pdf。

结论:官方 compose 示例本身可用;踩坑点是①solr 主机名与 URL 不一致②solr 不可达时启动会静默跳过 schema 初始化,修复连通性后必须重启 JVM 服务而非仅 reIndex。

问题 3:往摄取目录放文件,Docspell 里没有动静

两个已实测确认的机制:

  1. 必须有 collective 名子目录:watch 根目录(/opt/docs ↔ 宿主 ./import)下要建 import/<collective名>/(本例 import/admin/),否则 consumedir 日志报 Error finding collective…Make sure there is a subdirectory with the name of the collective,文件不摄取。
  2. watch 只响应新事件:已经存在于目录里的文件不会被补扫,放文件前先确认目录结构,再放入新文件;--delete 参数下摄取成功后源文件被删除,可据此确认闭环。

问题 4:docker exec <服务> curl 报 executable file not found

restserver/joex 镜像内无 curl(精简 JRE 环境,第九章实测)。验证一律走 docker logs 或宿主机 curl 容器 IP / 宿主映射端口。

问题 5:浏览器打开根路径 404

Docspell Web UI 挂在 /app(实测 GET / → 404,GET /app → 200)。访问地址用 http://<服务器IP>:8137/app。

问题 6:注册模式的安全收尾

compose 以 SIGNUP_MODE: open 便于首启注册,官方 compose 注释明确建议:建好账户后把 signup mode 改为 closed 或 invite(invite 需同时设置 DOCSPELL_SERVER_BACKEND_SIGNUP_NEW__INVITE__PASSWORD),否则任何人都能在公网实例上自助建档。

十二、参考链接

Docspell Docker Compose 部署指南 - Quzuo