2512 字
13 分钟

OSS Hub 部署与工程化:从本地运行到生产迁移

OSS Hub 部署与工程化:从本地运行到生产迁移#

对象存储管理平台会接触 AccessKey、用户权限、文件删除和 Bucket 配置,因此“本地能跑”只是起点。

这篇文章整理 OSS Hub 从初始化到生产部署的完整链路,包括环境变量、数据库、构建产物、反向代理、OpenAPI、测试和演进边界。

运行要求#

项目要求 Node.js 20.12+22+,推荐使用 Node.js 22 或更高 LTS 版本。

根目录使用 npm workspaces 管理:

backend
frontend

安装一次依赖后,可以在根目录统一启动、构建、类型检查和测试。

本地快速开始#

最短初始化流程是:

Terminal window
cp .env.example .env
npm install
npm run prisma:generate
npm run prisma:migrate
npm run dev

默认地址:

  • 前端:http://localhost:10011
  • 后端:http://localhost:10010
  • 健康检查:http://localhost:10010/health
  • OpenAPI:http://localhost:10010/openapi.json

没有 SSO 时使用内置登录#

.env.example 默认偏向 SSO。如果本地没有身份服务,可以改成:

AUTH_MODE=local
VITE_AUTH_MODE=local
LOCAL_ADMIN_USERNAME=admin
LOCAL_ADMIN_PASSWORD=<本地强密码>

后端和前端的认证模式必须一致。

VITE_* 变量会进入前端构建产物,因此修改生产认证模式后需要重新构建前端。

本地管理员只在 localboth 模式,并且密码已配置时自动创建或补齐管理员权限。

SSO 配置#

SSO 模式需要配置:

  • Issuer。
  • Authorization Endpoint。
  • Token Endpoint。
  • JWKS URI。
  • Client ID。
  • Redirect URI。
  • Logout Endpoint 或退出跳转地址。
  • Audience 和权限 claim 规则。

前端负责 Authorization Code + PKCE,后端只接受 Bearer token 并执行 JWT/JWKS 验证。

生产环境需要确保:

  • 回调地址与 SSO 应用配置完全一致。
  • Issuer、Audience 和 JWKS 来源可信。
  • 全站使用 HTTPS。
  • 不在日志中记录完整 token。

第一条云存储#

首次启动且数据库为空时,后端会创建一条默认云存储记录。

如果 .env 中的对象存储配置完整,会加密写入数据库;如果还是占位值,登录后需要在“设置 -> 云存储配置”补充。

需要确认:

  • 云服务商分类。
  • SDK 协议。
  • Region 和 Bucket。
  • AccessKey ID 与 Secret。
  • 后端 SDK Endpoint。
  • 公共访问域名。
  • S3 是否使用 Path Style。

浏览器直传需要 Bucket CORS#

前端把文件直接 PUT 到对象存储,因此浏览器检查的是 Bucket CORS,而不是 OSS Hub API 的 CORS。

至少需要根据实际上传方式允许:

  • OSS Hub 页面域名。
  • PUTPOSTGETHEAD 等方法。
  • Content-Type、ACL、存储类型和 Object 标签相关请求头。
  • 暴露 ETagetag 响应头。

如果目录浏览正常、后端 API 正常,但浏览器上传失败,最先检查的应当是 Bucket CORS。

分片上传能成功完成单个 PUT,却在最后提示缺少 ETag,也通常是因为没有暴露响应头。

开发与生产构建#

开发环境:

Terminal window
npm run dev

生产构建:

Terminal window
npm run build

根构建流程会:

  1. 编译后端 TypeScript。
  2. 类型检查并构建 Vue 前端。
  3. 把前端产物复制到后端静态目录。
  4. 检查生产构建是否完整。

生产运行时由 Fastify 同时提供 API 和前端静态资源:

Terminal window
npm run start

这样反向代理只需要指向一个后端端口,避免分别部署两个服务。

flowchart LR U[用户] --> N["Nginx / Caddy / LB"] N --> B["Fastify :10010"] B --> A["/api/*"] B --> F["Vue 静态资源"] B --> D[(数据库)] B --> O[对象存储]

生产准备脚本#

仓库提供生产准备脚本,用于检查环境、生成 Prisma Client、执行迁移并构建产物:

Terminal window
chmod +x scripts/prepare-production.sh
./scripts/prepare-production.sh
npm run prod:start:env

生产环境应把 .env 作为受控配置文件,不提交到版本库。

SQLite 部署#

SQLite 适合:

  • 个人使用。
  • 小团队单实例。
  • 较低并发。
  • 希望部署和备份简单的环境。

生产使用 SQLite 时需要:

  • 把数据库放在持久化目录。
  • 使用生产迁移命令,而不是 migrate dev
  • 定期备份数据库文件。
  • 避免多个后端实例同时写同一个文件。
  • 在备份和升级前确认服务状态。

SQLite 并不是对象文件本身的存储位置,因此数据库备份只包含配置、权限、索引、标签、会话和审计信息。

PostgreSQL 迁移#

项目维护独立的 PostgreSQL Prisma schema,并提供完整迁移流程:

prepare -> preflight -> copy -> verify -> cutover

对应命令包括:

Terminal window
npm run db:postgresql:prepare
npm run db:postgresql:preflight
npm run db:postgresql:copy
npm run db:postgresql:verify
npm run db:postgresql:cutover

如果切换后发现问题,还提供 SQLite 回滚脚本:

Terminal window
npm run db:sqlite:rollback

迁移前需要确保:

  • SQLite 和 PostgreSQL schema 保持同步。
  • 目标数据库为空或符合脚本预期。
  • JSON、BigInt、时间和枚举字段转换正确。
  • 用户、权限、文件、标签和对账记录数量一致。
  • 新后端只连接一个最终数据库。

prisma:schema:check 用于避免两套 schema 随代码演进而产生漂移。

配置密钥管理#

至少有两类密钥不能使用默认值:

AUTH_JWT_SECRET=<随机长字符串>
CONFIG_ENCRYPTION_KEY=<另一条随机长字符串>

它们的用途不同:

  • AUTH_JWT_SECRET:内置登录 token 签名。
  • CONFIG_ENCRYPTION_KEY:云存储配置加密。

不应复用同一个值。

可以使用密码管理器、部署平台 Secret 或系统级环境文件管理。配置加密密钥一旦用于写入数据库,轮换前必须先设计重新加密流程。

反向代理#

生产环境建议使用 Nginx、Caddy 或云负载均衡提供 HTTPS,再代理到 Fastify。

需要正确传递:

  • Host
  • X-Real-IP
  • X-Forwarded-For
  • X-Forwarded-Proto

SSO 回调、退出地址、CORS Origin 和站点公开地址都应使用最终 HTTPS 域名,而不是内部端口。

OpenAPI#

项目把公开接口目录和 OpenAPI 文档纳入代码管理。

常用命令:

Terminal window
npm run openapi:generate
npm run openapi:check

OpenAPI 3.1 文件不仅描述路径、请求和响应,还记录接口所需权限。前端内置 API 文档页面直接使用这份接口目录。

这样可以避免三套信息分裂:

  • 后端真实路由。
  • 仓库文档。
  • 前端 API 指南。

OSS Hub 内置 API 文档(待补图)

测试体系#

项目测试分为几层。

后端单元测试#

覆盖:

  • 权限继承。
  • ObjectKey 处理。
  • 输入校验。
  • 存储协议映射。
  • 上传和同步中的纯逻辑。

一致性测试#

检查:

  • SQLite 与 PostgreSQL schema 是否同步。
  • OpenAPI 与接口目录是否一致。
  • 关键配置和生成文件是否漂移。

性能边界测试#

验证分页、批量处理、同步步长和大数据量下的关键逻辑不会出现明显退化。

API 测试#

使用构建后的 Fastify 应用验证认证、权限、文件和管理接口。还可以通过环境变量选择真实对象存储执行 live 测试。

前端与 E2E#

  • Node 测试设备识别等纯逻辑。
  • Playwright 覆盖桌面页面。
  • 独立 Playwright 用例覆盖移动端页面。

提交前主检查命令是:

Terminal window
npm run test:ci

它串联 schema、OpenAPI、类型检查、后端测试、前端单元测试和生产构建。

安全边界#

OSS Hub 的关键安全规则包括:

  • 所有业务接口都需要认证。
  • 所有写操作都需要服务端权限检查。
  • 永久 AK/SK 不进入前端。
  • 预签名 URL 必须短期有效,并限定对象 Key 和操作。
  • 云存储凭据加密入库。
  • 文件名和路径由后端标准化。
  • 文本预览限制大小。
  • SVG 不以内联 HTML 方式渲染。
  • 删除和配置修改写入审计日志。
  • 上游错误不返回密钥、内部路径和完整堆栈。
  • 生产环境必须使用 HTTPS 和强随机密钥。

运维检查清单#

上线前可以按下面顺序检查:

  1. SSO 或内置登录能正常完成。
  2. 普通用户只看到被授权的云存储。
  3. AccessKey 不出现在接口响应和浏览器存储中。
  4. Bucket CORS 允许小文件和分片上传,并暴露 ETag。
  5. 文件浏览、搜索、预览、下载和删除正常。
  6. 上传完成后数据库索引正确创建。
  7. 同步任务能发现缺失和变化对象。
  8. SQLite 或 PostgreSQL 备份策略已配置。
  9. npm run test:ci 通过。
  10. HTTPS、反向代理和 SSO 回调地址使用最终域名。

当前边界#

OSS Hub 已经形成完整闭环,但仍有明确边界:

  • 大规模多实例部署更适合 PostgreSQL,而不是共享 SQLite。
  • 预签名 URL 仍然依赖 Bucket CORS 正确配置。
  • 不同 S3 兼容服务对生命周期、ACL 和标签的支持程度不同。
  • 图片处理和防盗链是阿里云 OSS 扩展能力。
  • 数据库索引不能保证实时反映所有外部对象变更,需要同步或访问时检查。
  • 浏览器保存分片恢复状态,不等于服务端可以在任意设备自动续传。

后续演进#

可以继续扩展的方向包括:

  • 后台定时同步和任务队列。
  • 更完整的跨设备分片续传。
  • 对象版本管理和回收站恢复。
  • CDN 刷新与缓存状态。
  • 更细粒度的目录级权限。
  • 审计日志查询和告警。
  • 指标监控和对象存储调用成本统计。
  • 更多 S3 兼容服务的能力探测。
  • 配置密钥轮换和外部 Secret Manager。

系列总结#

OSS Hub 最终解决的不是“如何上传一个文件”,而是对象存储进入团队日常使用后的一整套问题:

  • 身份从哪里来。
  • 谁可以访问哪个 Bucket。
  • 文件如何避免经过业务服务器。
  • 大文件失败后如何恢复。
  • 对象如何被搜索和分类。
  • 数据库与远端不一致时如何发现和修复。
  • 多云差异如何被隔离,而不是散落在业务代码中。
  • 项目如何被构建、测试、迁移和部署。

当这些问题形成闭环,对象存储才从一个 SDK 和 Bucket,变成一个真正可以交付给用户的资源管理平台。

OSS Hub 部署与工程化:从本地运行到生产迁移
https://march7th.online/blog/posts/0042-oss-hub-部署与工程化从本地运行到生产迁移/
作者
Yiguo
发布于
2026-07-28
许可协议
CC BY-NC-SA 4.0
最后更新于 2026-07-28,距今已过 2 天

部分内容可能已过时

所属合集

OSS Hub 对象存储管理平台

记录 OSS Hub 从项目定位、多云对象存储适配、浏览器直传、索引对账,到 Vue 管理后台、部署和工程化收尾的完整实现。

查看完整合集

目录