feat(deploy): 默认安装 ONLYOFFICE 标准组件
This commit is contained in:
@@ -9,7 +9,7 @@
|
|||||||
- 生产入口:`docker-compose.yaml`
|
- 生产入口:`docker-compose.yaml`
|
||||||
- 初始化方式:`docker compose run --rm --build backend-init`
|
- 初始化方式:`docker compose run --rm --build backend-init`
|
||||||
- 启动方式:`docker compose up -d --build`
|
- 启动方式:`docker compose up -d --build`
|
||||||
- 运行拓扑:`nginx`、`backend`、`db`
|
- 运行拓扑:`nginx`、`backend`、`db`、`onlyoffice`
|
||||||
- 对外入口:`nginx` 提供前端静态资源,并同域反代后端 API
|
- 对外入口:`nginx` 提供前端静态资源,并同域反代后端 API
|
||||||
- 数据库 schema 来源:Alembic migration,不再依赖 `database/init.sql`
|
- 数据库 schema 来源:Alembic migration,不再依赖 `database/init.sql`
|
||||||
- 默认无任何业务预置数据;生产初始化只确保固定管理员 `admin@huapont.cn / admin123` 存在
|
- 默认无任何业务预置数据;生产初始化只确保固定管理员 `admin@huapont.cn / admin123` 存在
|
||||||
@@ -50,11 +50,11 @@
|
|||||||
- Web 与桌面端共用产品版本;执行 `npm run version:set -- <version>` 统一升级,执行 `npm run version:check` 检查漂移。
|
- Web 与桌面端共用产品版本;执行 `npm run version:set -- <version>` 统一升级,执行 `npm run version:check` 检查漂移。
|
||||||
- 桌面端与 Web 端从同一发布标签和 Git 提交构建,具体流程见 `docs/guides/client-release.md`。
|
- 桌面端与 Web 端从同一发布标签和 Git 提交构建,具体流程见 `docs/guides/client-release.md`。
|
||||||
|
|
||||||
## ONLYOFFICE 开发预览
|
## ONLYOFFICE 标准组件
|
||||||
|
|
||||||
- 普通开发环境仍不强制启动 Document Server。
|
- `./install.sh` 或 `bash scripts/install.sh dev|main|release` 默认生成独立 JWT、持久化实例标识并启动 Document Server,不再需要额外启用 Compose profile。
|
||||||
- 需要 Office 只读预览时执行 `bash scripts/onlyoffice-dev-up.sh`。
|
- `bash scripts/onlyoffice-dev-up.sh` 仅保留为开发环境重建、健康验证和密钥轮换入口;普通安装无需再执行。
|
||||||
- 脚本会自动生成并持久化本机开发密钥,不需要手工填写;详细说明见 `docs/guides/onlyoffice-preview.md`。
|
- 默认镜像、字体、安全配置和生产许可要求见 `docs/guides/onlyoffice-preview.md`。
|
||||||
|
|
||||||
## 仓库治理文档
|
## 仓库治理文档
|
||||||
- 分支治理规范:`docs/branch-governance.md`
|
- 分支治理规范:`docs/branch-governance.md`
|
||||||
|
|||||||
+4
-5
@@ -47,11 +47,11 @@ services:
|
|||||||
MONITORING_IP_GEO_FALLBACK_TIMEOUT_SECONDS: ${MONITORING_IP_GEO_FALLBACK_TIMEOUT_SECONDS:-2.5}
|
MONITORING_IP_GEO_FALLBACK_TIMEOUT_SECONDS: ${MONITORING_IP_GEO_FALLBACK_TIMEOUT_SECONDS:-2.5}
|
||||||
MONITORING_IP_GEO_FALLBACK_CACHE_SECONDS: ${MONITORING_IP_GEO_FALLBACK_CACHE_SECONDS:-604800}
|
MONITORING_IP_GEO_FALLBACK_CACHE_SECONDS: ${MONITORING_IP_GEO_FALLBACK_CACHE_SECONDS:-604800}
|
||||||
MONITORING_IP_GEO_FALLBACK_MAX_LOOKUPS: ${MONITORING_IP_GEO_FALLBACK_MAX_LOOKUPS:-10}
|
MONITORING_IP_GEO_FALLBACK_MAX_LOOKUPS: ${MONITORING_IP_GEO_FALLBACK_MAX_LOOKUPS:-10}
|
||||||
ONLYOFFICE_ENABLED: ${ONLYOFFICE_ENABLED:-false}
|
ONLYOFFICE_ENABLED: ${ONLYOFFICE_ENABLED:-true}
|
||||||
ONLYOFFICE_JWT_SECRET: ${ONLYOFFICE_JWT_SECRET:-}
|
ONLYOFFICE_JWT_SECRET: ${ONLYOFFICE_JWT_SECRET:?请先运行安装脚本生成 ONLYOFFICE_JWT_SECRET}
|
||||||
ONLYOFFICE_INTERNAL_URL: ${ONLYOFFICE_INTERNAL_URL:-http://onlyoffice}
|
ONLYOFFICE_INTERNAL_URL: ${ONLYOFFICE_INTERNAL_URL:-http://onlyoffice}
|
||||||
ONLYOFFICE_STORAGE_BASE_URL: ${ONLYOFFICE_STORAGE_BASE_URL:-http://backend:8000}
|
ONLYOFFICE_STORAGE_BASE_URL: ${ONLYOFFICE_STORAGE_BASE_URL:-http://backend:8000}
|
||||||
ONLYOFFICE_INSTANCE_ID: ${ONLYOFFICE_INSTANCE_ID:-}
|
ONLYOFFICE_INSTANCE_ID: ${ONLYOFFICE_INSTANCE_ID:?请先运行安装脚本生成 ONLYOFFICE_INSTANCE_ID}
|
||||||
ONLYOFFICE_CONFIG_TTL_SECONDS: ${ONLYOFFICE_CONFIG_TTL_SECONDS:-300}
|
ONLYOFFICE_CONFIG_TTL_SECONDS: ${ONLYOFFICE_CONFIG_TTL_SECONDS:-300}
|
||||||
COLLABORATION_MAX_FILE_BYTES: ${COLLABORATION_MAX_FILE_BYTES:-52428800}
|
COLLABORATION_MAX_FILE_BYTES: ${COLLABORATION_MAX_FILE_BYTES:-52428800}
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -82,10 +82,9 @@ services:
|
|||||||
image: ctms-onlyoffice:9.4.0.1
|
image: ctms-onlyoffice:9.4.0.1
|
||||||
container_name: ctms_onlyoffice
|
container_name: ctms_onlyoffice
|
||||||
restart: always
|
restart: always
|
||||||
profiles: ["office"]
|
|
||||||
environment:
|
environment:
|
||||||
JWT_ENABLED: "true"
|
JWT_ENABLED: "true"
|
||||||
JWT_SECRET: ${ONLYOFFICE_JWT_SECRET:-}
|
JWT_SECRET: ${ONLYOFFICE_JWT_SECRET:?请先运行安装脚本生成 ONLYOFFICE_JWT_SECRET}
|
||||||
JWT_HEADER: AuthorizationJwt
|
JWT_HEADER: AuthorizationJwt
|
||||||
JWT_IN_BODY: "false"
|
JWT_IN_BODY: "false"
|
||||||
EXAMPLE_ENABLED: "false"
|
EXAMPLE_ENABLED: "false"
|
||||||
|
|||||||
@@ -147,12 +147,12 @@ bash scripts/install.sh release --base-url https://ctms.example.com
|
|||||||
|
|
||||||
```text
|
```text
|
||||||
1. 检查 docker、docker compose、openssl、curl。
|
1. 检查 docker、docker compose、openssl、curl。
|
||||||
2. 检查 .env;已存在则保留不改,不存在则新建。
|
2. 检查 .env;保留已有身份与登录密钥,补齐并默认启用标准 ONLYOFFICE 配置,不存在则新建。
|
||||||
3. 新建 main/release 的 .env 时自动生成 JWT 和 RSA 私钥。
|
3. 所有环境自动生成独立的 ONLYOFFICE JWT 与稳定实例标识;新建 main/release 的 .env 时同时生成登录 JWT 和 RSA 私钥。
|
||||||
4. main/release 先构建并执行 backend-init,确保数据库迁移使用当前代码中的 Alembic revision。
|
4. main/release 先构建并执行 backend-init,确保数据库迁移使用当前代码中的 Alembic revision。
|
||||||
5. 启动容器;默认执行 docker compose up -d --build,--skip-build 时执行 docker compose up -d。
|
5. 默认构建并启动数据库、后端、前端/Nginx 和 ONLYOFFICE;ONLYOFFICE 不再使用可选 Compose Profile。
|
||||||
6. 执行 docker compose run --rm backend python -m alembic upgrade head。
|
6. 执行 docker compose run --rm backend python -m alembic upgrade head。
|
||||||
7. 检查容器状态、后端环境、/health、/api/v1/auth/login-key。
|
7. 检查全部容器状态、后端环境、/health、/api/v1/auth/login-key 和 /onlyoffice/healthcheck。
|
||||||
```
|
```
|
||||||
|
|
||||||
更新进入“执行部署更新”后会持续显示 Docker 镜像拉取与构建进度:交互终端使用滚动实时输出窗口,CI、远程面板或管道环境直接流式输出构建日志,并在两种模式下显示累计耗时。
|
更新进入“执行部署更新”后会持续显示 Docker 镜像拉取与构建进度:交互终端使用滚动实时输出窗口,CI、远程面板或管道环境直接流式输出构建日志,并在两种模式下显示累计耗时。
|
||||||
@@ -195,6 +195,12 @@ ENV=development
|
|||||||
JWT_SECRET_KEY=dev-secret
|
JWT_SECRET_KEY=dev-secret
|
||||||
LOGIN_RSA_KEY_ID=default
|
LOGIN_RSA_KEY_ID=default
|
||||||
LOGIN_RSA_PRIVATE_KEY=
|
LOGIN_RSA_PRIVATE_KEY=
|
||||||
|
ONLYOFFICE_ENABLED=true
|
||||||
|
ONLYOFFICE_JWT_SECRET=<替换为独立的随机密钥,至少 32 个字符>
|
||||||
|
ONLYOFFICE_INTERNAL_URL=http://onlyoffice
|
||||||
|
ONLYOFFICE_STORAGE_BASE_URL=http://backend:8000
|
||||||
|
ONLYOFFICE_INSTANCE_ID=ctms-dev-<替换为随机实例标识>
|
||||||
|
ONLYOFFICE_CONFIG_TTL_SECONDS=300
|
||||||
EOF
|
EOF
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -316,6 +322,12 @@ ENV=production
|
|||||||
JWT_SECRET_KEY=<替换为 JWT 密钥>
|
JWT_SECRET_KEY=<替换为 JWT 密钥>
|
||||||
LOGIN_RSA_KEY_ID=main-YYYYMMDD
|
LOGIN_RSA_KEY_ID=main-YYYYMMDD
|
||||||
LOGIN_RSA_PRIVATE_KEY=<替换为 RSA 私钥单行文本>
|
LOGIN_RSA_PRIVATE_KEY=<替换为 RSA 私钥单行文本>
|
||||||
|
ONLYOFFICE_ENABLED=true
|
||||||
|
ONLYOFFICE_JWT_SECRET=<替换为不同于 JWT_SECRET_KEY 的独立随机密钥>
|
||||||
|
ONLYOFFICE_INTERNAL_URL=http://onlyoffice
|
||||||
|
ONLYOFFICE_STORAGE_BASE_URL=http://backend:8000
|
||||||
|
ONLYOFFICE_INSTANCE_ID=ctms-main-<替换为随机实例标识>
|
||||||
|
ONLYOFFICE_CONFIG_TTL_SECONDS=300
|
||||||
EOF
|
EOF
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -495,6 +507,12 @@ ENV=production
|
|||||||
JWT_SECRET_KEY=<替换为生产 JWT 密钥>
|
JWT_SECRET_KEY=<替换为生产 JWT 密钥>
|
||||||
LOGIN_RSA_KEY_ID=release-YYYYMMDD
|
LOGIN_RSA_KEY_ID=release-YYYYMMDD
|
||||||
LOGIN_RSA_PRIVATE_KEY=<替换为生产 RSA 私钥单行文本>
|
LOGIN_RSA_PRIVATE_KEY=<替换为生产 RSA 私钥单行文本>
|
||||||
|
ONLYOFFICE_ENABLED=true
|
||||||
|
ONLYOFFICE_JWT_SECRET=<替换为不同于 JWT_SECRET_KEY 的独立生产随机密钥>
|
||||||
|
ONLYOFFICE_INTERNAL_URL=http://onlyoffice
|
||||||
|
ONLYOFFICE_STORAGE_BASE_URL=http://backend:8000
|
||||||
|
ONLYOFFICE_INSTANCE_ID=ctms-release-<替换为随机实例标识>
|
||||||
|
ONLYOFFICE_CONFIG_TTL_SECONDS=300
|
||||||
EOF
|
EOF
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,28 @@
|
|||||||
# ONLYOFFICE 只读预览运行说明
|
# ONLYOFFICE 标准组件运行说明
|
||||||
|
|
||||||
当前集成只用于附件和文档版本的 Office 文件只读预览。PDF、图片、另存为和桌面端“打开”仍使用原有链路;第一期不启用编辑、保存回调、历史记录或强制保存。
|
ONLYOFFICE Document Server 是 CTMS 的标准部署组件,用于附件和文档版本预览,以及共享库在线协作编辑。PDF、图片、另存为和桌面端“打开”仍使用各自原有链路。
|
||||||
|
|
||||||
## 开发环境启动
|
## 默认安装
|
||||||
|
|
||||||
普通 `docker compose up` 不会拉取或启动 Document Server。开发环境需要预览时执行专用启动脚本:
|
执行标准安装即可同时安装 CTMS 与 ONLYOFFICE:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/install.sh dev
|
||||||
|
```
|
||||||
|
|
||||||
|
安装脚本会自动完成以下工作:
|
||||||
|
|
||||||
|
- 首次安装时生成独立的 256-bit 随机 `ONLYOFFICE_JWT_SECRET`,写入根目录 `.env`,且不在终端回显。
|
||||||
|
- 自动生成稳定、按部署环境隔离的实例标识并写入 `.env`。
|
||||||
|
- 将 `.env` 权限设置为 `0600`;该文件已被 Git 忽略。
|
||||||
|
- 默认构建并启动 backend、Document Server 与 Nginx,不再使用可选 Compose Profile。
|
||||||
|
- 将 Document Server 纳入容器状态、后端配置和 HTTP 健康检查。
|
||||||
|
- 后续启动默认复用密钥,防止后端和 Document Server 因签名密钥漂移而无法通信。
|
||||||
|
|
||||||
|
开发环境需要单独重建、验证或主动轮换密钥时,可使用兼容维护脚本:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash scripts/onlyoffice-dev-up.sh
|
bash scripts/onlyoffice-dev-up.sh
|
||||||
```
|
|
||||||
|
|
||||||
脚本会自动完成以下工作:
|
|
||||||
|
|
||||||
- 首次启动时生成 256-bit 随机 `ONLYOFFICE_JWT_SECRET`,写入根目录 `.env`,且不在终端回显。
|
|
||||||
- 自动生成稳定的开发实例标识并写入 `.env`。
|
|
||||||
- 将 `.env` 权限设置为 `0600`;该文件已被 Git 忽略。
|
|
||||||
- 使用同一环境重建 backend,并显式启用 `office` Profile 启动 Document Server。
|
|
||||||
- 后续启动默认复用密钥,防止后端和 Document Server 因签名密钥漂移而无法通信。
|
|
||||||
|
|
||||||
需要主动轮换开发密钥时执行:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bash scripts/onlyoffice-dev-up.sh --rotate-secret
|
bash scripts/onlyoffice-dev-up.sh --rotate-secret
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -30,7 +32,7 @@ bash scripts/onlyoffice-dev-up.sh --rotate-secret
|
|||||||
|
|
||||||
## 配置边界
|
## 配置边界
|
||||||
|
|
||||||
- `ONLYOFFICE_ENABLED` 默认 `false`。
|
- Compose 安装中的 `ONLYOFFICE_ENABLED` 默认 `true`;安装或更新旧环境时也会自动启用。
|
||||||
- `ONLYOFFICE_INTERNAL_URL` 默认 `http://onlyoffice`,只供后端健康探测。
|
- `ONLYOFFICE_INTERNAL_URL` 默认 `http://onlyoffice`,只供后端健康探测。
|
||||||
- `ONLYOFFICE_STORAGE_BASE_URL` 默认 `http://backend:8000`,只允许后端生成固定的内部文件地址。
|
- `ONLYOFFICE_STORAGE_BASE_URL` 默认 `http://backend:8000`,只允许后端生成固定的内部文件地址。
|
||||||
- `ONLYOFFICE_CONFIG_TTL_SECONDS` 默认 300 秒,允许范围为 60–900 秒。
|
- `ONLYOFFICE_CONFIG_TTL_SECONDS` 默认 300 秒,允许范围为 60–900 秒。
|
||||||
@@ -38,8 +40,8 @@ bash scripts/onlyoffice-dev-up.sh --rotate-secret
|
|||||||
- 配置响应禁止缓存;JWT、内部文件 URL 和磁盘路径不得进入日志、审计详情或桌面缓存。
|
- 配置响应禁止缓存;JWT、内部文件 URL 和磁盘路径不得进入日志、审计详情或桌面缓存。
|
||||||
- `onlyoffice_data`、`onlyoffice_lib` 和 `onlyoffice_logs` 不是 CTMS 业务权威数据,不纳入业务备份或恢复来源。
|
- `onlyoffice_data`、`onlyoffice_lib` 和 `onlyoffice_logs` 不是 CTMS 业务权威数据,不纳入业务备份或恢复来源。
|
||||||
|
|
||||||
## 生产启用前
|
## 生产部署要求
|
||||||
|
|
||||||
生产保持功能开关关闭,直至商业许可、批准镜像和真实授权环境回归完成。启用时必须使用生产随机密钥和稳定、唯一的 `ONLYOFFICE_INSTANCE_ID`,并完成 Web、macOS 和 Windows 内测端的真实 DOCX/XLSX/PPTX/WPS/ET/DPS 预览验证。
|
标准生产安装同样包含 ONLYOFFICE,并自动生成独立随机密钥和稳定、唯一的 `ONLYOFFICE_INSTANCE_ID`。正式上线前仍必须确认商业许可或 Community 版本授权边界、批准镜像、容量与备份监控策略,并完成 Web、macOS 和 Windows 内测端的真实 DOCX/XLSX/PPTX/WPS/ET/DPS 预览验证。
|
||||||
|
|
||||||
故障回退只关闭 `ONLYOFFICE_ENABLED`;不得影响附件下载、另存为、打开、PDF 或图片预览。Community 与商业版本的授权边界以 [ONLYOFFICE 官方许可说明](https://helpcenter.onlyoffice.com/docs/faq/docs-community.aspx) 为准。
|
故障回退可临时关闭 `ONLYOFFICE_ENABLED`;下一次标准安装或更新会按标准组件策略重新启用。回退不得影响附件下载、另存为、打开、PDF 或图片预览。Community 与商业版本的授权边界以 [ONLYOFFICE 官方许可说明](https://helpcenter.onlyoffice.com/docs/faq/docs-community.aspx) 为准。
|
||||||
|
|||||||
@@ -49,13 +49,13 @@
|
|||||||
|
|
||||||
## 本地开发
|
## 本地开发
|
||||||
|
|
||||||
执行:
|
标准开发安装会直接启动 ONLYOFFICE:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash scripts/onlyoffice-dev-up.sh
|
bash scripts/install.sh dev
|
||||||
```
|
```
|
||||||
|
|
||||||
脚本会生成或复用独立的开发 JWT 密钥,启用 `office` Profile,并验证只读预览及在线协作的后端路由。协作修订保存在现有后端上传卷下的独立 `collaboration/` 目录。
|
安装脚本会生成或复用独立的开发 JWT 密钥和稳定实例标识,默认启动 Document Server,并验证后端配置和 HTTP 健康状态。`bash scripts/onlyoffice-dev-up.sh` 仅用于开发环境单独重建、验证或轮换密钥。协作修订保存在现有后端上传卷下的独立 `collaboration/` 目录。
|
||||||
|
|
||||||
关键配置:
|
关键配置:
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ bash scripts/onlyoffice-dev-up.sh
|
|||||||
- `ONLYOFFICE_CONFIG_TTL_SECONDS`
|
- `ONLYOFFICE_CONFIG_TTL_SECONDS`
|
||||||
- `COLLABORATION_MAX_FILE_BYTES`
|
- `COLLABORATION_MAX_FILE_BYTES`
|
||||||
|
|
||||||
生产环境仍默认关闭 ONLYOFFICE;启用前必须按既有发布要求确认镜像许可、JWT 密钥、内部网络、备份与监控。
|
生产标准安装同样包含 ONLYOFFICE;正式上线前必须按既有发布要求确认镜像许可、独立 JWT 密钥、内部网络、容量、备份与监控。
|
||||||
|
|
||||||
参考:
|
参考:
|
||||||
|
|
||||||
|
|||||||
+10
-5
@@ -309,7 +309,8 @@ ctms_require_docker_compose() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# 安装/更新所需依赖。openssl、curl 仅在非 dev 环境要求(dev 用默认密钥、不做 RSA 生成)。
|
# 安装/更新所需依赖。所有环境都需要 openssl 生成独立的 ONLYOFFICE JWT 密钥;
|
||||||
|
# main/release 还会用它生成登录 RSA 密钥。
|
||||||
ctms_require_dependencies() {
|
ctms_require_dependencies() {
|
||||||
local env="$1"
|
local env="$1"
|
||||||
ctms_require_env "$env"
|
ctms_require_env "$env"
|
||||||
@@ -317,10 +318,7 @@ ctms_require_dependencies() {
|
|||||||
|
|
||||||
ctms_require_command docker "安装 Docker Engine 或 Docker Desktop,并确认 docker 命令可用" || missing=1
|
ctms_require_command docker "安装 Docker Engine 或 Docker Desktop,并确认 docker 命令可用" || missing=1
|
||||||
ctms_require_command curl "Linux: sudo apt-get install -y curl | macOS: brew install curl" || missing=1
|
ctms_require_command curl "Linux: sudo apt-get install -y curl | macOS: brew install curl" || missing=1
|
||||||
# openssl 仅非 dev 需要:dev 用 dev-secret 与空 RSA key,不生成密钥
|
ctms_require_command openssl "Linux: sudo apt-get install -y openssl | macOS: brew install openssl" || missing=1
|
||||||
if [[ "$env" != "dev" ]]; then
|
|
||||||
ctms_require_command openssl "Linux: sudo apt-get install -y openssl | macOS: brew install openssl" || missing=1
|
|
||||||
fi
|
|
||||||
[[ "$missing" -eq 0 ]] || ctms_fail "系统依赖不完整,请按上方提示安装后重试"
|
[[ "$missing" -eq 0 ]] || ctms_fail "系统依赖不完整,请按上方提示安装后重试"
|
||||||
|
|
||||||
if ! docker compose version >/dev/null 2>&1; then
|
if ! docker compose version >/dev/null 2>&1; then
|
||||||
@@ -541,6 +539,7 @@ ctms_upsert_env_value() {
|
|||||||
ctms_write_env_file() {
|
ctms_write_env_file() {
|
||||||
local project_name="$1" runtime_env="$2" login_key_id="$3"
|
local project_name="$1" runtime_env="$2" login_key_id="$3"
|
||||||
local jwt_secret="$4" rsa_private_key="$5"
|
local jwt_secret="$4" rsa_private_key="$5"
|
||||||
|
local onlyoffice_jwt_secret="$6" onlyoffice_instance_id="$7"
|
||||||
local allow_insecure_dev_login="false"
|
local allow_insecure_dev_login="false"
|
||||||
[[ "$runtime_env" == "development" ]] && allow_insecure_dev_login="true"
|
[[ "$runtime_env" == "development" ]] && allow_insecure_dev_login="true"
|
||||||
local temp_file
|
local temp_file
|
||||||
@@ -554,6 +553,12 @@ ctms_write_env_file() {
|
|||||||
printf 'JWT_SECRET_KEY=%s\n' "$jwt_secret"
|
printf 'JWT_SECRET_KEY=%s\n' "$jwt_secret"
|
||||||
printf 'LOGIN_RSA_KEY_ID=%s\n' "$login_key_id"
|
printf 'LOGIN_RSA_KEY_ID=%s\n' "$login_key_id"
|
||||||
printf 'LOGIN_RSA_PRIVATE_KEY=%s\n' "$rsa_private_key"
|
printf 'LOGIN_RSA_PRIVATE_KEY=%s\n' "$rsa_private_key"
|
||||||
|
printf 'ONLYOFFICE_ENABLED=true\n'
|
||||||
|
printf 'ONLYOFFICE_JWT_SECRET=%s\n' "$onlyoffice_jwt_secret"
|
||||||
|
printf 'ONLYOFFICE_INTERNAL_URL=http://onlyoffice\n'
|
||||||
|
printf 'ONLYOFFICE_STORAGE_BASE_URL=http://backend:8000\n'
|
||||||
|
printf 'ONLYOFFICE_INSTANCE_ID=%s\n' "$onlyoffice_instance_id"
|
||||||
|
printf 'ONLYOFFICE_CONFIG_TTL_SECONDS=300\n'
|
||||||
} >> "$temp_file"
|
} >> "$temp_file"
|
||||||
|
|
||||||
mv "$temp_file" "$CTMS_ENV_FILE"
|
mv "$temp_file" "$CTMS_ENV_FILE"
|
||||||
|
|||||||
+59
-6
@@ -173,6 +173,10 @@ generate_jwt_secret() {
|
|||||||
openssl rand -hex 32
|
openssl rand -hex 32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generate_onlyoffice_instance_id() {
|
||||||
|
printf 'ctms-%s-%s' "$TARGET_ENV" "$(openssl rand -hex 8)"
|
||||||
|
}
|
||||||
|
|
||||||
# ── 地址解析 ─────────────────────────────────
|
# ── 地址解析 ─────────────────────────────────
|
||||||
resolve_base_url() {
|
resolve_base_url() {
|
||||||
[[ -z "$BASE_URL" ]] && BASE_URL="$(default_base_url)"
|
[[ -z "$BASE_URL" ]] && BASE_URL="$(default_base_url)"
|
||||||
@@ -221,6 +225,7 @@ confirm_install() {
|
|||||||
row "健康检查地址" "$BASE_URL" "${CC_INFO}"
|
row "健康检查地址" "$BASE_URL" "${CC_INFO}"
|
||||||
row ".env 文件" "$env_status"
|
row ".env 文件" "$env_status"
|
||||||
row "pg_data 目录" "$pg_status"
|
row "pg_data 目录" "$pg_status"
|
||||||
|
row "ONLYOFFICE" "标准组件(自动安装)" "${CC_INFO}"
|
||||||
row "镜像构建" "$build_status"
|
row "镜像构建" "$build_status"
|
||||||
row "数据库迁移" "$migrate_status"
|
row "数据库迁移" "$migrate_status"
|
||||||
ctms_box_bottom "${CC_PRIMARY}${C_BOLD}" "$w"
|
ctms_box_bottom "${CC_PRIMARY}${C_BOLD}" "$w"
|
||||||
@@ -252,6 +257,7 @@ prepare_env_file() {
|
|||||||
step "准备环境配置文件"
|
step "准备环境配置文件"
|
||||||
local project_name="$1" runtime_env="$2" login_key_id="$3"
|
local project_name="$1" runtime_env="$2" login_key_id="$3"
|
||||||
local jwt_secret="" rsa_private_key=""
|
local jwt_secret="" rsa_private_key=""
|
||||||
|
local onlyoffice_jwt_secret="" onlyoffice_instance_id=""
|
||||||
|
|
||||||
# 首次安装:无 .env,写全量。
|
# 首次安装:无 .env,写全量。
|
||||||
if [[ ! -f "$ENV_FILE" ]]; then
|
if [[ ! -f "$ENV_FILE" ]]; then
|
||||||
@@ -265,7 +271,12 @@ prepare_env_file() {
|
|||||||
rsa_private_key="$(generate_escaped_private_key)"
|
rsa_private_key="$(generate_escaped_private_key)"
|
||||||
ok "已生成新的 LOGIN_RSA_PRIVATE_KEY"
|
ok "已生成新的 LOGIN_RSA_PRIVATE_KEY"
|
||||||
fi
|
fi
|
||||||
ctms_write_env_file "$project_name" "$runtime_env" "$login_key_id" "$jwt_secret" "$rsa_private_key"
|
onlyoffice_jwt_secret="$(generate_jwt_secret)"
|
||||||
|
onlyoffice_instance_id="$(generate_onlyoffice_instance_id)"
|
||||||
|
ok "已生成独立的 ONLYOFFICE JWT 密钥与实例标识"
|
||||||
|
ctms_write_env_file \
|
||||||
|
"$project_name" "$runtime_env" "$login_key_id" "$jwt_secret" "$rsa_private_key" \
|
||||||
|
"$onlyoffice_jwt_secret" "$onlyoffice_instance_id"
|
||||||
ok ".env 写入完成"
|
ok ".env 写入完成"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
@@ -310,6 +321,36 @@ prepare_env_file() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ONLYOFFICE 是标准组件:旧环境升级时自动启用并补齐独立安全配置。
|
||||||
|
if [[ "$(read_env_value ONLYOFFICE_ENABLED || true)" != "true" ]]; then
|
||||||
|
ctms_upsert_env_value ONLYOFFICE_ENABLED true; repaired=1
|
||||||
|
warn ".env 中 ONLYOFFICE 未启用,已作为标准组件启用"
|
||||||
|
fi
|
||||||
|
|
||||||
|
onlyoffice_jwt_secret="$(read_env_value ONLYOFFICE_JWT_SECRET || true)"
|
||||||
|
jwt_secret="$(read_env_value JWT_SECRET_KEY || true)"
|
||||||
|
if [[ ${#onlyoffice_jwt_secret} -lt 32 || "$onlyoffice_jwt_secret" == "$jwt_secret" ]]; then
|
||||||
|
onlyoffice_jwt_secret="$(generate_jwt_secret)"
|
||||||
|
ctms_upsert_env_value ONLYOFFICE_JWT_SECRET "$onlyoffice_jwt_secret"; repaired=1
|
||||||
|
warn ".env 缺少有效的独立 ONLYOFFICE_JWT_SECRET,已生成并补全"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$(read_env_value ONLYOFFICE_INSTANCE_ID || true)" ]]; then
|
||||||
|
onlyoffice_instance_id="$(generate_onlyoffice_instance_id)"
|
||||||
|
ctms_upsert_env_value ONLYOFFICE_INSTANCE_ID "$onlyoffice_instance_id"; repaired=1
|
||||||
|
warn ".env 缺少 ONLYOFFICE_INSTANCE_ID,已生成稳定实例标识"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$(read_env_value ONLYOFFICE_INTERNAL_URL || true)" ]]; then
|
||||||
|
ctms_upsert_env_value ONLYOFFICE_INTERNAL_URL http://onlyoffice; repaired=1
|
||||||
|
fi
|
||||||
|
if [[ -z "$(read_env_value ONLYOFFICE_STORAGE_BASE_URL || true)" ]]; then
|
||||||
|
ctms_upsert_env_value ONLYOFFICE_STORAGE_BASE_URL http://backend:8000; repaired=1
|
||||||
|
fi
|
||||||
|
if [[ -z "$(read_env_value ONLYOFFICE_CONFIG_TTL_SECONDS || true)" ]]; then
|
||||||
|
ctms_upsert_env_value ONLYOFFICE_CONFIG_TTL_SECONDS 300; repaired=1
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "$repaired" -eq 1 ]]; then
|
if [[ "$repaired" -eq 1 ]]; then
|
||||||
ok ".env 已补全缺失项"
|
ok ".env 已补全缺失项"
|
||||||
else
|
else
|
||||||
@@ -320,7 +361,8 @@ prepare_env_file() {
|
|||||||
# ── Docker 流程 ───────────────────────────────
|
# ── Docker 流程 ───────────────────────────────
|
||||||
run_compose_config() {
|
run_compose_config() {
|
||||||
step "校验 Docker Compose 配置"
|
step "校验 Docker Compose 配置"
|
||||||
ctms_run_quiet "Docker Compose 配置语法校验" -- compose_cmd config
|
# config 会展开并输出 JWT/RSA 等敏感环境变量;即使启用 --verbose 也只做静默校验。
|
||||||
|
ctms_run_quiet "Docker Compose 配置语法校验" -- compose_cmd config --quiet
|
||||||
}
|
}
|
||||||
|
|
||||||
run_backend_init() {
|
run_backend_init() {
|
||||||
@@ -338,14 +380,14 @@ run_build_and_start() {
|
|||||||
if [[ "$SKIP_BUILD" -eq 1 ]]; then
|
if [[ "$SKIP_BUILD" -eq 1 ]]; then
|
||||||
step "启动服务(跳过镜像构建)"
|
step "启动服务(跳过镜像构建)"
|
||||||
if [[ "$TARGET_ENV" == "dev" ]]; then
|
if [[ "$TARGET_ENV" == "dev" ]]; then
|
||||||
ctms_run_quiet "启动开发容器并刷新后端/Nginx/Vite" -- compose_cmd up -d --force-recreate backend nginx frontend-dev
|
ctms_run_quiet "启动开发容器并刷新后端/ONLYOFFICE/Nginx/Vite" -- compose_cmd up -d --force-recreate backend onlyoffice nginx frontend-dev
|
||||||
else
|
else
|
||||||
ctms_run_quiet "启动容器" -- compose_cmd up -d
|
ctms_run_quiet "启动容器" -- compose_cmd up -d
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
step "构建镜像并启动服务"
|
step "构建镜像并启动服务"
|
||||||
if [[ "$TARGET_ENV" == "dev" ]]; then
|
if [[ "$TARGET_ENV" == "dev" ]]; then
|
||||||
CTMS_LIVE_OUTPUT=1 ctms_run_quiet "构建并刷新开发容器(首次较慢)" -- compose_cmd up -d --build --force-recreate backend nginx frontend-dev
|
CTMS_LIVE_OUTPUT=1 ctms_run_quiet "构建并刷新开发容器(首次较慢)" -- compose_cmd up -d --build --force-recreate backend onlyoffice nginx frontend-dev
|
||||||
else
|
else
|
||||||
CTMS_LIVE_OUTPUT=1 ctms_run_quiet "构建镜像并启动容器(首次较慢)" -- compose_cmd up -d --build
|
CTMS_LIVE_OUTPUT=1 ctms_run_quiet "构建镜像并启动容器(首次较慢)" -- compose_cmd up -d --build
|
||||||
fi
|
fi
|
||||||
@@ -366,7 +408,7 @@ check_container_status() {
|
|||||||
step "检查容器运行状态"
|
step "检查容器运行状态"
|
||||||
local running
|
local running
|
||||||
running="$(compose_cmd ps --services --filter status=running 2>/dev/null || true)"
|
running="$(compose_cmd ps --services --filter status=running 2>/dev/null || true)"
|
||||||
local services=(db backend nginx)
|
local services=(db backend onlyoffice nginx)
|
||||||
[[ "$TARGET_ENV" != "dev" ]] || services+=(frontend-dev)
|
[[ "$TARGET_ENV" != "dev" ]] || services+=(frontend-dev)
|
||||||
local svc
|
local svc
|
||||||
for svc in "${services[@]}"; do
|
for svc in "${services[@]}"; do
|
||||||
@@ -398,6 +440,14 @@ if settings.LOGIN_RSA_KEY_ID != expected_key_id:
|
|||||||
sys.exit("LOGIN_RSA_KEY_ID 不匹配")
|
sys.exit("LOGIN_RSA_KEY_ID 不匹配")
|
||||||
if expected_env == "production" and settings.JWT_SECRET_KEY == "dev-secret":
|
if expected_env == "production" and settings.JWT_SECRET_KEY == "dev-secret":
|
||||||
sys.exit("生产环境不允许使用默认 JWT_SECRET_KEY")
|
sys.exit("生产环境不允许使用默认 JWT_SECRET_KEY")
|
||||||
|
if not settings.ONLYOFFICE_ENABLED:
|
||||||
|
sys.exit("ONLYOFFICE 必须作为标准组件启用")
|
||||||
|
if len(settings.ONLYOFFICE_JWT_SECRET or "") < 32:
|
||||||
|
sys.exit("ONLYOFFICE_JWT_SECRET 未正确配置")
|
||||||
|
if settings.ONLYOFFICE_JWT_SECRET == settings.JWT_SECRET_KEY:
|
||||||
|
sys.exit("ONLYOFFICE_JWT_SECRET 不得复用登录 JWT 密钥")
|
||||||
|
if not settings.ONLYOFFICE_INSTANCE_ID:
|
||||||
|
sys.exit("ONLYOFFICE_INSTANCE_ID 未配置")
|
||||||
if expect_rsa:
|
if expect_rsa:
|
||||||
if not settings.LOGIN_RSA_PRIVATE_KEY:
|
if not settings.LOGIN_RSA_PRIVATE_KEY:
|
||||||
sys.exit("LOGIN_RSA_PRIVATE_KEY 未配置")
|
sys.exit("LOGIN_RSA_PRIVATE_KEY 未配置")
|
||||||
@@ -463,6 +513,7 @@ run_health_checks() {
|
|||||||
check_http_endpoint "/health"
|
check_http_endpoint "/health"
|
||||||
check_http_endpoint "/readyz"
|
check_http_endpoint "/readyz"
|
||||||
check_http_endpoint "/api/v1/auth/login-key"
|
check_http_endpoint "/api/v1/auth/login-key"
|
||||||
|
check_http_endpoint "/onlyoffice/healthcheck" 120
|
||||||
if [[ "$TARGET_ENV" == "dev" ]]; then
|
if [[ "$TARGET_ENV" == "dev" ]]; then
|
||||||
check_http_endpoint "/" 60
|
check_http_endpoint "/" 60
|
||||||
fi
|
fi
|
||||||
@@ -515,4 +566,6 @@ main() {
|
|||||||
show_success
|
show_success
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
||||||
|
main "$@"
|
||||||
|
fi
|
||||||
|
|||||||
@@ -80,14 +80,13 @@ main() {
|
|||||||
docker compose
|
docker compose
|
||||||
-f "$CTMS_ROOT_DIR/docker-compose.dev.yaml"
|
-f "$CTMS_ROOT_DIR/docker-compose.dev.yaml"
|
||||||
-p ctms_dev
|
-p ctms_dev
|
||||||
--profile office
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ctms_step "校验开发 Compose 配置"
|
ctms_step "校验开发 Compose 配置"
|
||||||
"${compose[@]}" config --quiet
|
"${compose[@]}" config --quiet
|
||||||
ctms_ok "Compose 配置有效"
|
ctms_ok "Compose 配置有效"
|
||||||
|
|
||||||
ctms_step "构建并启动 Office 预览服务"
|
ctms_step "重新构建并启动标准 ONLYOFFICE 服务"
|
||||||
"${compose[@]}" up -d --build --force-recreate backend onlyoffice nginx
|
"${compose[@]}" up -d --build --force-recreate backend onlyoffice nginx
|
||||||
|
|
||||||
ctms_step "验证运行状态"
|
ctms_step "验证运行状态"
|
||||||
|
|||||||
Reference in New Issue
Block a user