22 KiB
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. 当前部署形态
主应用生产编排文件:
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 必填环境变量
部署前至少准备:
POSTGRES_PASSWORD=<generate-a-strong-random-password>
MINIO_ROOT_USER=<generate-a-storage-admin-user>
MINIO_ROOT_PASSWORD=<generate-a-strong-random-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=<generate-a-strong-random-secret>
S3_BUCKET=flnxi-materials
LICENSE_SERVER_URL=https://your-license-server.example.com
LICENSE_PROJECT_CODE=flnxi-sucai
LICENSE_REQUEST_SIGNING_SECRET=<generate-a-shared-license-request-secret>
LICENSE_PUBLIC_KEY=<license-server-rsa-public-key>
LOCAL_ENCRYPTION_KEY=<generate-a-32-char-or-longer-local-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必须写完整镜像地址和版本号,不要只写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 字符,不能使用示例值。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:<password>@192.168.1.10:5432/flnxi?sslmode=disable。
对象存储也有两种模式:
- 内置 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。 - 外部 S3 / 外部 MinIO:需要填写真实
S3_ENDPOINT、S3_ACCESS_KEY_ID、S3_SECRET_ACCESS_KEY、S3_BUCKET、S3_PUBLIC_DOMAIN,并确认 bucket 已存在或当前账号有创建和读写权限。
NAS 或 Linux 服务器上建议提前准备挂载目录:
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 目标机常见配置:
{
"insecure-registries": ["registry.example.com:5000"]
}
配置位置通常是 /etc/docker/daemon.json。改完后重启 Docker:
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:
cp .env.example .env
再按实际环境补齐数据库、MinIO、NextAuth、许可证和访问地址。首装使用内置 PostgreSQL 时,不要给 DATABASE_URL 填占位连接串;外部 PostgreSQL 才填写真实连接串。
3.3 启动服务
正式客户交付先通过 deploy-registry.ps1 完成版本化镜像发布,并把远端 .env 里的 APP_IMAGE 写到目标版本,再执行下面的启动命令。
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 会在启动时自动执行:
npx prisma migrate deploy
所以常规部署不需要手动再跑一次数据库迁移。
如果历史模板数据需要补齐,或自动迁移失败后要人工补救,再按实际容器名执行:
docker exec <APP_CONTAINER_NAME> npm run migrate:template-data
docker exec <APP_CONTAINER_NAME> npm run verify:template-data
默认容器名是 flnxi-material;如果 .env 配了 APP_CONTAINER_NAME,以实际值为准。
如是全新环境,继续按 docs/初次部署与出厂设置指南.md 走系统初始化流程。
3.5 验证服务
docker compose -f docker-compose.prod.yml ps
curl http://<SERVER_IP>: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://<SERVER_IP>:4320/login - 首页:
http://<SERVER_IP>:4320 - 管理后台:
http://<SERVER_IP>:4320/admin - 模板管理:在
http://<SERVER_IP>:4320/admin后台内打开;当前没有独立的/admin/templates路由
4. 版本化 Registry 发布
当前仓库的主发布脚本是 deploy-registry.ps1,用于构建、推送和远程更新主应用、Agent 以及运行时镜像。它默认会把版本镜像写入远端 .env,客户升级不要再回退到默认 latest。
DeployApp 远程部署现在默认包含第一轮升级保护:
- 升级前在远端创建
backups/deploy-时间戳/,保存升级前.env。 - 如果远端 PostgreSQL 是当前 Compose 管理的
postgres服务,会先执行pg_dump备份;如果使用外部数据库,会提示需要确认外部备份。 - 如果远端 MinIO 是当前 Compose 管理的
minio服务,会先把MINIO_VOLUME_NAME对应的数据卷打包备份;如果使用外部 S3 / 外部 MinIO,会在备份目录写入提示文件,要求按客户现场方案单独备份对象存储。 - 部署失败时默认尝试恢复升级前
.env,并按旧运行镜像或旧APP_IMAGE重建应用容器。 - 部署后会在远端校验应用容器实际运行镜像、镜像内
VERSION.txt和 Prisma 迁移状态,然后再做外部/api/health检查。
只有在已有其它备份和回滚体系时,才考虑使用 -NoRemoteDbBackup、-NoRemoteObjectStorageBackup 或 -NoRollback。离线客户现场如果没有 busybox:1.36,需要先把该 helper 镜像放到目标机,或通过 -RemoteBackupHelperImage 指定现场已有的小型 Linux 镜像。
必须注意:脚本的自动回滚只恢复应用镜像和 .env,不自动恢复数据库和对象存储。只要本次升级包含数据库迁移或素材文件结构变化,升级前的数据库备份和对象存储备份就必须保留,必要时由人工确认后恢复。
典型用法:
$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。 DeployApp远程部署时默认会更新远端.env的APP_IMAGE、访问地址和运行时镜像;只有临时验证时才使用-NoUpdateRemoteEnv。DeployApp默认会做远端.env备份、Compose PostgreSQL 备份、失败自动回滚、运行镜像校验、版本文件校验和 Prisma 迁移状态校验。- 旧的
deploy-new-fixed.ps1仍可作为内部维护参考,但不再作为当前主线部署入口。 - 如果要做远程更新,先确认
Registry、SSH、.env和目标机器都属于当前维护环境。
5. 部署前检查清单
- 已确认目标机器品牌、系统和 Docker Compose 支持情况;如使用 Podman,已单独实机验证
- 已确认端口、域名、证书、反向代理方案
- 已确认数据目录、对象存储目录和备份位置
.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. 部署后冒烟测试
启动前可以先做一轮不启动容器的安装前检查:
.\scripts\smoke-install.ps1 -ProjectDir "D:\deploy\flnxi" -PreflightOnly
如果是新目录,还希望脚本顺手创建 uploads/ 和 data/,可以加:
.\scripts\smoke-install.ps1 -ProjectDir "D:\deploy\flnxi" -PreflightOnly -PrepareDirectories
这一步会提前拦截 .env 示例值、latest 镜像、缺失数据目录和明显错误的访问地址,避免等容器启动失败后再排查。
首装后优先使用脚本做基础验收:
.\scripts\smoke-install.ps1 -ProjectDir "D:\deploy\flnxi" -Start
如果服务已经由 NAS 图形界面或其他编排入口启动,可以去掉 -Start,只做检查:
.\scripts\smoke-install.ps1 -ProjectDir "D:\deploy\flnxi"
该脚本会先做安装前检查,再检查 Compose 配置、容器状态、应用运行镜像、镜像内版本文件、Prisma 迁移状态、MinIO bucket 和 /api/health。如果客户使用外部对象存储,加 -SkipObjectStorageCheck,对象存储验收按客户现场方案单独执行。
人工验收命令仍保留如下:
/api/health正常- 登录 / 退出正常
- 首次初始化或激活流程正常
- 首页素材列表可加载
- 素材上传、预览、下载正常
- 后台模板管理可打开
- 系统设置可读取和保存
- 许可证状态显示正确
- 容器日志没有持续错误
7. 数据备份与回滚
deploy-registry.ps1 -Action DeployApp 会默认做一轮升级前备份和失败回滚。下面命令主要用于人工兜底、外部数据库场景或单独恢复演练。
7.1 一键备份
首选脚本:
.\scripts\backup-restore.ps1 -ProjectDir "D:\deploy\flnxi" -Action Backup
默认备份内容:
.envdocker-compose.prod.ymlVERSION.txt,如果部署目录里存在compose-config.txt、compose-ps.txt、docker-images.txt- Compose 管理的 PostgreSQL:
postgres.sql - Compose 管理的 MinIO 数据卷:
minio-data.tar.gz manifest.json:记录备份时间、应用镜像、访问地址、服务名等关键信息
如果 DATABASE_URL 指向外部 PostgreSQL,脚本不会假装自动备份,会在备份目录写入 EXTERNAL_DATABASE_BACKUP_REQUIRED.txt,客户现场必须按外部数据库方案单独备份。
如果对象存储是外部 S3 / 外部 MinIO,或现场已有独立对象存储快照,可加:
.\scripts\backup-restore.ps1 -ProjectDir "D:\deploy\flnxi" -Action Backup -SkipObjectStorageBackup
内置 MinIO 备份/恢复默认使用 busybox:1.36 作为 helper 镜像。离线客户现场需要提前把该镜像放进 Docker,或通过 -HelperImage 指定现场已有的 Linux 工具镜像。
7.2 一键验收
.\scripts\backup-restore.ps1 -ProjectDir "D:\deploy\flnxi" -Action Verify
该动作会检查 Compose 配置、容器状态和 /api/health,适合备份前、恢复后、升级后快速确认系统是否可用。
7.3 一键恢复
恢复会覆盖客户数据,必须停写入并确认备份来源正确。脚本要求输入固定确认短语,避免误操作:
.\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,然后启动服务并执行健康验收。 - 如果只恢复数据库、不恢复对象存储,加
-SkipObjectStorageRestore。 - 如果需要把备份包中的
.env一起恢复,加-RestoreEnv;脚本会先把当前.env另存为.env.before-restore-时间戳。 - 外部数据库和外部对象存储不受该脚本自动恢复,必须按客户现场备份方案操作。
7.4 手动备份数据库
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 的优先级更高。
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:<previous-version>#' .env
docker compose -f docker-compose.prod.yml pull app
docker compose -f docker-compose.prod.yml up -d app
curl http://<SERVER_IP>:4320/api/health
回滚后 /api/health 仍必须返回 200 才算应用恢复可用。
回滚前先确认数据库是否需要同时回滚。只回滚应用镜像不等于回滚数据库结构;如果本次升级包含数据库迁移,必须先确认备份和恢复路径。
7.6 手动恢复数据库
恢复前必须确认已停止会写入数据库的应用容器,并确认备份文件正确。下面给两种常见方式,二选一即可。
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
或者直接从宿主机标准输入恢复:
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 psAPP_PORT是否和访问端口一致SERVER_IP和NEXTAUTH_URL是否填写成浏览器可访问地址- 防火墙是否放通端口
MinIO 预览或下载异常
优先检查:
S3_BUCKETMINIO_ROOT_USERMINIO_ROOT_PASSWORDS3_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_URLLICENSE_PROJECT_CODELICENSE_REQUEST_SIGNING_SECRET是否与许可证服务一致- 许可证服务是否存在对应项目编码
- 主应用
/api/license/check、/api/license/verify响应 - 如果独立部署
license-server/docker-compose.yml,确认对外访问的是 Nginx 暴露的9527,不是容器内部3000。 - 如果请求返回
429,优先检查 Nginx 限流是否被触发,再看是否存在脚本重试、暴力激活或心跳频率异常。
数据迁移失败
优先查看:
docker logs flnxi-material --tail 200
docker exec flnxi-material npx prisma validate
docker exec flnxi-material npm run verify:template-data
9. 相关文档
docs/初次部署与出厂设置指南.mddocs/deployment/多品牌 NAS 与 Linux 交付差异清单.mddocs/许可证服务接入说明.mdscripts/README.md