docs: 全面更新文档,清理过期内容,对齐最新设计

主要变更:
- README.md: 重写,入口改为一键 install.sh,补充架构图和端口表
- runbook.md: 重写,移除旧脚本引用和内部 agent 规则,补充 nginx 配置和端口对照
- configuration.md: 更新端口表(11224-11231),移除 docs-site 引用,
  补充内置 nginx 说明(nginx-bundled profile)
- deployment-defaults.md: 改为通用模板,移除明文密码、真实 IP 和客户信息
- acceptance-checklist.md: 重写,改为直接 curl 端口验证,补充 license 和 nginx 验收项

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
徐勤民 2026-05-20 16:06:42 +08:00
父节点 f2f9f06bf7
当前提交 a5ecb30bf0
共有 5 个文件被更改,包括 301 次插入383 次删除

112
README.md
查看文件

@ -1,95 +1,67 @@
# XuqmGroup Private Deploy
私有化部署仓库只负责客户环境交付,不包含业务源码和 demo 前后端。
# XuqmGroup 私有化部署
## 快速开始
```bash
./scripts/configure.sh
vim .env
vim config/secrets.env
./scripts/install.sh --profile base
./scripts/healthcheck.sh
curl -fsSL https://xuqinmin.com/xuqmGroup/XuqmGroup-PrivateDeploy/raw/branch/main/install.sh \
-o install.sh && bash install.sh
```
生产部署前必须完成:
脚本自动完成:依赖检测 → 配置生成 → 镜像拉取 → 容器启动 → 租户初始化(新建或迁移)→ 全量验证。
- 配置镜像仓库 `REGISTRY` 和版本 `IMAGE_TAG`
- 选择 MySQL/Redis 模式:`external` 使用客户自备服务,`managed` 由脚本创建容器服务。
- 配置控制台、文档站、文件、IM、Push、Update、License 域名。
- 配置 SMTP、Push 厂商、应用市场发布凭据。
- 确认证书和反向代理策略,默认 Nginx 配置只作为模板入口。
部署完成后根据输出的端口表配置宿主机 nginx,详见 [docs/runbook.md](docs/runbook.md)。
## 部署模式
## 部署架构
MySQL、Redis 支持两种模式:
- `external`:客户自备连接,脚本只校验连通性和权限。
- `managed`:脚本新建服务,自动创建数据库、账号、密码和数据目录。
生产环境默认推荐 `external/external`
托管模式示例:
```bash
./scripts/install.sh --profile base --mysql-mode managed --redis-mode managed
```
用户 nginx宿主机
├── 127.0.0.1:11224 tenant-service /api/ /actuator/
├── 127.0.0.1:11225 file-service /file/
├── 127.0.0.1:11226 tenant-web /
├── 127.0.0.1:11227 ops-web /ops
├── 127.0.0.1:11228 im-service /api/im/ /ws/im
├── 127.0.0.1:11229 update-service /api/v1/updates/ /api/v1/rn/
├── 127.0.0.1:11230 license-service /api/license/
└── 127.0.0.1:11231 push-service (厂商回调,按需)
```
外部模式示例:
各服务仅绑定 `127.0.0.1`,外部无法直接访问,只有宿主机 nginx 能代理进去。
```bash
./scripts/install.sh --profile base --mysql-mode external --redis-mode external
```
## 租户初始化方式
## 可选服务
安装脚本启动后交互式选择:
- `base`:基础控制台、运营平台、文档站、文件服务。
- `im`IM HTTP / WebSocket。
- `push`:厂商推送。
- `update`版本管理、RN 热更新、应用市场自动发布。
- `license`License 校验。
- **新建租户**:填写邮箱、用户名、密码,首次启动自动创建
- **迁移租户**:在公有化平台安全中心生成迁移密钥(`pmk_` 开头),粘贴后自动完成导入
后期启用:
## 服务说明
| Profile | 服务 | 说明 |
|---------|------|------|
| base | tenant-service, file-service, tenant-web, ops-web | 必选核心服务 |
| infra-mysql | mysql | 托管数据库 |
| infra-redis | redis | 托管缓存 |
| im | im-service | IM HTTP + WebSocket |
| push | push-service | 厂商推送 |
| update | update-service | 版本管理 + RN 热更新 |
| license | license-service | License 校验 |
| nginx-bundled | nginx | 内置 nginx默认不启动,用户有宿主机 nginx 时不需要) |
## 后期启用/禁用服务
```bash
./scripts/enable-service.sh im
./scripts/enable-service.sh push
./scripts/enable-service.sh update
./scripts/enable-service.sh license
```
禁用服务只修改部署配置并停止对应容器,不删除数据:
```bash
./scripts/disable-service.sh im
```
## 租户迁移
将公有化平台的存量租户迁移到私有化部署(需源 MySQL 网络可达):
```bash
./scripts/migrate-tenant.sh \
--src-host <生产MySQL地址> \
--src-user <用户名> \
--src-password '<密码>' \
--tenant <租户邮箱或用户名>
```
`--dry-run` 只打印 SQL 不执行。详见 `docs/runbook.md`
## 注意事项
- `tenant-service` 运行在容器内 **9001** 端口,nginx 代理必须指向该端口,不是 8080。
- `application.yml` 中数据库 URL 硬编码了生产地址,私有化部署依赖 `docker-compose.yml` 中的 `SPRING_DATASOURCE_*` 覆盖,不能删除 `environment:` 节。
- `docs-site` 镜像可选,不存在时 nginx 和 healthcheck 可正常工作warn 级别)。
- `application.yml` 中数据库 URL 硬编码了生产地址,`docker-compose.yml` 的 `environment:` 节负责覆盖,**不能删除**
- 所有容器绑定 `127.0.0.1`,nginx 中 `proxy_pass` 必须写 `127.0.0.1:1122x`,不能写 `localhost`(部分系统 localhost 解析为 IPv6
## 接手入口
## 文档
- 实时部署进度:`.deploy-state/progress.md`
- 最近运行状态:`.deploy-state/current.json`
- 最近健康检查:`.deploy-state/last-healthcheck.json`
- 脚本审计日志:`logs/audit.log`
- 交付说明:`docs/runbook.md`
- 配置说明:`docs/configuration.md`
- 验收清单:`docs/acceptance-checklist.md`
- [运行手册](docs/runbook.md) — 完整部署流程、nginx 配置、常用运维命令
- [配置说明](docs/configuration.md) — 各配置文件字段说明
- [验收清单](docs/acceptance-checklist.md) — 交付验收检查项

查看文件

@ -1,36 +1,50 @@
# 验收清单
## 基础部署
## 部署流程
- `./scripts/configure.sh` 可重复执行。
- `./scripts/install.sh --profile base` 可完成部署。
- `./scripts/healthcheck.sh` 输出 `PASS` 或明确错误码。
- 文档站加载 `config/sdk/xuqm-private-sdk.json`
- 租户注册入口关闭。
- 首次启动自动创建内置租户。
- [ ] `install.sh` 可一键完成完整部署(含租户初始化)
- [ ] 新建租户模式:账号可正常登录控制台
- [ ] 迁移租户模式:使用迁移密钥(`pmk_`)完成导入,账号和应用数据完整
- [ ] 部署完成后输出端口表和 nginx 参考配置
## 中间件
## 基础服务
- `external` MySQL/Redis 不启动本地容器。
- `managed` MySQL/Redis 自动启动并持久化数据。
- 托管模式自动生成密码并写入 `config/secrets.env`
- [ ] tenant-service 健康:`curl http://127.0.0.1:11224/actuator/health` 返回 200
- [ ] 控制台前端可访问:`curl http://127.0.0.1:11226` 返回 HTML
- [ ] 运营后台可访问:`curl http://127.0.0.1:11227` 返回 HTML
- [ ] 文件服务可访问:`curl http://127.0.0.1:11225/file/health` 返回正常
- [ ] 私有化模式确认:`/api/private/deployment/status` 返回 `"mode":"PRIVATE"`
- [ ] 注册入口关闭:`"tenantRegisterEnabled":false`
## 可选服务
- `im` 可后期独立启用和禁用。
- `push` 可后期独立启用和禁用。
- `update` 可后期独立启用和禁用。
- `license` 可后期独立启用和禁用。
- 禁用任一可选服务时,基础服务可继续运行。
- [ ] im-service 健康:`curl http://127.0.0.1:11228/actuator/health` 返回 200
- [ ] update-service 健康:`curl http://127.0.0.1:11229/actuator/health` 返回 200
- [ ] license-service 健康:`curl http://127.0.0.1:11230/actuator/health` 返回 200
- [ ] push-service 已启动(厂商凭据按需填写)
## 厂商能力
## 中间件
- Push 支持华为、小米、OPPO、vivo、荣耀。
- 应用市场自动发布支持华为、小米、OPPO、vivo、荣耀。
- 厂商凭据缺失时返回明确诊断,不影响基础服务启动。
- [ ] MySQL managed 模式:容器自动启动,数据目录 `data/mysql/` 持久化
- [ ] Redis managed 模式容器自动启动,AOF 持久化
- [ ] 重启容器后数据完整
## License
- [ ] 所有应用在 `app_licenses` 表有对应记录
- [ ] `/api/license/admin/apps/:appKey` 返回 200,不出现 404
## Nginx 配置
- [ ] 宿主机 nginx 配置后,通过外部地址可访问控制台
- [ ] `/api/im/` 路由到 im-service11228
- [ ] `/ws/im` WebSocket 连接正常(需 `Upgrade` 头)
- [ ] `/api/v1/updates/` 路由到 update-service11229,不被 `/api/` 拦截
- [ ] `/api/license/` 路由到 license-service11230,不被 `/api/` 拦截
- [ ] `/file/` 支持大文件上传500MB
## 公有化隔离
- 公有化域名 `dev.xuqinmin.com` 不写入私有化 SDK 配置。
- 私有化改造不影响公有化配置和部署链路。
- 公有化回归通过后才能发布私有化版本。
- [ ] SDK 配置不包含公有化地址 `dev.xuqinmin.com`
- [ ] `config/sdk/xuqm-private-sdk.json` 中所有 URL 指向私有部署地址
- [ ] 私有化改造不影响公有化配置和部署链路

查看文件

@ -2,35 +2,32 @@
## `.env`
部署入口配置,控制镜像版本、服务 profile、域名和 MySQL/Redis 模式
主配置文件,由 `install.sh` 自动生成,控制镜像版本、启用的服务和中间件连接信息
关键字段:
- `REGISTRY`:私有 Docker 镜像仓库。
- `IMAGE_TAG`:本次部署镜像版本。
- `COMPOSE_PROFILES`:启用的服务集合,例如 `base,im,push,update,license`
- `MYSQL_MODE``external` 或 `managed`
- `REDIS_MODE``external` 或 `managed`
- `ENABLE_IM`、`ENABLE_PUSH`、`ENABLE_UPDATE`、`ENABLE_LICENSE`:运行时功能开关。
| 字段 | 说明 |
|------|------|
| `REGISTRY` | Docker 镜像仓库地址 |
| `IMAGE_TAG` | 镜像版本,默认 `latest` |
| `COMPOSE_PROFILES` | 启用的服务集合,默认 `base,infra-mysql,infra-redis,im,push,update,license` |
| `MYSQL_MODE` | `managed`(容器托管)或 `external`(客户自备) |
| `REDIS_MODE` | `managed``external` |
| `CONSOLE_DOMAIN` | 对外访问地址,用于服务间跳转和 SDK 配置 |
## `config/secrets.env`
敏感配置文件,不提交 Git。
敏感配置,权限 600,不提交 Git。
关键字段:
- `MYSQL_PASSWORD`
- `MYSQL_ROOT_PASSWORD`
- `REDIS_PASSWORD`
- `SMTP_PASSWORD`
托管模式下,如果密码为空或为 `change-me`,脚本会自动生成并写回该文件。
| 字段 | 说明 |
|------|------|
| `MYSQL_ROOT_PASSWORD` | MySQL root 密码 |
| `MYSQL_PASSWORD` | 业务账号密码 |
| `REDIS_PASSWORD` | Redis 密码 |
## `config/xuqm.env`
业务服务共享配置,包含私有化运行模式、单租户初始化、域名和基础中间件连接信息。
私有化必须保持:
业务服务容器内配置,所有服务共享。私有化部署必须保持:
```env
DEPLOYMENT_MODE=PRIVATE
@ -38,14 +35,26 @@ TENANT_REGISTER_ENABLED=false
TENANT_BOOTSTRAP_ENABLED=true
```
## Spring Boot 数据库 URL 覆盖(重要)
SDK 对外地址也在此文件配置:
`tenant-service``file-service``application.yml` 中数据库 URL 编译期写死了生产地址。
私有化部署**必须**通过 `docker-compose.yml``environment:` 节覆盖 Spring Boot 配置:
```env
CONSOLE_DOMAIN=http://your-domain-or-ip
SDK_FILE_SERVICE_URL=http://your-domain-or-ip
SDK_IM_API_URL=http://your-domain-or-ip
SDK_IM_WS_URL=ws://your-domain-or-ip/ws/im
```
## `config/tenant/bootstrap.env`
初始租户配置,权限 600。迁移模式下由迁移流程自动覆盖。
## Spring Boot 数据库 URL 覆盖
`application.yml` 中数据库 URL 硬编码了生产地址。私有化部署**必须**通过 `docker-compose.yml``environment:` 节覆盖:
```yaml
environment:
SPRING_DATASOURCE_URL: "jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT:-3306}/${MYSQL_DATABASE:-xuqm_private}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true"
SPRING_DATASOURCE_URL: "jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT:-3306}/${MYSQL_DATABASE:-xuqm_private}?..."
SPRING_DATASOURCE_USERNAME: "${MYSQL_USERNAME:-xuqm}"
SPRING_DATASOURCE_PASSWORD: "${MYSQL_PASSWORD}"
SPRING_DATA_REDIS_HOST: "${REDIS_HOST}"
@ -54,58 +63,62 @@ environment:
SPRING_DATA_REDIS_DATABASE: "${REDIS_DATABASE:-0}"
```
这些 `${VAR}` 在启动时由 Docker Compose 从 `.env` 文件展开,优先级高于 `env_file:` 中的同名变量。
当前 `docker-compose.yml` 已包含上述覆盖,不需要手动修改。
`docker-compose.yml` 已包含此配置,不需要手动修改。
## Nginx 服务端口
## 服务端口
| 服务 | 容器内端口 | nginx 路由 |
|------|-----------|-----------|
| tenant-service | **9001** | `/api/`(兜底),`/actuator/` |
| file-service | **8086** | `/file/` |
| im-service | **8082** | `/api/im/`,`/ws/im/`WebSocket |
| push-service | **8083** | 厂商回调(不直接暴露给前端) |
| update-service | **8084** | `/api/v1/updates/`,`/api/v1/rn/` |
| license-service | **8085** | 内部调用 |
| ops-web | 80 | `/ops` |
| tenant-web | 80 | `/`(根路径) |
各服务容器内端口固定,宿主机端口从 11224 顺序分配:
## 可选服务内部通信
| 宿主机端口 | 服务 | 容器内端口 | nginx 路由 |
|-----------|------|-----------|-----------|
| 11224 | tenant-service | 9001 | `/api/` `/actuator/` |
| 11225 | file-service | 8086 | `/file/` |
| 11226 | tenant-web | 80 | `/`(兜底路由) |
| 11227 | ops-web | 80 | `/ops` |
| 11228 | im-service | 8082 | `/api/im/` `/ws/im` |
| 11229 | update-service | 8084 | `/api/v1/updates/` `/api/v1/rn/` |
| 11230 | license-service | 8085 | `/api/license/` |
| 11231 | push-service | 8083 | 厂商回调(按需) |
im-service 和 update-service 在调用 tenant-service 内部 API 时,需要显式覆盖默认地址:
所有端口绑定 `127.0.0.1`,nginx 需写 `proxy_pass http://127.0.0.1:1122x`
## 容器内部通信
容器间通过 Docker 网络直接使用服务名,不经过宿主机端口:
```yaml
# im-service
environment:
TENANT_SERVICE_URL: "http://tenant-service:9001"
PUSH_SERVICE_URL: "http://push-service:8083"
TENANT_SERVICE_URL: "http://tenant-service:9001"
PUSH_SERVICE_URL: "http://push-service:8083"
# update-service
environment:
SDK_TENANT_SERVICE_URL: "http://tenant-service:9001"
SDK_TENANT_SERVICE_URL: "http://tenant-service:9001"
```
push-service 默认已使用 `http://tenant-service:9001`,无需额外配置
`docker-compose.yml` 已包含上述配置,不需要手动修改
`docker-compose.yml` 已包含上述覆盖,不需要手动修改。
## 内置 nginx可选
## docs-site 镜像
`nginx-bundled` profile 提供内置 nginx 容器,默认不启动。通常用宿主机自己的 nginx 代理到各服务端口。需要内置 nginx 时:
`docs-site` 镜像在部分 ACR namespace 下不存在。`docker-compose.yml` 已将 nginx 对 `docs-site` 的依赖标记为 `required: false`,镜像缺失时 nginx 仍可正常启动,`healthcheck.sh` 将 docs-site 容器计为可选WARN 而非 FAIL
```env
# .env
COMPOSE_PROFILES=base,infra-mysql,infra-redis,im,push,update,license,nginx-bundled
```
## `config/sdk/xuqm-private-sdk.json`
内置 nginx 绑定宿主机 80/443 端口,与宿主机已有 nginx 冲突时不可同时使用。
私有化 SDK 初始化配置,由 `scripts/render-config.sh` 生成。
## `config/vendors/`
文档站和客户应用示例必须使用该文件,不再指向 `dev.xuqinmin.com` 公有化逻辑。
## `config/vendors`
厂商能力配置:
- `push.env`华为、小米、OPPO、vivo、荣耀 Push 凭据。
- `store-submit.env`华为、小米、OPPO、vivo、荣耀应用市场自动发布凭据。
| 文件 | 说明 |
|------|------|
| `push.env` | 华为/小米/OPPO/vivo/荣耀/APNs/FCM 推送凭据,默认全部 `false` |
| `store-submit.env` | 应用市场自动发布凭据,默认全部 `false` |
## `config/mail/smtp.env`
邮件服务配置。生产环境必须使用客户提供的 SMTP 服务。
邮件服务配置,不填则邮件功能不可用,不影响其他服务启动。
## `config/sdk/xuqm-private-sdk.json`
SDK 初始化配置,由 `deploy.sh` 自动生成,客户端应用使用此文件初始化 SDK,不再指向公有化地址。

查看文件

@ -1,6 +1,6 @@
# 私有化部署默认信息
# 部署信息记录模板
本文档记录数字医信私有化部署的默认配置,供运维和对接人员参考
部署完成后将此文件复制填写,**不要将含有真实凭据的版本提交到 Git**
---
@ -8,24 +8,11 @@
| 项目 | 值 |
|------|-----|
| 部署版本 | 2026.05.19-private.1 |
| 部署主机 | 192.168.116.9 |
| 部署版本 | (见 VERSION 文件) |
| 部署主机 | |
| 部署目录 | /opt/xuqm-private |
| 部署时间 | 2026-05-19 |
---
## 访问地址
| 功能 | 地址 |
|------|------|
| 控制台(租户登录)| http://192.168.116.9 |
| 运营后台 | http://192.168.116.9/ops |
| 文档站 | http://192.168.116.9/docs/ |
| API 入口 | http://192.168.116.9/api/ |
| Actuator 健康 | http://192.168.116.9/actuator/health |
> **说明**:采用纯 IP 部署,无需配置域名。局域网内任意机器均可通过上述地址访问完整功能。
| 部署时间 | |
| 外部访问地址 | |
---
@ -33,11 +20,11 @@
| 项目 | 值 |
|------|-----|
| 租户名称 | 数字医信 |
| 登录邮箱 | szyx@bjca.org.cn |
| 登录用户名 | szyx |
| 初始密码 | 与公有化平台相同(迁移时未重置) |
| 迁移来源 | 公有化平台39.107.53.187 |
| 租户名称 | |
| 登录邮箱 | |
| 登录用户名 | |
| 初始密码 | (见 config/secrets.env 或部署时设置) |
| 迁移来源 | 新建 / 公有化平台迁移 |
---
@ -45,76 +32,24 @@
| 应用名称 | App Key |
|----------|---------|
| 医网信 | ak_c6fce237cae94ef5ab71fda6 |
| 临床知识库 | ak_1178fd37b8f54cefb7031744 |
| | |
---
## 服务列表和端口
## 服务端口
### 对外服务(通过 nginx 统一入口)
| 宿主机端口 | 服务 | 容器内端口 |
|-----------|------|-----------|
| 11224 | tenant-service | 9001 |
| 11225 | file-service | 8086 |
| 11226 | tenant-web | 80 |
| 11227 | ops-web | 80 |
| 11228 | im-service | 8082 |
| 11229 | update-service | 8084 |
| 11230 | license-service | 8085 |
| 11231 | push-service | 8083 |
| 服务名 | 内部端口 | nginx 路由路径 | 说明 |
|--------|----------|----------------|------|
| tenant-service | 9001 | `/api/*` `/actuator/*` | 核心 API,认证、租户、SDK 配置 |
| file-service | 8086 | `/file/*` | 文件上传下载,最大 500MB |
| im-service | 8082 | `/api/im/*` `/ws/im/*` | IM HTTP API 和 WebSocket |
| update-service | 8084 | `/api/v1/updates/*` `/api/v1/rn/*` | APP 版本管理和 RN 热更新 |
| license-service | 8085 | 内部调用 | License 有效期校验 |
| push-service | 8083 | 内部调用 | 厂商推送通知 |
| docs-site | 80 | `/docs/*` | 私有化 SDK 文档站 |
| ops-web | 80 | `/ops` | 运营后台前端 |
| tenant-web | 80 | `/` | 控制台前端(兜底路由) |
### 基础设施Docker 内部,不对外暴露)
| 服务名 | 内部端口 | 模式 | 说明 |
|--------|----------|------|------|
| mysql | 3306 | managed | MySQL 8.4,Docker 容器托管 |
| redis | 6379 | managed | Redis 7.4,AOF 持久化 |
---
## Docker Compose Profiles
| Profile | 包含服务 | 说明 |
|---------|----------|------|
| base | tenant-service, file-service, tenant-web, ops-web, docs-site, nginx | 必选核心服务 |
| infra-mysql | mysql | 托管数据库MYSQL_MODE=managed 时启用) |
| infra-redis | redis | 托管缓存REDIS_MODE=managed 时启用) |
| im | im-service | IM 服务(可选) |
| push | push-service | 推送服务(可选) |
| update | update-service | 版本管理服务(可选) |
| license | license-service | License 服务(可选) |
**当前启用的 Profiles**`base,infra-mysql,infra-redis,im,push,update,license`(全量部署)
---
## 数据库
| 项目 | 值 |
|------|-----|
| 主机 | mysqlDocker 服务名) |
| 端口 | 3306 |
| 数据库名 | xuqm_private |
| 业务账号 | xuqm |
| 业务密码 | XuqmMysql@2026 |
| Root 密码 | XuqmRoot@2026 |
| 字符集 | utf8mb4 / utf8mb4_unicode_ci |
| 时区 | +08:00 |
---
## Redis
| 项目 | 值 |
|------|-----|
| 主机 | redisDocker 服务名) |
| 端口 | 6379 |
| 数据库 | 0 |
| 密码 | XuqmRedis@2026 |
| 持久化 | AOFappendonly yes |
宿主机 nginx 配置参考见 [docs/runbook.md](runbook.md)。
---
@ -122,80 +57,35 @@
| 路径 | 说明 |
|------|------|
| `./data/mysql/` | MySQL 数据文件(重启后保留) |
| `./data/redis/` | Redis AOF 文件(重启后保留) |
| `./data/uploads/` | 文件服务上传目录 |
| `./data/update/` | 版本管理包存储目录 |
| `./data/backups/` | 迁移备份 |
| `./logs/` | 审计日志 |
| `./.deploy-state/` | 部署状态和验证结果 |
---
## 配置文件清单
| 文件 | 说明 |
|------|------|
| `.env` | 主配置文件COMPOSE_PROFILES、域名、功能开关 |
| `config/secrets.env` | 敏感凭据chmod 600 |
| `config/xuqm.env` | 业务服务容器内配置 |
| `config/tenant/bootstrap.env` | 初始租户配置(迁移后由真实数据替换) |
| `config/nginx/conf.d/xuqm.conf` | Nginx 路由配置 |
| `config/sdk/xuqm-private-sdk.json` | SDK 初始化配置文件 |
| `config/docs/docs-runtime.json` | 文档站运行时配置 |
| `config/vendors/push.env` | 推送厂商凭据(默认全部关闭) |
| `config/vendors/store-submit.env` | 应用市场发布凭据(默认全部关闭) |
| `config/mail/smtp.env` | 邮件服务配置 |
| `data/mysql/` | MySQL 数据文件 |
| `data/redis/` | Redis AOF 文件 |
| `data/uploads/` | 文件服务上传目录 |
| `data/update/` | 版本管理包存储 |
| `data/backups/` | 备份文件 |
| `logs/` | 审计日志 |
---
## 常用运维命令
```bash
# 进入部署目录
cd /opt/xuqm-private
# 查看所有容器状态
docker compose -f docker-compose.yml -f docker-compose.infra.yml ps
# 查看某个服务日志
# 查看服务日志
docker compose -f docker-compose.yml -f docker-compose.infra.yml logs --tail 100 tenant-service
# 运行一键验证
# 运行全量验证
bash scripts/verify.sh
# 重新部署(幂等)
DEPLOY_HOST=192.168.116.9 bash scripts/deploy-szyx.sh
# 手动迁移租户
bash scripts/migrate-tenant.sh \
--src-host 39.107.53.187 \
--src-user xuqm \
--src-password Xuqm@2026 \
--src-db xuqm_tenant \
--tenant szyx@bjca.org.cn
# 停止所有服务(保留数据)
docker compose -f docker-compose.yml -f docker-compose.infra.yml down
# 停止并清除所有数据(!不可恢复)
docker compose -f docker-compose.yml -f docker-compose.infra.yml down -v
```
---
## 验证结果
验证报告保存在 `.deploy-state/last-verify.json`,包含所有检查项的 PASS / WARN / FAIL 状态。
详细验证步骤见 [docs/acceptance-checklist.md](acceptance-checklist.md)。
---
## 注意事项
1. **注册功能已禁用**`TENANT_REGISTER_ENABLED=false`,任何人都无法自行注册账号,只能用迁移的账号登录。
2. **纯 IP 部署**:所有服务通过 `http://192.168.116.9` 访问,如需 HTTPS,请配置 SSL 证书并修改 nginx 配置(见 `docs/runbook.md`)。
3. **数据持久化**MySQL 和 Redis 数据存储在宿主机 `./data/` 目录,容器重启不丢失。重装需手动清除。
4. **推送服务**push-service 已启动,但各厂商推送默认关闭,需在 `config/vendors/push.env` 填写凭据并重启。
5. **中文字符集**:所有服务使用 utf8mb4,JDBC 连接串包含 `characterEncoding=UTF-8`,中文数据正常存储。
1. **注册功能已禁用**`TENANT_REGISTER_ENABLED=false`,只能用初始化的账号登录。
2. **数据持久化**MySQL 和 Redis 数据存储在 `data/` 目录,容器重启不丢失。
3. **推送服务**push-service 已启动,各厂商推送默认关闭,需填写 `config/vendors/push.env` 并重启。

查看文件

@ -1,106 +1,135 @@
# 私有化部署运行手册
## 目标
本仓库用于客户私有环境交付,只编排已有 Docker 镜像,不包含业务源码、不构建 demo 服务。
## 标准流程
1. 执行 `./scripts/configure.sh` 生成 `.env``config/secrets.env`
2. 修改 `.env`镜像仓库、镜像版本、域名、可选服务、MySQL/Redis 模式。
3. 修改 `config/secrets.env`数据库密码、Redis 密码、SMTP 密码等敏感配置。
4. 修改 `config/mail/smtp.env`、`config/vendors/*.env`。
5. 执行 `./scripts/install.sh --profile base` 部署基础服务。
6. 按需执行 `./scripts/enable-service.sh im|push|update|license` 启用可选服务。
7. 执行 `./scripts/healthcheck.sh` 并检查 `.deploy-state/last-healthcheck.json`
## MySQL/Redis 模式
`external` 模式:
- 客户提供连接地址、账号、密码、数据库名。
- 部署脚本只使用连接配置,不启动新服务。
- 生产默认使用该模式。
`managed` 模式:
- 部署脚本通过 Docker Compose 启动 MySQL/Redis。
- 密码为空或为 `change-me` 时自动生成并写入 `config/secrets.env`
- 数据目录写入 `data/mysql``data/redis`
## 可选服务
`im`、`push`、`update`、`license` 均可不部署,后期独立启用。
启用命令:
## 一键部署
```bash
./scripts/enable-service.sh im
./scripts/install.sh --profile base,im
curl -fsSL https://xuqinmin.com/xuqmGroup/XuqmGroup-PrivateDeploy/raw/branch/main/install.sh \
-o install.sh && bash install.sh
```
禁用命令:
交互式向导依次完成:
1. 选择租户初始化方式(新建 / 迁移)
2. 填写租户信息或迁移密钥
3. 填写外部访问地址(宿主机 nginx 对外的地址,用于 SDK 配置)
4. 自动完成容器启动、数据库初始化、全量验证
完成后按输出的端口表配置宿主机 nginx。
---
## Nginx 配置
部署完成后,将以下 location 块加入宿主机 nginx 的 server 配置:
```nginx
charset utf-8;
client_max_body_size 100m;
location /api/v1/updates/ { proxy_pass http://127.0.0.1:11229/api/v1/updates/; }
location /api/v1/rn/ { proxy_pass http://127.0.0.1:11229/api/v1/rn/; }
location /api/im/ { proxy_pass http://127.0.0.1:11228/api/im/; }
location /ws/im {
proxy_pass http://127.0.0.1:11228/ws/im;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
}
location /api/license/ { proxy_pass http://127.0.0.1:11231/api/license/; }
location /file/ {
proxy_pass http://127.0.0.1:11225/file/;
client_max_body_size 500m;
proxy_read_timeout 300s;
}
location /api/ { proxy_pass http://127.0.0.1:11224/api/; }
location /actuator/ { proxy_pass http://127.0.0.1:11224/actuator/; }
location /ops { proxy_pass http://127.0.0.1:11227; }
location / { proxy_pass http://127.0.0.1:11226; }
```
> location 顺序不可颠倒:精确路径(`/api/im/`、`/api/v1/`、`/api/license/`)必须在通用路径(`/api/`)前面。
---
## 端口对照表
| 宿主机端口 | 服务 | 容器内端口 | 说明 |
|-----------|------|-----------|------|
| 11224 | tenant-service | 9001 | 核心 API |
| 11225 | file-service | 8086 | 文件上传下载 |
| 11226 | tenant-web | 80 | 控制台前端 |
| 11227 | ops-web | 80 | 运营后台前端 |
| 11228 | im-service | 8082 | IM HTTP + WebSocket |
| 11229 | update-service | 8084 | 版本管理 + RN 热更新 |
| 11230 | license-service | 8085 | License 校验 |
| 11231 | push-service | 8083 | 厂商推送 |
所有端口绑定 `127.0.0.1`,外部不可直接访问。
---
## 租户迁移
迁移通过一键部署向导完成,选择「迁移租户」后:
1. 前往公有化平台控制台 → 安全中心 → 私有化部署迁移 → 生成迁移密钥
2. 将 `pmk_` 开头的密钥粘贴进向导
3. 脚本自动导出租户数据、导入私有库、写入 license 记录、重启服务
迁移为单租户操作,会清空现有 bootstrap 数据后写入迁移数据。
---
## 常用运维命令
```bash
./scripts/disable-service.sh im
# 查看所有容器状态
docker compose -f docker-compose.yml -f docker-compose.infra.yml ps
# 查看服务日志
docker compose -f docker-compose.yml -f docker-compose.infra.yml logs --tail 100 tenant-service
# 重新运行全量验证
bash scripts/verify.sh
# 停止所有服务(保留数据)
docker compose -f docker-compose.yml -f docker-compose.infra.yml down
# 启用可选服务
bash scripts/enable-service.sh im
# 禁用可选服务(不删数据)
bash scripts/disable-service.sh im
# 备份数据
bash scripts/backup.sh
# 恢复数据
bash scripts/restore.sh <backup-file>
```
禁用服务不会删除数据,重新启用后继续使用原配置和数据目录。
---
## 租户迁移(公有化 → 私有化)
## 数据目录
将公有化平台的存量租户迁移到私有化部署。
| 路径 | 说明 |
|------|------|
| `data/mysql/` | MySQL 数据文件 |
| `data/redis/` | Redis AOF 文件 |
| `data/uploads/` | 文件服务上传目录 |
| `data/update/` | 版本管理包存储 |
| `data/backups/` | 备份文件 |
| `logs/` | 审计日志 |
### 前提条件
---
- 私有化基础服务已通过 `healthcheck.sh`
- 源 MySQL 可从部署机器网络连通(`mysql -h SRC_HOST ...` 成功)。
- 私有化部署为单租户模式:迁移会**清空**当前 bootstrap 租户后写入迁移租户。
## 重新部署(幂等)
### 执行迁移
脚本幂等,可重复执行:
```bash
# Dry-run 确认要迁移的数据
./scripts/migrate-tenant.sh \
--src-host <生产MySQL> \
--src-user <用户名> \
--src-password '<密码>' \
--src-db xuqm_tenant \
--tenant <租户邮箱或用户名> \
--dry-run
# 确认无误后正式执行
./scripts/migrate-tenant.sh \
--src-host <生产MySQL> \
--src-user <用户名> \
--src-password '<密码>' \
--src-db xuqm_tenant \
--tenant <租户邮箱或用户名>
bash install.sh
```
迁移脚本会自动:
1. 从源库导出 `t_tenant`、`t_app`、`t_feature_service`(含厂商配置)。
2. 用显式列名 INSERT 规避生产与私有化 MySQL 的列序差异。
3. 清空私有化部署的 bootstrap 租户后写入迁移数据。
4. 重启 `tenant-service` 清空内存缓存。
5. 通过 `/api/sdk/config``/api/private/deployment/status` 验证结果。
### 验证
```bash
# SDK config 应返回 200
curl "http://DEPLOY_HOST/api/sdk/config?appKey=<app_key>&platform=ANDROID"
# 部署状态应为 PRIVATE,注册应为 false
curl "http://DEPLOY_HOST/api/private/deployment/status"
```
## 接手规则
任何 agent 开始执行前必须先查看:
- `.deploy-state/progress.md`
- `.deploy-state/current.json`
- `logs/audit.log`
执行关键步骤后必须追加进度,确保中断后可继续。
已运行的容器不会被重建,数据目录不受影响。