跳转至

ZJUI-Learn 学校服务器正式部署指南(生产环境)

本文基于仓库内官方文档与当前代码配置整理,目标是把本地开发环境迁移到学校服务器并可长期稳定运行。

参考来源(仓库内):

  • docs/running-in-production/setup.md
  • docs/running-in-production/docker-compose.md
  • docs/running-in-production/authentication.md
  • docs/running-in-production/admin-user.md
  • docker-compose-production.yml
  • apps/prairielearn/src/lib/config.ts

1. 先明确部署形态

对学校场景,建议分两阶段:

  1. 阶段A(试运行):单机Docker Compose(快)
  2. 阶段B(正式):单机/小集群 + 域名 HTTPS + 认证 + 备份 + 监控(稳定)

官方文档明确说明:生产部署不自动覆盖高可用/备份,需要你自行建设运维体系。


2. 生产前置条件(学校服务器)

最低建议:

  • Linux服务器(Ubuntu 22.04/24.04)
  • 4C8G启动(并发高建议8C16G+)
  • 系统盘 + 数据盘(课程仓库与数据分离)
  • 公网域名,例如pl.school.edu.cn
  • 80/443 对外,SSH 仅堡垒机或白名单

安装依赖:

sudo apt update
sudo apt install -y git curl ca-certificates gnupg lsb-release

安装 Docker + Compose 插件(官方方式)后验证:

docker --version
docker compose version

3. 拉取项目代码(建议用你的学校维护仓库)

sudo mkdir -p /opt/zjuilearn
sudo chown -R $USER:$USER /opt/zjuilearn
cd /opt/zjuilearn
git clone < 你的学校仓库地址 > ZJUI-Learn
cd ZJUI-Learn

4. 准备持久化目录(非常关键)

docker-compose-production.yml默认只声明了postgres体积与/jobs映射。正式使用请显式规划持久化路径:

sudo mkdir -p /srv/zjuilearn/{courses,jobs,logs,ssh,config,backup}
sudo chown -R $USER:$USER /srv/zjuilearn
chmod 700 /srv/zjuilearn/ssh

5. 生产配置 config.json(必须)

官方支持在仓库根目录放config.json(或启动时--config 指定路径)。

/srv/zjuilearn/config/config.json创建(先最小可用):

{
  "serverCanonicalHost": "https://pl.school.edu.cn",
  "cookieDomain": ".school.edu.cn",
  "trustProxy": true,

  "coursesRoot": "/srv/pl-courses",

  "postgresqlHost": "localhost",
  "postgresqlDatabase": "postgres",
  "postgresqlUser": "postgres",
  "postgresqlPassword": null,

  "redisUrl": "redis://localhost:6379/",

  "secretKey": "REPLACE_WITH_LONG_RANDOM_SECRET",
  "databaseEncryptionKey": "REPLACE_WITH_64_HEX_CHARS",

  "hasOauth": false
}

生成安全随机值示例:

openssl rand -hex 32 # 用于 databaseEncryptionKey(64位hex)
openssl rand -hex 48 # 可用于 secretKey

注意(来自代码校验逻辑):

  • NODE_ENV=productioncookieDomain 必填,且必须以 . 开头
  • databaseEncryptionKey 不能使用默认全 0 值

以上要求可在apps/prairielearn/src/lib/config.ts中看到。


6. 认证配置(正式上线必做)

官方文档给了两类主流方案:

  • 谷歌OAuth2(docs/running-in-production/authentication.md
  • LTI(活动LMS)

6.1 采用 Google OAuth2(示例)

在 Google Cloud 创建 OAuth Web 应用后,把以下配置写入 config.json

{
  "hasOauth": true,
  "googleClientId": "xxx.apps.googleusercontent.com",
  "googleClientSecret": "xxx",
  "googleRedirectUrl": "https://pl.school.edu.cn/pl/oauth2callback"
}

7.覆盖制作(建议新建覆盖文件)

在仓库根目录新建docker-compose.production.override.yml

services:
  pl:
    container_name: pl
    image: prairielearn/prairielearn:latest
    restart: unless-stopped
    ports:
      - '127.0.0.1:3000:3000'
    environment:
      - NODE_ENV=production
      - HOST_JOBS_DIR=/srv/zjuilearn/jobs
    volumes:
      - postgres:/var/postgres
      - /var/run/docker.sock:/var/run/docker.sock
      - /srv/zjuilearn/jobs:/jobs
      - /srv/zjuilearn/config/config.json:/PrairieLearn/config.json:ro
      - /srv/zjuilearn/courses:/srv/pl-courses
      - /srv/zjuilearn/ssh:/root/.ssh
      - /srv/zjuilearn/logs:/PrairieLearn/logs
    extra_hosts:
      - 'host.docker.internal:172.17.0.1'

volumes:
  postgres:

说明:

  • 将3000绑定本机回环,外网经Nginx反代
  • 持久化课程目录,避免容器重建导致课程丢失
  • 挂载SSH密钥,支持课程Git同步

8. 首次启动与健康检查

cd /opt/zjuilearn/PrairieLearn
docker compose -f docker-compose-production.yml -f docker-compose.production.override.yml up -d
docker ps
curl -I http://127.0.0.1:3000/pl/webhooks/ping

返回 200 表示核心服务健康(官方推荐的健康端点)。


9.Nginx反向代理+HTTPS(推荐)

安装Nginx和证书工具(Let's Encrypt):

sudo apt install -y nginx certbot python3-certbot-nginx

Nginx 站点示例 /etc/nginx/sites-available/zjuilearn.conf

server {
    listen 80;
    server_name pl.school.edu.cn;
    client_max_body_size 50m;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 600s;
    }
}

启用并校验:

sudo ln -s /etc/nginx/sites-available/zjuilearn.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

签发证书:

sudo certbot --nginx -d pl.school.edu.cn

获取HTTPS后,请确保config.json中:

  • serverCanonicalHosthttps://pl.school.edu.cn
  • trustProxytrue

10. 创建管理员账号(官方流程)

  1. 先用认证登录一次系统(让用户进入users表)
  2. 进入容器:
docker exec -it pl /bin/bash
psql postgres
  1. 查询用户:
SELECT
  *
FROM
  users;
  1. 将目标 user_id 提升为管理员:
INSERT INTO
  administrators (user_id)
VALUES
  (< user_id >);

该流程来自docs/running-in-production/admin-user.md


11.课程仓库接入(Git同步)

生产环境通常按官方建议使用 Git 维护课程:

  1. 准备SSH密钥(建议专用密钥)
  2. 加入Git平台(GitHub/Gitee/GitLab)仓库部署密钥
  3. ZJUI-Learn 管理页面添加课程(Admin -> Courses)
  4. 课程路径填挂载目录下路径(如/srv/pl-courses/mycourse
  5. 点击 Sync -> Pull from remote git repository

为避免首次连接主机密钥报错,可在config.json设置:

{
  "gitSshCommand": "ssh -o StrictHostKeyChecking=accept-new"
}

12. 上线验收清单(建议逐项打勾)

  • https://pl.school.edu.cn/pl/webhooks/ping 返回 200
  • 登录流程可用(OAuth/LTI)
  • 管理员权限正常
  • 课程可同步、拉取成功
  • 题目预览/提交/评分链路正常
  • 文件上传功能可用
  • 服务重启后课程与数据仍在(持久化验证)

13. 运维必做项(正式投入使用)

13.1 自动拉起

建议以systemd托管撰写:

/etc/systemd/system/zjuilearn.service

[Unit]
Description=ZJUI-Learn ZJUI-Learn Service
After=docker.service
Requires=docker.service

[Service]
Type=oneshot
WorkingDirectory=/opt/zjuilearn/PrairieLearn
RemainAfterExit=true
ExecStart=/usr/bin/docker compose -f docker-compose-production.yml -f docker-compose.production.override.yml up -d
ExecStop=/usr/bin/docker compose -f docker-compose-production.yml -f docker-compose.production.override.yml down
TimeoutStartSec=0

[Install]
WantedBy=multi-user.target

启用:

sudo systemctl daemon-reload
sudo systemctl enable --now zjuilearn

13.2 备份策略(至少)

  • 数据库卷备份(postgres卷)
  • 课程目录备份(/srv/zjuilearn/courses
  • 配置与密钥备份(/srv/zjuilearn/config, /srv/zjuilearn/ssh
  • 日备份 + 异地副本 + 恢复演练

13.3 监控告警(至少)

  • 设备、CPU、内存、磁盘
  • /pl/webhooks/ping HTTP 标记
  • Nginx 5xx 同样
  • 磁盘剩余空间告警(课程仓库和日志增长)

14. 升级流程(推荐停机升级)

官方推荐:停服务 -> 迁移 -> 启服务。

cd /opt/zjuilearn/PrairieLearn
git fetch --all
git checkout <目标版本或分支>
git pull

docker compose -f docker-compose-production.yml -f docker-compose.production.override.yml down
docker compose -f docker-compose-production.yml -f docker-compose.production.override.yml pull
docker compose -f docker-compose-production.yml -f docker-compose.production.override.yml up -d

升级后执行验收清单第 12 节。


15. 你可以直接照抄的最短上线路径(单机)

  1. 准备好服务器+Docker+域名
  2. 克隆仓库到/opt/zjuilearn/ZJUI-Learn
  3. 创建/srv/zjuilearn/{config,courses,jobs,ssh,logs}
  4. 写入 config.json(至少配置域名、cookieDomain、secret、databaseEncryptionKey)
  5. docker-compose.production.override.yml
  6. docker compose ... up -d
  7. 配置Nginx + HTTPS
  8. 登录并提升管理员
  9. 接入课程Git仓库并同步
  10. 完成验收后对外发布