news 2026/9/16 15:36:30

在 DigitalOcean App Platform 上部署 Manifest:Web 服务 + Dev PostgreSQL + Space 对象存储的完整实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
在 DigitalOcean App Platform 上部署 Manifest:Web 服务 + Dev PostgreSQL + Space 对象存储的完整实战指南

在 DigitalOcean App Platform 上部署 Manifest:Web 服务 + Dev PostgreSQL + Space 对象存储的完整实战指南

【免费下载链接】llm-gatewayConnect Your Agents And Harnesses With Any Provider 🦚项目地址: https://gitcode.com/GitHub_Trending/manifest7/llm-gateway

本指南基于仓库 deploy/digitalocean/TUTORIAL.md 展开,讲解如何通过 DigitalOcean 官方的 Deploy to DigitalOcean 流程,把 Manifest(开源 AI 模型网关)部署为 App Platform 上的 Web 服务,并搭配 Dev PostgreSQL 数据库与用户自备的 DigitalOcean Space 对象存储,用于持久化请求记录(request recordings)。读完本文,你将掌握 App Platform 部署模板的完整参数填写方法、密钥生成规范、S3 兼容存储的配置要点,以及部署后的健康检查与生产化建议;文中同时结合 app.config.ts、request-recording-storage.service.ts 等源码,说明每个环境变量的底层作用。

一、部署方案总览

Manifest 是一个 OpenAI 兼容的 AI 模型路由网关,可连接各类 LLM 提供商与 Agent。在 DigitalOcean 上,官方推荐的部署形态是一套三件套组合:

组件类型用途
App Platform Web Service应用服务承载 Manifest 后端与内置前端页面
Dev PostgreSQL托管数据库应用主数据库(开发档)
DigitalOcean Space用户自备对象存储持久化请求记录(request recordings)

整个部署通过 DigitalOcean 的Deploy to DigitalOcean流程完成:该按钮会读取公开仓库中的.do/deploy.template.yaml部署模板,据此在 App Platform 上创建应用。需要注意的是,App Platform 没有持久化卷(no persistent volumes),其本地文件系统是临时性的(ephemeral),因此任何需要跨重启、跨实例保留的数据——尤其是请求记录——都必须放在外部持久化存储中,这就是引入 Space 的原因。同时,部署模板无法自动创建带限定权限(scoped)的 Space 凭证,所以 Space 与受限访问密钥必须在部署前由你在 DigitalOcean 控制台手动创建

该方案会创建付费资源(App Platform 服务、Dev PostgreSQL、Space),部署前请确认账号已开通计费(billing)且目标区域可用 App Platform。

二、前置条件:账号与 Space 准备

开始部署前,你需要满足以下前置条件:

  • 一个已开通计费(billing enabled)的 DigitalOcean 账号;
  • 所选区域(region)内可访问 App Platform;
  • 一个私有(private)Space,以及该 Space 专属的受限 Read/Write/Delete 访问密钥

准备 Space 时,请在 DigitalOcean 控制台完成如下动作并记录四个信息:

  1. Space 名称(对应REQUEST_RECORDING_S3_BUCKET);
  2. 区域端点(region endpoint),格式形如https://nyc3.digitaloceanspaces.com
  3. 访问密钥 ID(access key);
  4. 密钥(secret key)。

建议为 Space 创建受限(limited)访问密钥,只授予该 Space 的读、写、删除权限,而不是使用具有全局权限的密钥——这与仓库中其他平台模板的安全做法一致(例如 app.json 中要求 access key 仅限读写删除录制 bucket 内的对象)。

三、发起部署:Deploy to DigitalOcean 流程

准备好上述信息后,在浏览器打开 DigitalOcean 的部署入口:

https://cloud.digitalocean.com/apps/new?repo=https://github.com/mnfst/manifest/tree/main

DigitalOcean 会读取仓库的部署模板,并在正式部署前提示你填写缺失的 secret 值。此时需要你为下列敏感变量生成并填入独立的值。

四、密钥生成与核心环境变量详解

4.1 生成两份相互独立的随机密钥

文档明确要求为BETTER_AUTH_SECRETMANIFEST_ENCRYPTION_KEY各生成一个独立的随机值,使用命令:

openssl rand -hex 32

每次执行都会输出一个 64 位十六进制字符串(32 字节)。请分别运行两次,得到两个不同的值,一个用于BETTER_AUTH_SECRET,另一个用于MANIFEST_ENCRYPTION_KEY,切勿复用同一个值。

为什么必须两个都填且互不相同?packages/backend/.env.example 给出了清晰的源码级解释:

  • BETTER_AUTH_SECRET是会话(session cookie)签名密钥,最小 32 字符
  • MANIFEST_ENCRYPTION_KEY静态加密(at-rest encryption)密钥,用于加密存储的 LLM 提供商 API Key、OAuth Token 以及请求记录本身。AES-256-GCM 密钥由该 secret 通过 scrypt 派生;
  • MANIFEST_ENCRYPTION_KEY未设置,Manifest 会回退使用BETTER_AUTH_SECRET作为加密密钥。这样虽然省事,但一旦会话 cookie 泄露,攻击者就能解密所有已存储的提供商凭证——两个泄露面完全重叠。设置两个独立值,能让两条泄露路径互不关联。

另外请注意:静态加密密钥一旦变更,旧的已存储请求记录将无法读取,会被保留期策略清理,因此生产环境应长期妥善保管这两个 secret。

4.2 请求记录的 S3 相关变量

部署时需填写的 Space 相关变量如下:

环境变量填写内容说明
REQUEST_RECORDING_S3_BUCKET你的 Space 名称存放请求记录的 bucket
REQUEST_RECORDING_S3_ENDPOINThttps://<space-region>.digitaloceanspaces.comSpace 的区域端点,用于定位实际 Space 所在区域
REQUEST_RECORDING_S3_ACCESS_KEY_ID受限 Space 访问密钥 ID仅需该 Space 的读写删权限
REQUEST_RECORDING_S3_SECRET_ACCESS_KEY对应 secret与上面的 access key 配对
REQUEST_RECORDING_S3_REGION保持us-east-1按文档要求保持默认值
REQUEST_RECORDING_S3_FORCE_PATH_STYLE保持false使用虚拟主机风格(virtual-hosted style)URL

其中后两个变量的说明值得展开:REQUEST_RECORDING_S3_REGION=us-east-1需要原样保留,因为 DigitalOcean 的 AWS SDK 指引(guidance)是通过endpoint来实际选择 Space 所在区域的,region 仅用于请求签名;REQUEST_RECORDING_S3_FORCE_PATH_STYLE=false则让 SDK 采用虚拟主机风格寻址而非路径风格,这是 DigitalOcean Spaces 兼容 AWS S3 的默认行为。

这些变量在源码中的定义见 packages/backend/src/config/app.config.ts,它们被逐一读取并注册为 NestJS 配置项:

requestRecordingS3Bucket: process.env['REQUEST_RECORDING_S3_BUCKET'] ?? '', requestRecordingS3Endpoint: process.env['REQUEST_RECORDING_S3_ENDPOINT'] ?? '', requestRecordingS3Region: process.env['REQUEST_RECORDING_S3_REGION'] ?? '', requestRecordingS3AccessKeyId: process.env['REQUEST_RECORDING_S3_ACCESS_KEY_ID'] ?? '', requestRecordingS3SecretAccessKey: process.env['REQUEST_RECORDING_S3_SECRET_ACCESS_KEY'] ?? '', requestRecordingS3ForcePathStyle: process.env['REQUEST_RECORDING_S3_FORCE_PATH_STYLE'] === 'true',

4.3 底层实现:S3RecordingStorage 如何工作

request-recording-storage.service.ts 中的S3RecordingStorage类展示了这些配置的真实用途:它基于@aws-sdk/client-s3构造S3Client,将regionendpointforcePathStyle与可选的凭证对直接传入:

new S3Client({ region: config.region, endpoint: config.endpoint, forcePathStyle: config.forcePathStyle, credentials: config.accessKeyId && config.secretAccessKey ? { accessKeyId: config.accessKeyId, secretAccessKey: config.secretAccessKey } : undefined, });

写入对象时,PutObjectCommandContentType显式设为application/octet-stream——这是因为请求记录正文是客户端侧密文(见 request-recording-codec.ts 的压缩加密逻辑),若声明为 gzip 内容编码,某些 S3 兼容存储或 CDN 会在 GET 时尝试透明解压,导致数据损坏。

对象在 Space 中的键名遵循如下层级结构(来自 objectKey 方法):

request-recordings/v1/tenants/{tenantId}/requests/{requestId}/attempts/{attemptId}.json.gz

这也印证了文档中"请求记录是 Space 中的私有对象"的说法——每条请求、每次重试尝试(attempt)都有独立的对象,便于审计与追溯。

五、PostgreSQL 连接:uselibpqcompat 与 sslmode=require

部署模板会自动把uselibpqcompat=true追加到 DigitalOcean 的 PostgreSQL URL 上。这样做的原因是:DigitalOcean 生成的连接串默认带sslmode=require,而 Node 生态的pg驱动在解析这种连接串时需要兼容性开关才能正确处理;uselibpqcompat=truepg采用 libpq 兼容的解析方式,从而在 TLS 连接下正常工作。

这一处理并非 DigitalOcean 独有——仓库中 deploy/aws/manifest.yaml 的 AWS 部署同样在连接串中拼接了?uselibpqcompat=true&sslmode=require,可见这是 Manifest 在托管 PostgreSQL 平台上统一使用的连接串约定。如果你在其他平台(如 Koyeb)上部署,deploy/koyeb/TUTORIAL.md 也给出了类似要求:连接串需带sslmode=require(无查询参数时用?,已有参数时用&追加)。

由于 App Platform 通过环境变量注入数据库连接串,你不需要(也不应该)手动修改DATABASE_URL,模板会自动完成上述追加处理。

六、验证部署与创建首个管理员

App Platform 完成部署后:

  1. 打开应用 URL(形如https://<your-app>.ondigitalocean.app),创建第一个账号。第一个注册的账号将成为管理员(admin),因此请在公开分享应用地址前完成这一步;
  2. 验证后端健康状态,打开:
https://<your-app-url>/api/v1/health

该健康检查端点在源码中位于 health.controller.ts,路由为GET /api/v1/health,正常返回:

{ "status": "healthy", "uptime_seconds": 42 }

值得注意的细节是:当进程进入优雅关停(draining)状态时,该端点会返回503并携带{ "status": "shutting_down", ... },让平台边缘停止向该副本路由新流量——这也是 App Platform 滚动部署期间判断实例是否健康的重要依据。

七、注意事项与生产化建议

7.1 Dev Database 仅适合起步

DigitalOcean 的部署按钮目前只支持公开仓库与 Dev Database。Dev 档数据库适合试用与开发环境;生产数据请从 App Platform 设置中将 Dev Database 升级为托管数据库(managed database),以获得更优的性能、备份与高可用能力。

7.2 切勿移除 S3 变量

如第一节所述,App Platform 的本地文件系统是临时性的,应用重启或实例重建都会清空。因此除非你明确禁用记录持久化,否则不要移除上述REQUEST_RECORDING_S3_*变量。Manifest 的存储选择默认是auto能力检测模式(见 app.config.ts):完整且配对的 S3 凭证优先;无 S3 凭证时自托管部署才会回退到挂载的文件系统。在 App Platform 上,唯一合理的回退就是 Space,移除这些变量等价于放弃记录持久化。

7.3 删除应用不会删除 Space

删除 App Platform 应用不会级联删除 Space。如果你不再使用,请先导出需要的请求记录,再单独清理 Space,避免数据永久丢失。

7.4 其他值得关注的生产配置

结合仓库中其他平台部署文档与 .env.example,生产环境还建议关注:

  • MANIFEST_MODE=selfhostedBIND_ADDRESS=0.0.0.0:让后端监听所有网卡接口,供平台边缘路由流量(参考 app.json 与 Koyeb 模板的做法);
  • NODE_ENV=production:以生产模式运行后端;
  • DB_POOL_MAX:按数据库连接上限控制连接池大小,避免连接数打满(App Platform 的托管数据库同样有连接数限制,参见 deploy/heroku/TUTORIAL.md 中按档位调小池的同类处理)。

结语

在 DigitalOcean App Platform 上部署 Manifest 的核心思路可以概括为三句话:用 App Platform 跑无状态应用、用 Dev/托管 PostgreSQL 存业务数据、用私有 Space 持久化请求记录。只要在部署前把私有 Space 与受限密钥准备好,按模板要求填写两组独立的随机密钥和六个 S3 变量,保持REQUEST_RECORDING_S3_REGION=us-east-1REQUEST_RECORDING_S3_FORCE_PATH_STYLE=false不变,即可顺利完成部署,并通过/api/v1/health快速验证。仓库中 deploy/ 目录还提供了 AWS、Fly、GCP、Coolify、EasyPanel、Koyeb、Heroku 等平台的同类指南,可作为多平台部署的对照参考。

【免费下载链接】llm-gatewayConnect Your Agents And Harnesses With Any Provider 🦚项目地址: https://gitcode.com/GitHub_Trending/manifest7/llm-gateway

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 15:36:18

SkyPilot 快速上手:用 PyTorch DDP 在云端启动 minGPT 分布式训练

SkyPilot 快速上手&#xff1a;用 PyTorch DDP 在云端启动 minGPT 分布式训练 【免费下载链接】skypilot The AI Compute Platform for frontier teams. SkyPilot turns fragmented AI compute into one AI supercomputer, so frontier AI teams build custom intelligence fas…

作者头像 李华
网站建设 2026/9/16 15:35:18

tmux终端复用器实战:从防断线到高效工作流

用过终端的人&#xff0c;应该都有过这种经历&#xff1a;远程连了台服务器&#xff0c;部署跑了一半&#xff0c;网络一抖&#xff0c;SSH一断&#xff0c;整个任务跟着终端一起没了。那个瞬间&#xff0c;悔恨、无奈、想砸电脑的情绪交织在一起&#xff0c;最后只能老老实实重…

作者头像 李华
网站建设 2026/9/16 15:33:01

Python命令行参数类型管理实战指南

1. 为什么需要参数类型管理在Python命令行工具开发中&#xff0c;参数解析是每个开发者都要面对的基础问题。记得我第一次写命令行工具时&#xff0c;处理用户输入的各种参数格式简直让人抓狂 - 数字被当成字符串、文件路径需要手动验证、布尔值判断写了一大堆if...else。直到深…

作者头像 李华
网站建设 2026/9/16 15:32:16

InternVL MMMU评测教程:多模态多任务理解的权威基准

InternVL MMMU评测教程&#xff1a;多模态多任务理解的权威基准 【免费下载链接】InternVL [CVPR 2024 Oral] InternVL Family: A Pioneering Open-Source Alternative to GPT-4o. 接近GPT-4o表现的开源多模态对话模型 项目地址: https://gitcode.com/GitHub_Trending/in/Int…

作者头像 李华
网站建设 2026/9/16 15:31:20

校园视频监控SSM毕设源码解析:从环境部署到二次开发实战

简介&#xff1a;面向Java毕业设计/课程设计学生的校园视频监控系统完整项目&#xff0c;基于SSM&#xff08;Spring、SpringMVC、MyBatis&#xff09;与MySQL实现&#xff0c;覆盖个人中心、用户权限、视频管理员、摄像头管理、实时监控、留言板与系统管理等核心业务模块&…

作者头像 李华