ContiNew

快速部署

从环境准备、打包到 Docker Compose 与 Nginx 配置,完成 ContiNew Admin 的生产部署,并附上线前检查清单。

本文是 4.x 的归档文档(冻结于 v4.2.0)。该分支只接收勘误修正, 内容基本不再变动;文中的源码路径、配置项与版本号均以 4.2.x 为准,不建议用于新项目。

新项目请查看 5.x 最新文档。已在 4.2.x 上运行的项目,本文仍是可靠依据。

本文以仓库自带的 docker/ 目录为主线,走「打包 → 产物落位 → Docker Compose 编排 → Nginx 反向代理 → 验收」的完整路径。不使用 Docker 的场景可以只参考打包与 Nginx 两节。

部署前先确认你已经能在本机跑通并登录(见快速开始)。生产环境首次启动请留足观察时间:Liquibase 会自动建表并灌入初始数据,首次启动比平时慢。

环境要求

组件版本说明
JDK17Spring Boot 3 的最低要求,打包与运行都需要
Maven3.9.16项目用 Maven Wrapper 锁定,直接用 ./mvnw
Node.js / pnpmNode 22 / pnpm 9.3.0仅构建前端时需要
MySQL8.0.42也支持 PostgreSQL,见下方切换步骤
Redis7.2.8会话、缓存、验证码、限流共用
Nginx1.27.0前端静态资源托管与后端反向代理
Docker / Docker Compose任意近期版本仅容器化部署需要

第 1 步:生产配置

后端

后端 Dockerfile 基于 application-prod.yml 运行,部署前逐项确认:

  • 数据源连接池配置;
  • SQL 日志(prod 默认关闭);
  • 接口文档随 nextdoc4j.production: ${application.production} 进入屏蔽模式;
  • 日志级别(prod 默认 INFO),需要改日志保留策略时同步改 logback-spring.xml 的 <springProfile name="prod"> 段;
  • 跨域白名单。continew-starter.web.cors 只放行 ${application.url},改了前端域名就要改 application.url:
continew-starter.web.cors:
  enabled: true
  allowed-origins:
    - ${application.url}
  allowed-methods: '*'
  allowed-headers: '*'
  exposed-headers: '*'

前端

pnpm build 使用 .env.production,确认 VITE_API_BASE_URL 与 VITE_API_WS_URL 指向实际后端地址(开启 SSL 用 https / wss)。前后端同域名部署时改用 VITE_API_PREFIX=/api + 后端地址,并放开 Nginx 里 /api/ 的代理配置;同源部署下 Refresh Token Cookie 天然同源,cookie-allowed-origins 的配置压力最小。

前端环境变量要点见前端开发,完整清单见环境变量参考。

第 2 步:打包

后端

后端提供胖瘦两种打包方式,由 continew-server/pom.xml 的 Maven profile 控制,默认激活 thin-jar。

./mvnw clean package

瘦包把主程序、依赖、配置文件拆到三个目录,产物在 continew-server/target/app/:

app/
├── bin/continew-admin.jar    # 主程序(仅业务类)
├── config/                   # 配置文件、db 脚本、模板、logback
└── lib/                      # 全部第三方依赖 jar

配置文件外置后改配置不用重新打包,compose 也是把宿主目录挂载到 /app/config/ 来覆盖配置。

前端

前端在独立仓库 continew-admin-ui 中:

pnpm install
pnpm build

产物在 dist/,部署时把整个目录交给 Nginx(compose 中挂载到 /usr/share/nginx/html/)。

pnpm build 会先跑 vue-tsc --noEmit 做类型检查再执行 vite build,类型错误会直接中断构建。VITE_CLIENT_ID 必须与后端「系统管理 → 系统配置 → 客户端配置」中某条启用状态的客户端 ID 一致,否则登录会被拒绝。

第 3 步:产物落位

瘦包模式下这一步最关键,漏掉依赖目录会导致容器起不来。把 continew-server/target/app/ 下的三个目录整体复制到 docker/continew-admin/:

docker/continew-admin/
├── bin/continew-admin.jar    # 来自 app/bin
├── config/                   # 来自 app/config(外置配置放这里)
└── lib/                      # 来自 app/lib(必须复制,缺了会 ClassNotFound)

docker/continew-admin/Dockerfile 只把 ./bin/*.jar 复制进镜像,依赖与配置靠 compose 的 volumes 挂载(/docker/continew-admin/lib/:/app/lib/)。宿主目录 /docker/continew-admin/lib/ 必须是上面复制过来的真实依赖目录,只创建空目录会让主程序加载不到任何依赖。

需要定时任务时,把 continew-extension/continew-extension-schedule-server/target/continew-extension-schedule-server.jar 复制到 docker/schedule-server/ 下(也可以直接用 Snail Job 官方镜像部署,二者等价)。前端 dist/ 内容复制到 /docker/continew-admin/web/。

第 4 步:编排与启动

docker/ 提供完整编排样例,包含五个服务。

服务镜像端口职责
mysqlmysql:8.0.423306业务数据库(含注释掉的 postgres:14.2 备选)
redisredis:7.2.86379缓存与会话
continew-servercontinew-server:4.2.0(本地构建)18000、17889后端主服务,17889 为 Snail Job 客户端端口
continew-webnginx:1.27.080、443前端静态资源与后端反向代理
schedule-serverschedule-server(本地构建)18001、17888Snail Job 调度中心,可选

按上一步把产物放到宿主目录,并补齐 docker/redis/conf/redis.conf 的 requirepass、docker/nginx/conf/nginx.conf 的 upstream admin-server.server、监听端口、server_name 与 SSL 证书路径。端口修改后,所有涉及的配置文件都要同步改。

编辑 docker/docker-compose.yml 的 environment,把占位值换成真实值。必填的凭据与密钥包括 DB_USER、DB_PWD、REDIS_PWD、ACCESS_TOKEN_JWT_SECRET、REFRESH_TOKEN_SECRET、FIELD_ENCRYPT_PASSWORD、FIELD_ENCRYPT_PUBLIC_KEY、FIELD_ENCRYPT_PRIVATE_KEY,启用任务调度还要 SCHEDULE_TOKEN、SCHEDULE_PASSWORD。两个 Token 密钥都要高熵随机、至少 32 字符且互不相同。

调度相关的地址按容器拓扑配置:SCHEDULE_HOST: schedule-server、SCHEDULE_PORT: 17888、SCHEDULE_API_URL: http://schedule-server:18001/snail-job。SCHEDULE_API_URL 缺省是 http://127.0.0.1:18001/snail-job,在容器里会指向后端自身而不是调度中心,必须显式覆盖。

启动并验收:

cd docker
docker compose up -d
docker compose ps
docker compose logs -f continew-server

MySQL 与 Redis 配了健康检查,后端会等两者就绪后启动。首次启动由 Liquibase 自动建表与灌入初始数据,看到 ContiNew Admin server started successfully. 后访问前端域名验证,用初始账号 admin / admin123 登录并立即改密码。

后端镜像基于 bellsoft/liberica-openjdk-debian:17.0.14,JVM 参数预置 ZGC、Metaspace 上限 256MB,OOM 时自动向 /app/logs/oom.hprof 写堆转储(该目录已挂载到宿主,容器重建后仍可拿到现场)。

不使用任务调度时可以不启动 schedule-server,并把 application-prod.yml 的 snail-job.enabled 改为 false;prod 默认为 true,缺失调度中心会让任务相关功能报错。

Nginx 配置

docker/nginx/conf/nginx.conf 采用双站点结构,前后端各一个 server 块,共用一套 SSL 证书。

后端站点(api.continew.top)把请求反代到 upstream admin-server(172.17.0.1:18000),三个要点:

  • proxy_http_version 1.1 配合 Upgrade 头转发,WebSocket(/websocket)才能工作;
  • X-Forwarded-For 显式覆盖为 $remote_addr,不信任客户端自带的转发头,防止伪造来源 IP 绕过限流;
  • client_max_body_size 100m,要大于等于后端 spring.servlet.multipart 的 20MB 上限,分片上传场景按需再调大。
location / {
    proxy_pass http://admin-server/;
    proxy_ignore_client_abort on;
    proxy_http_version 1.1;

    proxy_set_header Upgrade           $http_upgrade;
    proxy_set_header Connection        "Upgrade";
    proxy_set_header Host              $host;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Forwarded-For   $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
}

前端站点(admin.continew.top)是标准 SPA 托管,try_files $uri $uri/ /index.html 保证 history 路由刷新不 404。两个站点的 80 端口都 301 到 HTTPS。不用独立 API 域名时,改用前端站点内 /api/ 前缀代理后端,配置文件里留了注释样例。

后端经 Nginx 反代后,必须在 continew-starter.refresh-token 中配置 trusted-proxy-addresses 指向 Nginx 出口地址。不配置的话后端按连接对端地址限流,全站用户共享 Nginx 这一个 IP 的限流桶,/auth/refresh 容易被打满返回 429。

切换到 PostgreSQL

新项目直接选择 PostgreSQL 时,需要改四处,只改 database-id 不够:

  1. application.yml 的 mybatis-plus.database-id 改为 pgsql(分页方言靠它区分);
  2. 数据源 URL 与驱动:jdbc:postgresql://host:5432/db,驱动 org.postgresql.Driver,application-prod.yml 与 application-dev.yml 都要改;
  3. Liquibase 的 db.changelog-master.yaml 把 MySQL 的 include 切到 PostgreSQL 的 include,两份脚本在 db/changelog/mysql 与 db/changelog/postgresql;
  4. 代码生成器的类型映射按 PostgreSQL 方言提供(application-generator.yml 已内置 int2 / int4 / int8 等映射)。

已有 MySQL 库迁移到 PostgreSQL 属于数据迁移,不在文档范围。建库字符集建议 UTF8,排序规则与 MySQL 场景保持一致再校验分页与排序行为。

生产检查清单

上线前逐项过一遍,全部来自 prod 配置与安全相关的硬约束。

凭据与密钥

  • DB_PWD、REDIS_PWD 已通过环境变量注入,prod 无默认值,缺失即启动失败
  • ACCESS_TOKEN_JWT_SECRET 与 REFRESH_TOKEN_SECRET 为两个不同的高熵随机值(至少 32 字符)
  • FIELD_ENCRYPT_PASSWORD 与 RSA 密钥对(FIELD_ENCRYPT_PUBLIC_KEY / FIELD_ENCRYPT_PRIVATE_KEY)已注入,且不与 dev 示例密钥复用
  • 第三方登录默认关闭;启用时设置 JUSTAUTH_ENABLED=true,并只为实际使用的平台注入 JUSTAUTH_<平台>_CLIENT_ID 与 JUSTAUTH_<平台>_SECRET
  • SCHEDULE_PASSWORD、SCHEDULE_TOKEN 已注入(启用任务调度时)

配置

  • PROFILES_ACTIVE=prod,application.url 指向真实前端域名
  • 跨域白名单仅放行 ${application.url},不再是 *
  • cookie-secure: true 已生效,站点全量 HTTPS
  • trusted-proxy-addresses 已按反代拓扑配置
  • 接口文档已随 application.production: true 进入屏蔽模式
  • VITE_CLIENT_ID 与后端客户端配置一致

基础设施

  • MySQL 已建库(默认 continew_admin),字符集 utf8mb4;Liquibase 首次启动自动建表
  • Redis 已设置密码,bind 不暴露公网
  • Nginx client_max_body_size 不小于后端上传上限
  • 日志目录(/app/logs)已挂载持久化,OOM 堆转储可回取
  • 部署目录权限按最小可用原则设置(不要用 777)

相关源码

目录