主题
部署
本页是「部署」这一章的入口,只回答一件事:把 Wujies 无界平台装到一台服务器上,要装哪几个包、按什么顺序、装完必须做什么。
当前的交付方式是 1Panel 应用包 + docker compose + 外部中间件。平台自己只提供两个容器(前端 nginx + 后端),MySQL / Redis / RabbitMQ 不在包内、也不打进镜像 —— 它们在安装表单里「从 1Panel 应用商店选一个已装的服务」或「填你自己的外部实例地址」。jar 直跑只用于开发验证与排障(入口是 script/prune/start-host.ps1),交付与生产走 1Panel 包。
先分清两类「包」,它们不是一回事
| 平台包(本页) | 业务应用包 | |
|---|---|---|
| 是什么 | 把平台装成 1Panel 本地应用(前端 nginx + 后端 jar) | 应用市场里的应用:mall / gallery / im / member / pay … |
| 谁产出 | wujies-platform/deploy/tools/build-1panel.ps1 | 发布方 wujies/wujies-plugins/package.ps1 |
| 产物 | deploy/dist/1panel/wujies-platform-1panel-5.6.3.tar.gz | <code>-<version>.zip(含 signature.txt) |
| 装在哪 | 1Panel → 应用商店 → 本地应用 | 平台内「应用上架」上传,再在「应用市场」安装 |
两者通过应用目录衔接:业务应用包上架并发布后,目录里才有它的版本,市场里才有东西可装。 这条链路的起点是 打包与上架。
交付产物:四个 1Panel 应用包
| 包 | 是什么 | 什么时候装 |
|---|---|---|
wujies-platform-server | 官方版:目录在自己的库里(catalog.mode=local)、含上架端、对外提供 /app/catalog/** | 单机自用;或多部署里那台「目录服务」 |
wujies-platform-client | 用户版:没有上架端,目录从官方版读(catalog.mode=remote,写死) | 交付给客户,且已经有一台官方版在跑 |
wujies-snailjob-server | 定时任务调度中心(SnailJob 服务端 + 控制台 /snail-job) | 要跑定时任务:订单自动取消 / 自动收货、优惠券状态与过期、促销启停、统计刷新、积分过期 |
wujies-monitor-admin | 服务监控中心(Spring Boot Admin,/admin) | 想在线看健康、JVM、日志级别、配置 |
后两个是独立的应用包,各有自己的容器与(调度中心还有)自己的数据库。主包安装表单里填上它们的地址即启用,留空就不启用。当前端在同一个 1panel-network 上时,地址固定填 snailjob-server 与 http://monitor-admin:9090/admin(两个包各带一个固定网络别名,不用去查面板随机生成的容器名)。
官方版与用户版是同一个 jar 靠配置扮演两个角色,不是两个 fork —— 差别只在目录从哪读、上架端开不开。选型与目录集中见 多部署与目录服务。
主包里有什么
主包只有两个容器:
| 服务 | 容器名 | 端口 | 说明 |
|---|---|---|---|
frontend(主服务) | ${CONTAINER_NAME} | ${PANEL_APP_PORT_HTTP} → 80 | nginx:托管前端 dist、反代 /prod-api/ 到后端、按 /remote-apps/ 提供远程应用产物 |
backend | ${CONTAINER_NAME}-backend | 8080;官方版额外对公映射 ${PANEL_APP_PORT_API} | 后端 jar,启动前先解析中间件地址、首次启动初始化数据库 |
中间件一个都不在包里。每个中间件在安装表单里都是两条路,解析规则是「外部字段非空 → 用外部;否则用面板选的服务;都空 → 容器启动失败并打印原因」,这段逻辑写在 deploy/docker/backend/entrypoint.sh 里(compose 与 Spring 都表达不了这种条件)。
后端容器里有两个卷必须记住,它们把「后端写产物」和「nginx 读产物」连起来:
| 宿主(相对应用目录) | 容器内 | 谁在用 |
|---|---|---|
./data/plugins-dist | /app/plugins-dist | 插件 jar 落位目录 = app-market.deploy.plugin-dir,运行期由插件运行时加载 |
./data/remote-apps | /app/remote-apps(后端读写)、/var/www/remote-apps:ro(nginx 只读) | 远程应用前端产物 = app-market.deploy.frontend-dir |
这两行挂的不是同一个宿主目录,表现就是「安装成功、菜单也在,点进去 404」。完整卷表与配置项见 后端部署 与 前端部署与 Nginx。
部署要走完的六步
① 打包(开发机 / CI)
powershell
# 全量:前端 vite build --mode docker + 后端 mvn install + 组装 + 打 tar.gz
powershell -ExecutionPolicy Bypass -File wujies-platform\deploy\tools\build-1panel.ps1
# 只改了后端 Java
powershell -ExecutionPolicy Bypass -File wujies-platform\deploy\tools\build-1panel.ps1 -SkipFrontend
# 只改了 SQL / data.yml / compose(最常用,几十秒,不用重建镜像)
powershell -ExecutionPolicy Bypass -File wujies-platform\deploy\tools\build-1panel.ps1 -SkipFrontend -SkipBackend前提是 Node 22+、JDK 17($env:JAVA_HOME)、Maven。产出在 deploy/dist/1panel/:apps/(四个包)、docker/(四个镜像构建上下文)、wujies-platform-1panel-5.6.3.tar.gz(上传到服务器的那一个文件)。
- ⚠️
build-1panel.ps1必须保持 UTF-8 with BOM:Windows PowerShell 5.1 对无 BOM 的脚本按 ANSI 解码,中文注释会连带吃掉下一行。 - 改版本号要同时动四处:脚本的
$Version、包内5.6.x/目录名、compose 里的镜像 tag、deploy/tools/gen-appstore-data.mjs的VERSION。 - 包里的初始化 SQL 是文件(
sql/files/,只读挂进容器),不是打进镜像的;只有 jar 与前端dist/需要重建镜像。
② 构建镜像(有 Docker 的那台机器)
1Panel 本地应用只负责拉镜像,镜像要你自己构建:
bash
cd /root/pkg/docker/backend && docker build -t wujies-platform/backend:5.6.3 .
cd ../frontend && docker build -t wujies-platform/frontend:5.6.3 .
# 只有装了可加装的两个包才需要下面两个
cd ../snailjob && docker build -t wujies-platform/snailjob-server:5.6.3 .
cd ../monitor && docker build -t wujies-platform/monitor-admin:5.6.3 .- 面板安装时总会先
docker pull一遍。日志出现拉取镜像 失败 … denied紧跟着「镜像已存在,使用存量镜像」不是错误(wujies-platform/*会被解析成 Docker Hub 上的同名命名空间);想省掉那一分钟左右,在安装抽屉的「高级」里取消勾选「拉取镜像」。 - 多机部署 / 上架官方商店必须让拉取能成功:把镜像 tag 到你自己的仓库并推到可公开拉取的地方,同时把包内 compose 的
image:一起换掉。私有仓库还要先在面板「容器 → 仓库」里加凭据。
③ 传进面板
bash
scp wujies-platform-1panel-5.6.3.tar.gz root@<host>:/root/
ssh root@<host> 'mkdir -p /root/pkg && tar -xzf /root/wujies-platform-1panel-5.6.3.tar.gz -C /root/pkg'
ssh root@<host> 'cp -r /root/pkg/apps/* /opt/1panel/resource/apps/local/ && chmod -R a+rX /opt/1panel/resource/apps/local/wujies-platform-*'然后在面板里 应用商店 → 本地应用 → 同步/刷新,四个包就出现了。
别用 scp 直接传进资源目录
Windows 的 OpenSSH scp 建出来的目录是 0700,容器里的非 root 用户读不到挂载进去的文件。传完一律 chmod -R a+rX;走 tar 解包不会踩(推荐)。
④ 装主包,填安装表单
| 分组 | 字段 | 要点 |
|---|---|---|
| 数据库 | 数据库服务 | 下拉只提供 MySQL:平台初始化 SQL 通篇 utf8mb4_0900_ai_ci,MariaDB 没有这个排序规则,装了也没用 |
| 数据库名 / 用户 / 密码 | 点安装时面板自动生成 wujies_<6位随机> 并自动建库 + 授权。⚠️ 装完别改:这三个值同时写在 MySQL 里和容器的 .env 里,只改一边就是「等待 MySQL 超时」 | |
| 数据库地址(外部)等 | 填了优先用外部(云数据库、已有集群)。⚠️ 外部库要你自己先建库并授权,面板不会替你建,入口脚本只会 CREATE DATABASE IF NOT EXISTS | |
| Redis | Redis 服务 | 必填。⚠️ 面板里那个 Redis 没设密码时这一栏是空的、而它是必填项 —— 先去给 Redis 设密码 |
| RabbitMQ | RabbitMQ 服务等 | 选填,留空应用照常启动,只是消息中心 / 站内信不可用。⚠️ 面板不会把账号密码带过来,默认按官方应用的 rabbitmq / rabbitmq 预填,改过就去「应用商店 → 已安装 → RabbitMQ → 参数」抄 |
| 访问 | 外部访问地址 | 形如 http://<host>:8080,第三方登录回调等对外链接用它 |
| 前端访问端口 / 后端接口端口 | 官方版要暴露后端端口给用户版读目录(默认 18080);用户版不需要 | |
| 应用市场 | 应用包检查模式 | 默认 warn。切 enforce 的前提是 public-key 已配置 —— 没配公钥时 enforce 会拒绝所有包(包括你自己签的) |
| 目录服务令牌 | 用户版必填且要手抄官方版那个值;两端不一致的表现是市场列表 500「目录接口令牌校验失败」 | |
| 可加装 | 调度中心地址 / 监控中心地址 | 留空 = 不启用。装了那两个包就填 snailjob-server 与 http://monitor-admin:9090/admin |
官方版与用户版的两个必配对项
- 用户版的「官方版地址」要写官方版后端端口(
http://<官方版IP>:18080),不是前端端口; - 两端的「目录服务令牌」必须是同一个长随机串。
用户版写死 catalog.mode=remote:它是 client 形态,配 local 会直接启动失败并写明该改哪一行(MarketEditionStartupCheck)。
⑤ 看首次启动的初始化日志
bash
# 先定位实例目录(<实例名> 就是面板「已安装」里那个名字),形如
# /opt/1panel/apps/local/<包名>/<实例名>/
cd /opt/1panel/apps/local/wujies-platform-server/<实例名>
docker compose ps
docker compose logs --tail=200 backend | grep '\[entry\]'期望看到(全新初始化):
[entry] MySQL=mysql:3306/wujies_xxxxxx Redis=redis:6379 RabbitMQ=rabbitmq:5672
[entry] 等待 MySQL 就绪…
[entry] 首次启动:初始化数据库 wujies_xxxxxx
[entry] 导入 01-platform.sql
[entry] 导入 02-app-market.sql
[entry] 导入 03-app-catalog.sql
[entry] 应用目录:app_info=N 行 app_version=M 行
[entry] 数据库初始化完成,已写入标记 platform.init.version=5.6.3
[entry] 启动应用(profile=prod)顺序固定:01-platform.sql(平台表 + 平台数据)→ 02-app-market.sql(应用市场的表与列)→ 03-app-catalog.sql(应用目录种子)。判据是 sys_config 里有没有 platform.init.version 这一行(不是「有没有 sys_user 表」:半途失败的库会缺表但已有表)。
导入用 mysql --force 容忍个别语句报错,随后做两道复核:关键表全检(缺一张就不写标记、让容器失败 —— 宁可安装当场失败,也不要交付一个残库)与目录数据非空(app_info 为 0 行同样失败)。第二次启动看到的是「数据库已初始化过…跳过导入」。
重来一遍不要 DROP DATABASE
面板建库时只给了 GRANT ALL PRIVILEGES ON `wujies_xxxxxx`.*,没有全局 CREATE。库一删,入口脚本那句 CREATE DATABASE IF NOT EXISTS 就建不回来,导入全部落到不存在的库上,最后卡在「缺 N 张关键表」起不来。 要重来请清空该库里的表(保留库与授权)再重启容器;只改数据的话更省事:删掉 platform.init.version 那一行再重启,脚本本身幂等。
⑥ 装完的收尾
- 对象存储:系统工具 → 系统配置 → 文件存储配置,启用一种(MinIO / 阿里云 / 腾讯云 / 七牛)。默认所有配置都是停用状态,所以刚装完上传应用包与图片会失败 —— 这是刻意的,不替用户决定用哪个存储。另外装了 1Panel 的 MinIO 应用时,
domain填http://<host>:<前端端口>/minio走本应用 nginx 反代,并把 compose 里 frontend 的MINIO_HOST改成 MinIO 容器名。 - 签名公钥与检查模式:发布方生成密钥(
wujies/wujies-plugins/package.ps1 -Keygen),把公钥贴进app-market.security.public-key,再按发布说明重建宿主 jar 并重启,最后把表单里的检查模式改成enforce。见 密钥与签名 与 安全校验模式。 - 上架并安装业务应用:官方版 →「应用上架」上传业务应用包 → 建版本 → 发布;再回到「应用市场」安装。全新部署的市场里已经有第一方应用(目录种子
03-app-catalog.sql随包),不需要重新上架一遍。 - 可加装的两个服务:调度中心控制台在
http://<host>:8800/snail-job/(种子账号admin/admin,进去就改),任务定义要在「任务管理 → 导入」里导script/sql/snailjob-task-export.json;监控中心在http://<host>:9090/admin(HTTP Basic,账号密码与主包表单里填的一致)。⚠️ 两者都是「端口 + context-path」,根路径 404 是正常的,不是装坏了。
部署前检查清单
- [ ] 1Panel 已就绪;面板里已装 MySQL(8.x,排序规则
utf8mb4_0900_ai_ci)与 Redis(已设密码);RabbitMQ 选填 - [ ] 一台有 Docker 的机器用于构建镜像(或镜像已推到可拉取的仓库)
- [ ] 打包机满足 Node 22+ / JDK 17 / Maven,且
build-1panel.ps1仍是 UTF-8 with BOM - [ ] 服务器内存按主包 README 的规格准备(后端 + nginx ≥ 2GB,中间件另计)
- [ ] 包里有
sql/files/03-app-catalog.sql(缺了打包时会Write-Warning,新部署的市场会是空的) - [ ] 多部署时:官方版与用户版用的是同一个目录服务令牌,且用户版填的是官方版后端端口
- [ ] 对象存储、签名公钥这两件收尾事项已经安排人做(否则上传会失败、
enforce会拒包) - [ ] 动过已有部署前看过 升级与补丁 的备份清单
上线前必须替换的凭据
1Panel 路线下,库名 / 账号 / 密码、目录服务令牌都由面板随机生成,不用你操心。下面这些是仓库里带着的开发验证值,正式对外前必须逐个换掉;本页只列位置。
| 位置 | 换成什么 | 不做会怎样 |
|---|---|---|
application.yml 的 sa-token.jwt-secret-key(仓库里是 abcdefghijklmnopqrstuvwxyz) | 自己生成的长随机串 | 任何人可伪造登录态 |
api-decrypt.publicKey / privateKey(与前端 .env.* 成对,api-decrypt.enabled 当前为 false) | 重新生成一对,前后端同时换,要启用接口加密就先换 | 接口加密形同虚设 |
app-market.security.public-key | 自己 keygen 出来的公钥(源码注释已写明现有值是开发验证阶段生成的) | 别人能用旧私钥签出被你认可的包 |
wujies/wujies-plugins/keys/private.pem | 自己的私钥,留在发布方并备份到仓库之外 | 换钥会让旧钥签过的包全部作废;私钥丢了只能重签所有包 |
前端 .env.production 的 VITE_APP_BASE_API | 自己的接口地址(容器路线用的是 .env.docker 的 /prod-api,不受影响) | 前端打到别人的环境 |
调度中心控制台账号(script/sql/ry_job.sql 的种子是 admin / admin)与监控中心账号密码 | 自己的值 | 默认口令被人登进控制台 |
application-prod.yml 里的数据源 / Redis / RabbitMQ / 监控中心账号 / SnailJob 接入令牌 | jar 直跑时必须自己改;1Panel 路线由环境变量覆盖,不用管 | 连到开发库;密码泄露 |
三条底线
wujies/wujies-plugins/keys/已在.gitignore里 —— 不要为了「方便」把它提交进仓库;- 公钥不是秘密,可以放配置文件;私钥只留在发布方,且不要放在部署机上;
public-key、api-decrypt的密钥、sa-token.jwt-secret-key都是启动期读入的 —— 改完必须重建宿主 jar 再重启,只改 yml 文件不生效。