Scoold 1.70 Docker Compose 部署指南

在 Linux 服务器上以 Docker Compose 部署 Scoold 1.70.2 + Para 1.57.0 双服务栈:autoinit 初始化、四步引导向导、JVM 堆上限验证、备份恢复与五则排障实录,全程实测回显。

ScooldDocker ComposeDocker自托管Java2026/10/30

Scoold 1.70 Docker Compose 部署指南

‍‍​​‌​## 一、部署前准备

1.1 环境与资源要求

本文在真实 Linux 服务器上从零完成 Scoold 1.70.2 + Para 1.57.0 的部署与验收,全程命令与回显均为实测记录。开始前确认以下条件:

  • 一台 Linux 服务器(本文使用 root 账号操作),已安装 Docker 与 Docker Compose v2;
  • 磁盘剩余空间不少于 2GB(两个镜像合计约 900MB,加内嵌数据与日志余量);
  • 内存不少于 2GB——本文为两个 JVM 进程各配置 512MB 堆上限,再加系统开销与搜索索引缓存,2GB 是舒适下限;
  • 两个空闲 TCP 端口,本文规划为 8131(Scoold Web 入口)与 8132(Para 后端 API)。选端口前先确认未被占用:
ss -ltn | grep -E '8131|8132'

无输出即两个端口均空闲。若被占用,在后续 Compose 文件中同步替换为其他空闲端口即可。

1.2 软件版本与镜像渠道

角色镜像版本说明
Web 应用erudikaltd/scoold1.70.2Spring Boot 单 JAR,监听容器内 8000 端口
数据后端erudikaltd/para1.57.0Para 数据服务,监听容器内 8080 端口

两个镜像均由 Erudika 官方维护于 Docker Hub。版本号取自官方 GitHub Releases 与镜像 tag(查询日期 2026-10-30):Scoold 1.70.x 与 Para 1.57.x 是官方配套发布的版本组合,升级时两者应同步升级。

1.3 镜像拉取与网络降级实录

⚠️ 网络说明:本次部署实测时(2026-10-30)服务器直连 Docker Hub(registry-1.docker.io 与 auth.docker.io)出现连接超时,镜像源 DaoCloud(docker.m.daocloud.io)未收录 erudikaltd/para 仓库。实测可用的拉取渠道为国内镜像源 docker.1ms.run(对任意仓库透明代理)。当前实测可用渠道按优先级为:docker.1ms.run → 直连 Docker Hub → 官方 tag 配套渠道。以下拉取命令按实际可用渠道执行:

docker pull docker.1ms.run/erudikaltd/scoold:latest_stable
docker pull docker.1ms.run/erudikaltd/para:latest_stable

拉取完成后回贴官方 tag,使编排文件继续引用官方镜像名(与官方文档保持一致):

docker tag docker.1ms.run/erudikaltd/scoold:latest_stable erudikaltd/scoold:latest_stable
docker tag docker.1ms.run/erudikaltd/para:latest_stable erudikaltd/para:latest_stable
docker images | grep erudikaltd

实测回显:

erudikaltd/para:latest_stable    ...   408MB
erudikaltd/scoold:latest_stable  ...   408MB

(镜像体积各约 408MB,内含 JRE 与应用 JAR。)

二、编写 Compose 编排文件

2.1 目录与配置文件

为本次部署建立独立工作目录,并放置两个空配置模板(Scoold 与 Para 均支持 Typesafe Config 格式的 application.conf;空模板即代表全部使用默认值,这是官方推荐的首次部署方式):

mkdir -p /opt/scoold && cd /opt/scoold
cat > scoold-application.conf <<'EOF'
# empty template - all Scoold defaults apply
EOF
cat > para-application.conf <<'EOF'
# empty template - all Para defaults apply (H2 storage)
EOF

2.2 编排文件全文

创建 docker-compose.yml:

name: scoold-1.70.2-stack

services:
  para:
    image: erudikaltd/para:latest_stable
    container_name: para-svc
    ports:
      - "8132:8080"
    volumes:
      - type: volume
        source: paraData
        target: /para/data
      - type: volume
        source: paraLib
        target: /para/lib
      - type: bind
        source: ./para-application.conf
        target: /para/application.conf
    restart: always
    environment:
      - JAVA_OPTS=-Dconfig.file=/para/application.conf -Dloader.path=/para/lib -Xms256m -Xmx512m
    networks:
      - scoold-net

  scoold:
    depends_on:
      - para
    image: erudikaltd/scoold:latest_stable
    container_name: scoold-svc
    ports:
      - "8131:8000"
    volumes:
      - type: bind
        source: ./scoold-application.conf
        target: /scoold/application.conf
      - type: bind
        source: ./para-application.conf
        target: /scoold/para-application.conf
    restart: always
    environment:
      - JAVA_OPTS=-Dconfig.file=/scoold/application.conf -Dscoold.autoinit.para_config_file=/scoold/para-application.conf -Dscoold.para_endpoint=http://para:8080 -Xms256m -Xmx512m
      - BOOT_SLEEP=5
    networks:
      - scoold-net

volumes:
  paraData:
  paraLib:

networks:
  scoold-net:
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.64.0/24

2.3 编排设计逐项解说

  • 显式项目名 name: scoold-1.70.2-stack:Compose 项目名必须显式指定。多套自托管栈共存于同一台服务器时,同名项目的 down 操作会误删其他组件的栈——这是多服务共存的硬性纪律。
  • 启动顺序:scoold 服务声明 depends_on: para,保证 Para 先启动;Scoold 侧另配 BOOT_SLEEP=5,等 Para 完成监听后再发起连接。
  • autoinit 机制:-Dscoold.autoinit.para_config_file=/scoold/para-application.conf 让 Scoold 首次启动时自动在 Para 中创建 app:scoold 应用环境、生成接入密钥,并把运行时配置回写到挂载的配置文件中——这是 Scoold 的开箱即用核心机制,2.4 节有实测验证。
  • 数据持久化:Para 的数据与库目录使用命名卷 paraData/paraLib(内嵌 H2 数据库文件与 Lucene 索引落在这里);两个配置文件使用 bind mount,便于宿主机直接查看与修改。
  • JVM 堆上限:两个服务通过 JAVA_OPTS 显式设置 -Xms256m -Xmx512m。Scoold 与 Para 都是 Java 进程,生产环境必须给堆设上限,避免默认堆策略在内存紧张的宿主机上触发 OOM。修改位置即本文件 JAVA_OPTS 行,验证方法见 4.3 节。
  • 独立网络:专属 bridge 网络 scoold-net 并显式指定 10.89.64.0/24 网段(部署前用 docker network ls 确认该网段未被其他栈占用;被占用时从空闲网段中另选)。

2.4 启动与 autoinit 实录

cd /opt/scoold && docker compose up -d

实测回显:

 Container para-svc Created
 Container para-svc Started
 Container scoold-svc Starting
 Container scoold-svc Started

等待约 20 秒让两服务完成启动,查看 Scoold 日志确认 autoinit 生效:

docker logs scoold-svc 2>&1 | grep -E 'Auto-init|listening|Connected'

实测回显:

2026-10-30 09:18:56 [INFO ] Auto-init succeeded - created new app 'app:scoold' and saved keys to /scoold/application.conf.
2026-10-30 09:18:56 [INFO ] Scoold server is listening on http://localhost:8000
2026-10-30 09:18:56 [INFO ] Connected to Para on http://para:8080 with credentials for 'app:scoold'.

三行日志分别确认:Para 应用环境创建成功、Web 服务监听、后端连接建立。此时查看宿主机的 scoold-application.conf,会发现 autoinit 已把生成的接入密钥与运行时配置回写到这份 bind mount 文件里:

scoold.app_name = "Scoold"
scoold.para_access_key = "app:scoold"
scoold.para_secret_key = "CAtIBtcMWsWkSTRKzUZD+HCFTKt760n40DSNjJuVtA5SUOhxAjd9SQ=="
scoold.para_endpoint = "http://para:8080"
scoold.host_url = "http://localhost:8000"
scoold.app_secret_key = "XdTUO/Kup4ioavfr8PuvRow/9Qyr5pxDjj8NhPnnOIg="
...

⚠️ 注意:para_secret_key 与 app_secret_key 是首次启动自动生成的本实例专用密钥,属于敏感凭据,等同数据库口令管理——不要把回写后的配置文件提交到代码仓库或公开渠道。每个部署实例的密钥各不相同,本文以上回显已做示例化处理。

三、首次启动:初始化向导

Scoold 首次访问会强制进入初始化向导(onboarding),第一步注册的账号自动成为管理员。向导共四步。

3.1 验证向导入口

浏览器打开 http://<服务器IP>:8131/,任意页面都会 303 重定向到 /start:

curl -sS -o /dev/null -w 'location:%{redirect_url}\nstatus:%{http_code}\n' http://localhost:8131/

实测回显:

location:http://localhost:8131/start
status:303

3.2 四步向导内容

步骤页面内容
1/start/1选择界面语言
2/start/2检查与 Para 的连接状态(autoinit 正常时显示「Already connected to Para!」)
3/start/3站点设置:站点名称、对外 URL、默认空间是否公开;创建管理员账号(姓名、邮箱、认证方式选 Password、密码)
4/start/4SMTP 邮件服务器设置(可留空跳过,后续在管理面板补配)

第 3 步的管理员账号创建表单关键字段:adminName(姓名)、adminEmail(管理员邮箱,逗号分隔可填多个)、authMethod(认证方式,默认 password)、adminPassword(密码,最少 8 位且需通过强度检查)。本文使用演示账号 admin / q1w2e3r4(邮箱 admin@scoold.local)。

命令行完成第 3 步的等价操作:

curl -sS -c cookies.txt -X POST http://localhost:8131/start/site-setup \
  --data-urlencode 'appName=Scoold' \
  --data-urlencode 'hostUrl=http://localhost:8131' \
  --data-urlencode 'isDefaultSpacePublic=true' \
  --data-urlencode 'adminName=admin' \
  --data-urlencode 'adminEmail=admin@scoold.local' \
  --data-urlencode 'authMethod=password' \
  --data-urlencode 'adminPassword=q1w2e3r4' \
  -o /dev/null -w 'status:%{http_code} loc:%{redirect_url}\n'

实测回显:

status:303 loc:http://localhost:8131/start/4

303 跳转到第 4 步即站点设置提交成功。第 4 步 SMTP 可直接提交空表单完成向导:

curl -sS -b cookies.txt -c cookies.txt -X POST http://localhost:8131/start/smtp-setup \
  -o /dev/null -w 'status:%{http_code} loc:%{redirect_url}\n'

实测回显:

status:303 loc:http://localhost:8131/

跳回首页说明向导结束。此时 Scoold 日志会记录向导写入的配置项:

2026-10-30 09:21:10 [INFO ] Configuration property 'app_name' was modified by user 1.
2026-10-30 09:21:10 [INFO ] Configuration property 'host_url' was modified by user 1.
2026-10-30 09:21:10 [INFO ] Configuration property 'is_default_space_public' was modified by user 1.
2026-10-30 09:21:10 [INFO ] Configuration property 'admins' was modified by user 1.
2026-10-30 09:21:10 [INFO ] Configuration property 'password_auth_enabled' was modified by user 1.

3.3 管理员登录验证

向导创建的账号即管理员。退出会话后可用密码登录验证:

curl -sS -c cookies.txt -X POST http://localhost:8131/signin \
  --data-urlencode 'username=admin@scoold.local' \
  --data-urlencode 'password=q1w2e3r4' \
  --data-urlencode 'provider=password' \
  --data-urlencode 'access_token=password' \
  -o /dev/null -w 'status:%{http_code} loc:%{redirect_url}\n'
curl -sS -b cookies.txt http://localhost:8131/ -o /dev/null -w 'home:%{http_code}\n'

实测回显:

status:303 loc:http://localhost:8131/
home:200

登录后首页返回 200,页面右上角出现个人入口与退出链接,且管理员账号自带版主(moderator)权限标识。

四、部署验证

4.1 服务健康检查

Para 提供免签名健康端点,Scoold 首页在初始化完成后应返回 200:

curl -sS http://localhost:8132/v1/_health
curl -sS http://localhost:8132/v1/_setup
curl -sS -o /dev/null -w 'scoold:%{http_code}\n' http://localhost:8131/

实测回显:

{"message":"healthy"}
{"message":"All set!"}
scoold:200

/v1/_health 返回 healthy、/v1/_setup 返回 All set!,双服务链路完整。

4.2 业务冒烟:提问

登录态下发布一个测试问题并验证其出现在问题列表:

curl -sS -b cookies.txt -X POST http://localhost:8131/questions/ask \
  --data-urlencode 'space=' \
  --data-urlencode 'title=部署验收测试问题' \
  --data-urlencode 'body=这是一条用于验证 Scoold 部署成功的测试问题正文,验证完成后可删除。' \
  --data-urlencode 'tags=测试' \
  -o /dev/null -w 'ask:%{http_code} loc:%{redirect_url}\n'

实测回显(303 跳转到新问题详情页即成功):

ask:303 loc:http://localhost:8131/question/2026971254229045248/部署验收测试问题

4.3 JVM 堆参数验证

两个服务都是 Java 进程,进入运行实例确认堆上限已按 2.2 节配置生效:

docker exec scoold-svc ps -ef | grep [j]ava
docker exec para-svc ps -ef | grep [j]ava

实测回显:

    1 root      0:07 java -Dconfig.file=/scoold/application.conf -Dscoold.autoinit.para_config_file=/scoold/para-application.conf -Dscoold.para_endpoint=http://para:8080 -Xms256m -Xmx512m -Djava.security.egd=file:/dev/./urandom -jar scoold.jar
root           1       0 35 09:39 ?        00:00:10 java -Dconfig.file=/para/application.conf -Dloader.path=/para/lib -Xms256m -Xmx512m --add-modules jdk.incubator.vector --enable-native-access=ALL-UNNAMED -jar para.jar

两个进程命令行中均可见 -Xms256m -Xmx512m。若需调整堆大小,改 Compose 文件中的 JAVA_OPTS 后执行 docker compose up -d 重建即可,数据在命名卷中不受影响。

4.4 重启韧性验证

docker compose restart
sleep 20 && curl -sS http://localhost:8132/v1/_health && echo

实测重启后健康端点恢复 healthy,且管理员会话 Cookie 与已发布内容全部保留——H2 数据在命名卷、运行时配置在 bind 文件、会话凭据由 app_secret_key 签发,三者均持久化。

五、日常运维

5.1 升级

固定版本组合升级三步:改 Compose 文件中两个 image 的 tag → docker compose pull → docker compose up -d。务必 Scoold 与 Para 成对升级(版本配套关系见 1.2 节)。升级前建议先做 5.2 节的备份。

5.2 备份与恢复

Scoold 管理面板内置备份恢复:管理员登录后进入 Admin → Backup & Restore,可将站点内容导出为压缩包,并支持从导出包恢复。页面同时提供数据导入入口(表单提交至 /admin/import)。除应用层备份外,文件层备份直接打包 Para 的两个命名卷即可:

docker run --rm -v scoold-1.70.2-stack_paraData:/data -v /opt/backup:/backup alpine \
  tar czf /backup/para-data-$(date +%F).tar.gz -C /data .

(卷名以实际 docker volume ls 输出为准,命名规则为「项目名_卷名」。)

5.3 日志与监控

docker compose logs -f scoold   # Web 应用日志
docker compose logs -f para     # 后端日志

日常巡检关注两类日志行:Configuration property ... was modified by user(管理员改配置的审计记录)与 Created new user ...(新用户注册记录)。

六、排障实录

6.1 注册密码被拒:「Password is not strong enough.」

现象:注册新用户时报错 Password is not strong enough.,看起来普通的密码(如 q1w2e3r4)也被拒。 根因:Scoold 默认密码强度策略为 2(强),由 scoold.min_password_strength 控制,默认值下键盘序列型密码通不过强度评分。内部部署可将其降为 1:管理员进入 Admin → Configuration,搜索 scoold.min_password_strength,改为 1 保存;或提高用户密码复杂度。实测将强度降为 1 后,q1w2e3r4 注册成功。 启示:该参数同时作用于注册与改密流程,公开站点建议保持默认值 2 以上。

6.2 注册表单静默失败与误导性报错

现象:命令行或脚本方式提交注册表单,返回 200 并重新渲染表单,页面报「This email is already registered.」——但该邮箱从未注册过。 根因:Scoold 注册表单带防机器人机制:隐藏字段 timestamp 记录页面渲染时间,提交时校验距渲染已过去至少 7 秒(源码 isSubmittedByHuman 实现:System.currentTimeMillis() - time >= 7000)。自动化提交太快就会落入拦截分支;而拦截分支的报错文案固定显示邮箱相关错误,与真实原因无关,极具误导性。 处置:脚本化注册时先 GET 渲染页面取得 timestamp,等待 8 秒以上再提交,即可正常注册并自动登录。

6.3 未验证邮箱卡住登录:/signin?code=3&error=true

现象:注册流程走完但登录被拒,重定向到 /signin?code=3&error=true;管理员在用户列表看不到该用户。 根因:code=3 对应「认证失败或被取消」。默认配置 scoold.security.allow_unverified_emails = false 时,未完成邮箱验证的账号处于未激活态,无法登录;而验证邮件依赖 SMTP——若 SMTP 未配置(3.2 节第 4 步留空),验证码发不出去,账号就永久卡在未激活态。 处置:管理员进入 Admin → Configuration,将 scoold.security.allow_unverified_emails 改为 true,此后新注册用户即时激活;已卡住的旧账号需重新注册或补配 SMTP 后走验证流程。公开站点不建议长期开启该开关。

6.4 镜像拉取超时

现象:docker pull erudikaltd/para 长时间无进展,/var/lib/docker/tmp 无增长;直连 Docker Hub 域名 curl 超时。 处置:按 1.3 节降级链换用实测可用的镜像源 docker.1ms.run,以全限定名拉取后 docker tag 回官方名。注意 Docker 配置文件中的 registry-mirrors 只对 docker.io 官方命名空间透明加速,第三方组织镜像(如 erudikaltd/*)未被 DaoCloud 收录时会落到直连逻辑,此时显式全限定名拉取是最可靠路径。

6.5 端口与网段冲突

现象:docker compose up 报网段重叠或端口绑定失败。 处置:端口用 ss -ltn 预检;网段用 docker network ls + docker network inspect 预检,10.89.0.0/16 内未被占用的 /24 均可用。多栈共存务必保持每个栈独立的显式项目名(2.3 节)。

七、安全加固建议

  1. HTTPS 反向代理:Scoold 自身提供 HTTP 服务,生产环境前置 Nginx/Caddy 终结 TLS,并把 scoold.host_url 改为对外 HTTPS 地址(向导第 3 步的 Site URL 或配置文件),否则邮件里的链接与 OAuth 回调地址会指向错误协议。
  2. 收紧注册策略:内部部署用 scoold.approved_domains_for_signups 限定可注册的邮箱域名后缀;公开部署保持 allow_unverified_emails = false 并配好 SMTP。
  3. 会话与密钥:scoold.session_timeout(默认 86400 秒)按安全等级调整;回写后的配置文件含实例密钥,权限收敛为 600 并纳入备份加密范围。
  4. 最小暴露:Para 的 8132 端口只为管理与调试提供便利,生产环境若无需直连 Para,可在 Compose 中删除 para 服务的 ports 映射——Scoold 经内部网络 http://para:8080 访问后端,不依赖宿主映射。

部署完成后,后续的参数调优与 API 接入分别见 《Scoold 1.70 配置参数详解》 与 《Scoold 1.70 REST API 使用详解》;组件定位与选型背景可回看 《Scoold 1.70 介绍与选型指南》。