# FLNXI 素材库部署说明 本文档是当前主应用部署入口,合并了原来的快速部署、部署前检查清单和完整部署说明。 先说结论: - 客户或私有化交付默认按 `NAS(网络存储)` / `Linux(服务器系统)` 现场参数部署。 - 固定服务器、固定端口、固定 Registry 地址只属于内部维护示例,不是客户默认交付口径。 - 客户交付必须显式固定完整 `APP_IMAGE`,例如 `registry.example.com/flnxi/material/flnxi-material:1.0.1`;不要把 `latest` 当成客户部署依据。 - `deploy-registry.ps1` 不再默认指向任何测试服务器,发布和远程部署必须显式传入 `-RegistryHost`,远程部署还必须显式传入 `-Server`。 - 不同品牌 NAS 或客户自有 Linux 服务器交付前,先看 `docs/deployment/多品牌 NAS 与 Linux 交付差异清单.md`。 ## 1. 当前部署形态 主应用生产编排文件: ```bash docker-compose.prod.yml ``` 当前会拉起: - `postgres`:PostgreSQL 数据库 - `minio`:MinIO 对象存储 - `minio-init`:初始化对象存储桶 - `app`:FLNXI 素材库主应用 当前主应用镜像以 Registry 发布链路为准,实际部署时可通过 `.env` 中的 `APP_IMAGE`、`POSTGRES_IMAGE`、`MINIO_IMAGE`、`MINIO_MC_IMAGE` 覆盖。容器名、卷名、网络名和端口也支持用 `.env` 覆盖,下面命令中的 `flnxi-material` 和 `4320` 都只是默认值。 `APP_IMAGE` 是生产启动必填项。这样做是为了让客户现场明确运行哪个版本,避免安装或升级时误拉旧仓库、旧测试镜像或 `latest`。 根目录 `docker-compose.yml` 是本地/历史维护入口,不是客户正式安装入口。客户交付、NAS 和 Linux 私有化部署统一以 `docker-compose.prod.yml + .env` 为准。 当前不会由该 Compose 文件直接拉起: - Nginx / Traefik 等反向代理 - 独立 `license-server` - Node 版或 Go 版安装 Agent 这些组件根据交付场景单独部署或由安装 Agent 编排。 独立许可证服务的默认编排在 `license-server/docker-compose.yml`。该编排会由 Nginx 对外暴露 `9527`,再反代到内部 `license-server:3000`;应用容器不再直接暴露宿主机端口。这样登录和 API 限流配置会进入默认链路,避免验证服务器在低配置机器上被暴力请求直接打到 Next 服务。 ## 2. 部署前准备 ### 2.1 机器条件 建议最低条件: - CPU:4 核及以上 - 内存:8GB 及以上 - 磁盘:100GB 可用空间 - 系统:Ubuntu 22.04 LTS、群晖 DSM、飞牛 fnOS 或其他支持 Docker 的 Linux 环境 - Docker:Docker 24+ 和 Docker Compose V2 当前主线安装命令按 Docker Compose 验证。Podman / 图形化容器套件属于目标兼容方向,但不同 NAS 的网络、卷权限和健康检查差异很大,客户交付前必须单独实机验证,不能直接把本文的 Docker 命令等同为 Podman 已完整支持。 ### 2.2 必填环境变量 部署前至少准备: ```env POSTGRES_PASSWORD= MINIO_ROOT_USER= MINIO_ROOT_PASSWORD= APP_IMAGE=registry.example.com/flnxi/material/flnxi-material:1.0.1 SERVER_IP=192.168.x.x APP_PUBLIC_URL=http://192.168.x.x:4320 NEXTAUTH_URL=http://192.168.x.x:4320 NEXTAUTH_SECRET= S3_BUCKET=flnxi-materials LICENSE_SERVER_URL=https://your-license-server.example.com LICENSE_PROJECT_CODE=flnxi-sucai LICENSE_REQUEST_SIGNING_SECRET= LICENSE_PUBLIC_KEY= LOCAL_ENCRYPTION_KEY= MAX_UPLOAD_FILE_SIZE_BYTES=10737418240 MAX_UPLOAD_TOTAL_FILE_SIZE_BYTES=10737418240 MAX_UPLOAD_FIELD_SIZE_BYTES=2097152 ``` 说明: - `SERVER_IP` 必须是用户浏览器能访问到的 NAS / 服务器地址。 - `APP_PUBLIC_URL` 必须和最终访问入口一致,用于生成公开访问、分享和回调相关地址。 - `NEXTAUTH_URL` 必须和最终访问入口一致。 - `APP_IMAGE` 必须写完整镜像站地址和版本号,例如 `registry.example.com:5000/flnxi/material/flnxi-material:1.0.1`;不要只写 `flnxi-material:1.0.1` 或 `latest`。 - `POSTGRES_IMAGE`、`MINIO_IMAGE`、`MINIO_MC_IMAGE` 建议同样固定版本;离线或受控网络交付时,应写成私有 Registry 里的固定版本镜像。 - `LICENSE_PROJECT_CODE` 必须和 `license-server` 中项目表的 `projects.code` 一致。 - `LICENSE_REQUEST_SIGNING_SECRET` 必须和 `license-server` 的同名变量一致,至少 32 字符,用于主应用到验证服务器的请求签名。 - `LICENSE_PUBLIC_KEY` 是许可证服务签发许可证时使用的 RSA 公钥,主应用靠它确认许可证没有被伪造。 - `LOCAL_ENCRYPTION_KEY` 用于主应用本地加密保存许可证缓存,至少 32 字符,不能使用示例值。 - 付费模块核心本体走镜像站,不走验证服务器大文件下载;`license-server` 需要配置 `PREMIUM_MODULE_REGISTRY_BASE` 和 `PREMIUM_MODULE_VERSION`,用于给客户实例下发签名模块清单。 - `MAX_UPLOAD_FILE_SIZE_BYTES` 是单个素材文件上限;`MAX_UPLOAD_TOTAL_FILE_SIZE_BYTES` 是一次上传请求总上限;`MAX_UPLOAD_FIELD_SIZE_BYTES` 是表单文字字段总上限。示例值分别是 10GB、10GB、2MB,低配 NAS 可按客户机器内存和磁盘调小。 - 不要把真实密码、许可证地址、对象存储密钥写入 Git。 数据库有两种模式: - 内置 PostgreSQL:`DATABASE_URL` 留空或不写,由 `docker-compose.prod.yml` 按 `POSTGRES_USER`、`POSTGRES_PASSWORD`、`POSTGRES_DB` 自动拼接到 `postgres` 服务。 - 外部 PostgreSQL:才填写真实 `DATABASE_URL`,例如 `postgresql://flnxi:@192.168.1.10:5432/flnxi?sslmode=disable`。 - 商业首版更推荐内置 PostgreSQL,升级脚本可以自动备份和回滚。若客户坚持使用外部 PostgreSQL,升级前必须先完成客户侧数据库备份;执行 `deploy-registry.ps1` 时需显式加 `-ExternalDataBackupConfirmed`,否则脚本会中止升级。 对象存储也有两种模式: - 内置 MinIO:`S3_ENDPOINT=http://minio:9000`,`S3_ACCESS_KEY_ID` / `S3_SECRET_ACCESS_KEY` 可不填,Compose 会使用 `MINIO_ROOT_USER` / `MINIO_ROOT_PASSWORD`。`S3_PUBLIC_DOMAIN` 必须写成用户浏览器能访问的地址,例如 `http://192.168.1.20:9000/flnxi-materials`。 - 内置 MinIO 的 API 端口默认通过 `MINIO_API_BIND_HOST=0.0.0.0` 对浏览器可访问地址开放,用于素材预览和下载;管理控制台端口默认通过 `MINIO_CONSOLE_BIND_HOST=127.0.0.1` 只绑定本机。只有明确需要从局域网访问 MinIO 管理界面时,才把 `MINIO_CONSOLE_BIND_HOST` 改成服务器局域网 IP,并配合防火墙限制来源。 - 外部 S3 / 外部 MinIO:需要填写真实 `S3_ENDPOINT`、`S3_ACCESS_KEY_ID`、`S3_SECRET_ACCESS_KEY`、`S3_BUCKET`、`S3_PUBLIC_DOMAIN`,并确认 bucket 已存在或当前账号有创建和读写权限。 - 商业首版更推荐内置 MinIO,升级脚本可以自动备份素材对象。若使用外部 S3 / MinIO,升级前必须先完成客户侧 bucket / 对象备份;执行 `deploy-registry.ps1` 时同样需显式加 `-ExternalDataBackupConfirmed`。 NAS 或 Linux 服务器上建议提前准备挂载目录: ```bash mkdir -p uploads data chown -R 1001:1001 uploads data chmod 775 uploads data ``` 如果客户系统启用了更严格的用户权限,需让运行主应用容器的用户可以写入这两个目录;当前镜像内应用用户通常按 UID `1001` 理解。飞牛 / NAS 场景里,第一次手工创建目录如果是 root 所有权,单纯 `chmod 775` 可能还是不够,优先把目录属主改成 `1001:1001`。最简单的验收标准是:容器启动后能上传素材,`uploads/` 和 `data/` 没有持续出现权限拒绝日志。 ### 2.3 HTTP Registry 前置检查 如果 Registry 使用 `http://`,本机 Docker 和目标机器 Docker 都要先允许这个 Registry。否则会出现 `HTTP response to HTTPS client`,表现为登录、推送或拉取镜像失败。 Linux 目标机常见配置: ```json { "insecure-registries": ["registry.example.com:5000"] } ``` 配置位置通常是 `/etc/docker/daemon.json`。改完后重启 Docker: ```bash sudo systemctl restart docker docker info | grep -A 5 "Insecure Registries" ``` Docker Desktop 需要在设置里的 Docker Engine 配置同样的 `insecure-registries`,保存并重启 Docker。 ## 3. 标准部署步骤 ### 3.1 区分首装和升级 当前交付链路分三段看,不能混成一个命令: - 发布方构建和推送镜像:使用 `deploy-registry.ps1` 的发布动作,产出固定版本镜像。 - 客户首次安装:在目标机器准备部署目录、`docker-compose.prod.yml`、`.env`、数据卷和固定版本镜像,然后启动 Compose。 - 已有客户升级:使用 `deploy-registry.ps1 -Action DeployApp` 写入新 `APP_IMAGE`,并执行备份、拉取、迁移、健康检查和失败回滚。 `deploy-registry.ps1 -Action DeployApp` 默认假设远端已经有部署目录、生产 Compose 和 `.env`,它是升级/远程更新入口,不是单独完整的首装向导。 ### 3.2 准备环境文件 在目标机器部署目录准备 `.env`: ```bash cp .env.example .env ``` 再按实际环境补齐数据库、MinIO、NextAuth、许可证和访问地址。首装使用内置 PostgreSQL 时,不要给 `DATABASE_URL` 填占位连接串;外部 PostgreSQL 才填写真实连接串。 ### 3.3 启动服务 正式客户交付先通过 `deploy-registry.ps1` 完成版本化镜像发布,并把远端 `.env` 里的 `APP_IMAGE` 写到目标版本,再执行下面的启动命令。 ```bash docker compose -f docker-compose.prod.yml up -d ``` 生产 Compose 只读取 `APP_IMAGE`,不包含 `build:`。如果需要重新构建镜像,应在发布方机器使用 `deploy-registry.ps1` 或内部构建脚本先生成版本镜像,再更新 `.env`。 离线或受控网络交付时,启动前还要确认 `APP_IMAGE`、`POSTGRES_IMAGE`、`MINIO_IMAGE`、`MINIO_MC_IMAGE` 都已经在目标机器 Docker 或客户私有 Registry 中存在。否则 `docker compose up -d` 会因为无法拉取镜像而失败。 ### 3.4 初始化数据库 主应用容器入口脚本 `scripts/docker-entrypoint.sh` 会在启动时自动执行: ```bash npx prisma migrate deploy ``` 所以常规部署不需要手动再跑一次数据库迁移。 如果历史模板数据需要补齐,或自动迁移失败后要人工补救,再按实际容器名执行: ```bash docker exec npm run migrate:template-data docker exec npm run verify:template-data ``` 默认容器名是 `flnxi-material`;如果 `.env` 配了 `APP_CONTAINER_NAME`,以实际值为准。 如是全新环境,继续按 `docs/初次部署与出厂设置指南.md` 走系统初始化流程。 ### 3.5 验证服务 ```bash docker compose -f docker-compose.prod.yml ps curl http://:4320/api/health docker logs flnxi-material --tail 100 ``` `/api/health` 返回 `200` 表示应用启动检查已通过;如果返回 `503`,先查看 `docker logs flnxi-material --tail 100`,通常是数据库连接、迁移或内置模板初始化未完成。 如果 `.env` 覆盖了 `APP_PORT` 或 `APP_CONTAINER_NAME`,验证命令也要同步替换成实际端口和容器名。 页面验证: - 登录页:`http://:4320/login` - 首页:`http://:4320` - 管理后台:`http://:4320/admin` - 模板管理:在 `http://:4320/admin` 后台内打开;当前没有独立的 `/admin/templates` 路由 ## 4. 版本化 Registry 发布 当前仓库的主发布脚本是 `deploy-registry.ps1`,用于构建、推送和远程更新主应用、Agent 以及运行时镜像。它默认会把版本镜像写入远端 `.env`,客户升级不要再回退到默认 `latest`。 `DeployApp` 远程部署现在默认包含第一轮升级保护: - 升级前在远端创建 `backups/deploy-时间戳/`,保存升级前 `.env`。 - 发现已有 app 容器运行时,会先短暂停止 app,让系统进入升级维护窗口,减少备份期间继续上传、编辑或删除素材造成的数据库和对象存储不一致。 - 如果远端 PostgreSQL 是当前 Compose 管理的 `postgres` 服务,会先执行 `pg_dump` 备份;如果使用外部数据库,会提示需要确认外部备份。 - 如果远端 MinIO 是当前 Compose 管理的 `minio` 服务,会先把 `MINIO_VOLUME_NAME` 对应的数据卷打包备份;如果使用外部 S3 / 外部 MinIO,会在备份目录写入提示文件,要求按客户现场方案单独备份对象存储。 - 备份目录会生成 `RESTORE_PLAN.txt`,把本次 `.env`、PostgreSQL、MinIO 备份文件和 L1/L2/L3 恢复命令列出来,便于升级失败时按影响范围恢复。 - 部署失败时默认尝试恢复升级前 `.env`,并按旧运行镜像或旧 `APP_IMAGE` 重建应用容器。 - 部署后会在远端校验应用容器实际运行镜像、镜像内 `VERSION.txt` 和 Prisma 迁移状态,然后再做外部 `/api/health` 检查。 只有在已有其它备份和回滚体系时,才考虑使用 `-NoRemoteDbBackup`、`-NoRemoteObjectStorageBackup` 或 `-NoRollback`。离线客户现场如果没有 `busybox:1.36`,需要先把该 helper 镜像放到目标机,或通过 `-RemoteBackupHelperImage` 指定现场已有的小型 Linux 镜像。 必须注意:脚本的自动回滚只恢复应用镜像和 `.env`,不自动恢复数据库和对象存储。只要本次升级包含数据库迁移或素材文件结构变化,升级前的数据库备份和对象存储备份就必须保留,并按 `RESTORE_PLAN.txt` 的 L2/L3 步骤由人工确认后恢复。 典型用法: ```powershell $registryPassword = Read-Host 'Registry密码' -AsSecureString $sshPassword = Read-Host 'SSH密码' -AsSecureString .\deploy-registry.ps1 -Action DeployApp -DeployChannel release -Version 1.0.1 -RegistryHost registry.example.com:5000 -Server 192.168.1.20 -RegistryPassword $registryPassword -Password $sshPassword .\deploy-registry.ps1 -Action PublishRelease -Version 1.0.1 -RegistryHost registry.example.com:5000 -RegistryPassword $registryPassword .\deploy-registry.ps1 -Action PublishAgent -Version 1.0.1 -RegistryHost registry.example.com:5000 -RegistryPassword $registryPassword .\deploy-registry.ps1 -Action SyncRuntime -RegistryHost registry.example.com:5000 -RegistryPassword $registryPassword ``` 说明: - 客户升级和内部发布优先按版本 tag 走,不要把 `latest` 当成客户部署依据。 - 客户现场部署使用 `-DeployChannel release -Version x.x.x`;测试通道只用于内部验证,必须显式传 `-DeployChannel test`。 - 客户 SSH 端口、登录用户和部署目录必须按现场显式确认;脚本默认端口是常见的 `22`,默认目录是 `/opt/flnxi`,内部测试机或自定义环境要显式传 `-SshPort`、`-Username`、`-RemotePath`。 - `DeployApp` 远程部署时默认会更新远端 `.env` 的 `APP_IMAGE`、访问地址和运行时镜像;只有临时验证时才使用 `-NoUpdateRemoteEnv`。 - `DeployApp` 默认会做远端维护窗口停写入、`.env` 备份、Compose PostgreSQL 备份、Compose MinIO 备份、恢复分级说明、失败自动回滚、运行镜像校验、版本文件校验和 Prisma 迁移状态校验。 - 旧的 `deploy-new-fixed.ps1` 仍可作为内部维护参考,但不再作为当前主线部署入口。 - 如果要做远程更新,先确认 `Registry`、SSH、`.env` 和目标机器都属于当前维护环境。 ### 4.1 镜像体积基线 发布前可以对主应用镜像做一次体积和分层记录: ```powershell .\scripts\measure-image-size.ps1 ` -Image "registry.example.com/flnxi/material/flnxi-material:1.0.1" ` -OutputPath ".\reports\image-size-1.0.1.md" ` -MaxImageSizeMB 650 ` -MaxLayerCount 80 ` -MaxLargestLayerMB 250 ``` 这个脚本不会改镜像,只会读取 Docker 本地镜像信息,列出总大小、层数和最大的若干层。传入 `-MaxImageSizeMB`、`-MaxLayerCount` 或 `-MaxLargestLayerMB` 后,超出阈值会以非 0 退出,适合发布前挡住明显变胖的镜像。后续做镜像瘦身时,先用这个报告确认是 `ffmpeg`、字体、`canvas`、`node_modules` 还是 Prisma 迁移工具占用更大,再决定是否拆成可选能力或独立迁移镜像。 ## 5. 部署前检查清单 - [ ] 已确认目标机器品牌、系统和 Docker Compose 支持情况;如使用 Podman,已单独实机验证 - [ ] 已确认端口、域名、证书、反向代理方案 - [ ] 已确认数据目录、对象存储目录和备份位置 - [ ] 已确认升级失败时使用 L1 应用回滚、L2 数据库恢复还是 L3 数据库+素材恢复 - [ ] `.env` 已填写真实环境变量;内置 PostgreSQL 模式下 `DATABASE_URL` 没有错误占位值 - [ ] `APP_IMAGE` 已固定到完整版本镜像,不使用 `latest` - [ ] 如果 Registry 是 HTTP,本机和目标机 Docker 都已配置 `insecure-registries` - [ ] `NEXTAUTH_URL` 与最终访问地址一致 - [ ] `S3_BUCKET`、`S3_PUBLIC_DOMAIN` 口径正确 - [ ] `LICENSE_SERVER_URL` 和 `LICENSE_PROJECT_CODE` 已确认 - [ ] `LICENSE_REQUEST_SIGNING_SECRET` 已配置且与许可证服务一致 - [ ] `LICENSE_PUBLIC_KEY`、`LOCAL_ENCRYPTION_KEY` 已配置为真实值 - [ ] `uploads/`、`data/` 目录对应用容器可写 - [ ] 已执行与本次改动相关的测试或命令 - [ ] 涉及数据库变更时已有备份和回滚方案 ## 6. 部署后冒烟测试 NAS / Linux 客户现场优先使用 `.sh` 脚本。如果当前账号没有 Docker 权限,就用 `sudo bash ...` 执行。 启动前可以先做一轮不启动容器的安装前检查: ```bash bash scripts/smoke-install.sh --project-dir /opt/flnxi --preflight-only ``` 如果希望给实施人员一个更像向导的入口,可以先只看步骤: ```bash bash scripts/customer-install.sh --project-dir /opt/flnxi --plan-only ``` 确认 `.env`、镜像和数据目录都准备好后,让脚本按步骤预检、启动并验收: ```bash sudo bash scripts/customer-install.sh --project-dir /opt/flnxi --prepare-directories --start --expect-version 1.0.1 ``` `customer-install.sh` 只是对 `smoke-install.sh` 的分步骤包装,不替代 `docker-compose.prod.yml`,也不把 Agent 当成唯一安装入口。`--prepare-directories` 在 root / sudo 运行时会把 `uploads/` 和 `data/` 调整为应用容器 UID `1001` 可写,能提前拦截飞牛 / NAS 常见目录权限问题。 Windows 实施机或已安装 PowerShell 的现场,可以使用对应 `.ps1` 脚本: ```powershell .\scripts\smoke-install.ps1 -ProjectDir "D:\deploy\flnxi" -PreflightOnly ``` 如果希望给实施人员一个更像向导的入口,可以先只看步骤: ```powershell .\scripts\customer-install.ps1 -ProjectDir "D:\deploy\flnxi" -PlanOnly ``` 确认 `.env`、镜像和数据目录都准备好后,让脚本按步骤预检、启动并验收: ```powershell .\scripts\customer-install.ps1 -ProjectDir "D:\deploy\flnxi" -PrepareDirectories -Start -ExpectedVersion 1.0.1 ``` `customer-install.ps1` 只是对 `smoke-install.ps1` 的分步骤包装,不替代 `docker-compose.prod.yml`,也不把 Agent 当成唯一安装入口。 如果是新目录,还希望脚本顺手创建 `uploads/` 和 `data/`,可以加: ```powershell .\scripts\smoke-install.ps1 -ProjectDir "D:\deploy\flnxi" -PreflightOnly -PrepareDirectories ``` 这一步会提前拦截 `.env` 示例值、`latest` 镜像、缺失数据目录和明显错误的访问地址,避免等容器启动失败后再排查。 首装后优先使用脚本做基础验收: ```powershell .\scripts\smoke-install.ps1 -ProjectDir "D:\deploy\flnxi" -Start -ExpectedVersion 1.0.1 ``` 如果服务已经由 NAS 图形界面或其他编排入口启动,可以去掉 `-Start`,只做检查: ```powershell .\scripts\smoke-install.ps1 -ProjectDir "D:\deploy\flnxi" ``` 这些脚本会先做安装前检查,再检查 Compose 配置、容器状态、应用运行镜像、镜像内版本文件、Prisma 迁移状态、MinIO bucket 和 `/api/health`。建议每次首装或升级验收都带上期望版本,`.sh` 使用 `--expect-version x.x.x`,`.ps1` 使用 `-ExpectedVersion x.x.x`,脚本会同时确认容器内 `VERSION.txt` 和浏览器访问入口 `/api/health` 返回的版本,避免现场访问地址指到旧服务。如果客户使用外部对象存储,`.sh` 脚本加 `--skip-object-storage-check`,`.ps1` 脚本加 `-SkipObjectStorageCheck`,对象存储验收按客户现场方案单独执行。 人工验收命令仍保留如下: - [ ] `/api/health` 正常 - [ ] 登录 / 退出正常 - [ ] 首次初始化或激活流程正常 - [ ] 首页素材列表可加载 - [ ] 素材上传、预览、下载正常 - [ ] 后台模板管理可打开 - [ ] 系统设置可读取和保存 - [ ] 许可证状态显示正确 - [ ] 容器日志没有持续错误 如果需要一条命令做客户业务验收,可在实施机或部署机上运行: ```bash npm run smoke:customer -- \ --base-url http://:4320 \ --expect-version 1.0.1 ``` 提供临时验收账号后,可以继续验登录、后台权限和模板接口: ```bash npm run smoke:customer -- \ --base-url http://:4320 \ --expect-version 1.0.1 \ --email \ --password ``` 需要真实验证数据库和 MinIO 写入时,加 `--write`。该动作会创建一条小素材验收记录,建议只在测试环境或客户允许的验收窗口执行: ```bash npm run smoke:customer -- \ --base-url http://:4320 \ --expect-version 1.0.1 \ --email \ --password \ --write ``` 不要把验收账号密码写入文档、Git 或聊天记录;如果使用 `.env.smoke`,该文件也必须留在本机,不进入仓库。 ## 7. 数据备份与回滚 `deploy-registry.ps1 -Action DeployApp` 会默认做一轮升级前备份和失败回滚。下面命令主要用于人工兜底、外部数据库场景或单独恢复演练。 ### 7.1 一键备份 首选脚本: NAS / Linux: ```bash sudo bash scripts/backup-restore.sh --project-dir /opt/flnxi --action backup ``` Windows / PowerShell: ```powershell .\scripts\backup-restore.ps1 -ProjectDir "D:\deploy\flnxi" -Action Backup ``` 默认备份内容: - `.env` - `docker-compose.prod.yml` - `VERSION.txt`,如果部署目录里存在 - `compose-config.txt`、`compose-ps.txt`、`docker-images.txt` - Compose 管理的 PostgreSQL:`postgres.sql` - Compose 管理的 MinIO 数据卷:`minio-data.tar.gz` - 本地挂载目录:`data.zip`、`uploads.zip`,用于保留许可证实例数据和历史本地上传残留 - `manifest.json`:记录备份时间、应用镜像、访问地址、服务名等关键信息 备份脚本默认也会在备份期间短暂停止 app,并在备份结束后恢复启动,目的是让数据库、MinIO、`data/`、`uploads/` 尽量处在同一个时间点。只有客户现场已经有其它停写入机制时,才考虑加 `-SkipStopAppForBackup`。 备份包里会包含 `.env`、数据库内容和客户素材文件,通常也就包含访问密钥、许可证缓存和企业内部资料。备份目录必须放在受控位置,按客户现场要求加密或限权保存,不能提交到 Git,也不能随意发到聊天工具。 `DeployApp` 升级时生成的 `backups/deploy-时间戳/RESTORE_PLAN.txt` 是升级恢复指引;`backup-restore.ps1 -Action Backup` 生成的 `flnxi-backup-时间戳/manifest.json` 是完整备份包记录。两者用途不同,客户升级失败时优先看当次升级目录里的 `RESTORE_PLAN.txt`。 如果 `DATABASE_URL` 指向外部 PostgreSQL,脚本不会假装自动备份,会在备份目录写入 `EXTERNAL_DATABASE_BACKUP_REQUIRED.txt`,客户现场必须按外部数据库方案单独备份。 如果对象存储是外部 S3 / 外部 MinIO,或现场已有独立对象存储快照,可加: ```bash sudo bash scripts/backup-restore.sh --project-dir /opt/flnxi --action backup --skip-object-storage-backup ``` ```powershell .\scripts\backup-restore.ps1 -ProjectDir "D:\deploy\flnxi" -Action Backup -SkipObjectStorageBackup ``` 内置 MinIO 备份/恢复默认使用 `busybox:1.36` 作为 helper 镜像。离线客户现场需要提前把该镜像放进 Docker,或通过 `-HelperImage` 指定现场已有的 Linux 工具镜像。 ### 7.2 一键验收 NAS / Linux: ```bash bash scripts/backup-restore.sh --project-dir /opt/flnxi --action verify ``` Windows / PowerShell: ```powershell .\scripts\backup-restore.ps1 -ProjectDir "D:\deploy\flnxi" -Action Verify ``` 该动作会检查 Compose 配置、容器状态和 `/api/health`,适合备份前、恢复后、升级后快速确认系统是否可用。 ### 7.3 一键恢复 恢复会覆盖客户数据,必须停写入并确认备份来源正确。脚本要求输入固定确认短语,避免误操作: NAS / Linux: ```bash sudo bash scripts/backup-restore.sh \ --project-dir /opt/flnxi \ --action restore \ --backup-path /opt/flnxi/backups/flnxi-backup-YYYYMMDD-HHMMSS \ --confirm-restore RESTORE_FLNXI_DATA ``` Windows / PowerShell: ```powershell .\scripts\backup-restore.ps1 ` -ProjectDir "D:\deploy\flnxi" ` -Action Restore ` -BackupPath "D:\deploy\flnxi\backups\flnxi-backup-YYYYMMDD-HHMMSS" ` -ConfirmRestore RESTORE_FLNXI_DATA ``` 说明: - 默认恢复 `postgres.sql`、`minio-data.tar.gz`、`data.zip` 和 `uploads.zip`,然后启动服务并执行健康验收。 - 如果只恢复数据库、不恢复对象存储,加 `-SkipObjectStorageRestore`。 - 如果需要把备份包中的 `.env` 一起恢复,加 `-RestoreEnv`;脚本会先把当前 `.env` 另存为 `.env.before-restore-时间戳`。 - 外部数据库和外部对象存储不受该脚本自动恢复,必须按客户现场备份方案操作。 ### 7.4 手动备份数据库 ```bash docker exec flnxi-postgres pg_dump \ -U postgres \ -d flnxi \ -F c \ -f /tmp/flnxi-backup-$(date +%Y%m%d-%H%M%S).dump ``` 再把备份文件复制到宿主机或外部备份位置。外部数据库不受 Compose 脚本管理,必须按客户现场数据库方案单独备份。 ### 7.5 手动回滚应用 如使用镜像部署,回滚到上一镜像版本时,直接改完整 `APP_IMAGE`。不要只改 `IMAGE_TAG`,因为完整 `APP_IMAGE` 的优先级更高。 ```bash docker compose -f docker-compose.prod.yml down cp .env .env.rollback-$(date +%Y%m%d-%H%M%S) sed -i 's#^APP_IMAGE=.*#APP_IMAGE=registry.example.com/flnxi/material/flnxi-material:#' .env docker compose -f docker-compose.prod.yml pull app docker compose -f docker-compose.prod.yml up -d app curl http://:4320/api/health ``` 回滚后 `/api/health` 仍必须返回 `200` 才算应用恢复可用。 回滚前先确认数据库是否需要同时回滚。只回滚应用镜像不等于回滚数据库结构;如果本次升级包含数据库迁移,必须先确认备份和恢复路径。 ### 7.6 手动恢复数据库 恢复前必须确认已停止会写入数据库的应用容器,并确认备份文件正确。下面给两种常见方式,二选一即可。 ```bash docker cp ./flnxi-backup-YYYYMMDD-HHMMSS.dump flnxi-postgres:/tmp/flnxi-restore.dump docker exec flnxi-postgres pg_restore \ -U postgres \ -d flnxi \ -c \ /tmp/flnxi-restore.dump ``` 或者直接从宿主机标准输入恢复: ```bash docker exec -i flnxi-postgres pg_restore \ -U postgres \ -d flnxi \ -c \ < ./flnxi-backup-YYYYMMDD-HHMMSS.dump ``` ## 8. 常见问题 ### 应用访问不到 优先检查: - `docker compose -f docker-compose.prod.yml ps` - `APP_PORT` 是否和访问端口一致 - `SERVER_IP` 和 `NEXTAUTH_URL` 是否填写成浏览器可访问地址 - 防火墙是否放通端口 ### 旧恢复接口被拒绝 `/api/restore-data` 是历史一次性数据恢复入口,不属于客户日常后台功能。客户环境默认应保持: ```env RESTORE_DATA_ENABLED=0 ``` 只有在受控恢复窗口才临时启用,并且必须同时满足: - `RESTORE_DATA_TOKEN` 至少 32 字符,不能使用示例值或短口令。 - `RESTORE_DATA_ALLOWED_IPS` 只写维护机来源 IP。 - 通过可信反向代理传递来源 IP 时,才设置 `RESTORE_DATA_TRUST_PROXY=1`;否则接口默认不信任 `x-forwarded-for`。 - 调用时必须同时带 `x-restore-data-token` 和 `x-restore-data-confirm: RESTORE_DATA`。 恢复完成后必须立刻把 `RESTORE_DATA_ENABLED` 改回 `0`,并重启应用容器。 ### MinIO 预览或下载异常 优先检查: - `S3_BUCKET` - `MINIO_ROOT_USER` - `MINIO_ROOT_PASSWORD` - `S3_PUBLIC_DOMAIN` - MinIO 控制台是否能看到桶和对象 - `S3_SET_ACL` 是否仍为默认 `0`。私有化交付默认不公开素材桶;只有兼容旧公开对象模式时才允许显式改成 `1`。 - 当前生产 Compose 的 `minio-init` 会默认执行 `mc anonymous set none`,用于关闭 MinIO 桶匿名下载。如果客户历史环境曾经公开过桶,升级后应重跑 `minio-init` 或手动执行同等命令确认桶已恢复私有。 - 外部 S3 或历史环境可能存在旧 bucket policy、旧对象级 ACL 或历史公开链接,这些不一定会被当前 `minio-init` 自动收回,升级前后要单独做只读审计。 ### 许可证异常 优先检查: - `LICENSE_SERVER_URL` - `LICENSE_PROJECT_CODE` - `LICENSE_REQUEST_SIGNING_SECRET` 是否与许可证服务一致 - 许可证服务是否存在对应项目编码 - 主应用 `/api/license/check`、`/api/license/verify` 响应 - 如果独立部署 `license-server/docker-compose.yml`,确认对外访问的是 Nginx 暴露的 `9527`,不是容器内部 `3000`。 - 如果请求返回 `429`,优先检查 Nginx 限流是否被触发,再看是否存在脚本重试、暴力激活或心跳频率异常。 ### 数据迁移失败 优先查看: ```bash docker logs flnxi-material --tail 200 docker exec flnxi-material npx prisma validate docker exec flnxi-material npm run verify:template-data ``` ## 9. 相关文档 - `docs/初次部署与出厂设置指南.md` - `docs/deployment/多品牌 NAS 与 Linux 交付差异清单.md` - `docs/许可证服务接入说明.md` - `scripts/README.md`