Manifest LLM Gateway 自托管 Heroku 部署实战指南:Cedar 容器栈 + Postgres Essential-0 一键拉起
【免费下载链接】llm-gatewayConnect Your Agents And Harnesses With Any Provider 🦚项目地址: https://gitcode.com/GitHub_Trending/manifest7/llm-gateway
本篇技术指南基于 llm-gateway 仓库的 deploy/heroku/TUTORIAL.md 展开,系统讲解如何将开源的 Manifest LLM 网关(AI 模型路由器)部署到 Heroku Cedar 容器栈,配套一个 web dyno 与 Heroku Postgres Essential-0 数据库。读完本文,你将掌握 Heroku 一键部署流程、S3 兼容对象存储的请求录制配置、自托管运行时的关键环境变量(会话签名、凭据加密、连接池与 TLS),以及部署后的初始化、健康检查、日志排查与销毁计费资源的方法。
部署前置条件
Manifest 是一个面向 AI Agent 与应用的 LLM 网关,把 API Key、订阅与本地模型统一收敛到一个 OpenAI 兼容端点。自托管部署到 Heroku 前,需要确认以下条件:
- Heroku 账号且已启用计费:Cedar 容器栈的部署会产生付费资源,账号需要绑定账单方式。
- 应用、插件(Add-on)与配置变量的创建权限:部署流程会创建 Heroku app、Postgres Add-on,并写入大量 Config Vars。
- 一个私有的 S3 兼容存储桶及受限凭据:Heroku dyno 的文件系统是临时(ephemeral)的,请求录制数据必须落到外部对象存储;用于该存储桶的访问密钥权限应限定为只对该桶对象进行读写删操作。
需要特别留意:Heroku 已不再提供免费 dyno 或免费的 Heroku Postgres 套餐,本部署栈全部由付费资源构成。若仅用于测试,建议在验证完成后及时销毁应用(见下文"拆除资源"小节)以停止计费。
一键部署流程
打开 Heroku Deploy Button
Manifest 仓库根目录的 app.json 声明了标准的 Heroku Button 元数据(stack: container、formation、addons与env),因此可以直接使用官方部署链接拉起应用:
https://www.heroku.com/deploy?template=https://github.com/mnfst/manifest打开链接后选择应用名称,Heroku 将依据 app.json 依次完成:创建container栈应用 → 供应一个basic规格的 web dyno → 附加heroku-postgresql:essential-0数据库(以DATABASE为标识)→ 写入运行时配置 → 构建镜像并启动。
传入应用公网 URL
由于 dyno 文件系统随时可能被回收,请求录制必须使用外部对象存储。部署前请先创建好私有 S3 兼容存储桶与受限访问密钥。当 Heroku 在 Deploy 向导中询问配置时,首先填写应用的公网 URL:
https://<your-app-name>.herokuapp.com该值对应 app.json 中的BETTER_AUTH_URL,它决定了 Better Auth 会话 Cookie 的签发源与回跳地址。从源码看,auth.instance.ts 会把该值作为认证源(authOrigin)并与CORS_ORIGIN一起写入受信任来源(trusted origins)列表,用于 OAuth 与会话校验。若填写错误,登录/授权回调可能因来源不匹配而失败。
录制存储桶配置项
随后填写请求录制的 S3 配置,对应 app.json 中的REQUEST_RECORDING_*系列变量与 TUTORIAL.md 中的说明:
| 配置变量 | 含义 | 示例 / 说明 |
|---|---|---|
REQUEST_RECORDING_S3_BUCKET | 私有存储桶名称 | 必填,如manifest-recordings-prod |
REQUEST_RECORDING_S3_ENDPOINT | 自定义 S3 兼容端点 | 使用 AWS S3 时留空;使用 DigitalOcean Spaces 等需填写 |
REQUEST_RECORDING_S3_REGION | 签名区域 | 如us-east-1,同时适用于 DigitalOcean Spaces |
REQUEST_RECORDING_S3_ACCESS_KEY_ID | 受限访问密钥 | 仅需该桶对象的读写删权限 |
REQUEST_RECORDING_S3_SECRET_ACCESS_KEY | 与访问密钥配对的密钥 | 必填 |
REQUEST_RECORDING_S3_FORCE_PATH_STYLE | 是否使用 path-style 桶 URL | 默认false,仅当 S3 兼容服务要求时改为true |
这些变量在 app.config.ts 中被解析为requestRecordingS3Bucket、requestRecordingS3Endpoint、requestRecordingS3Region、requestRecordingS3AccessKeyId、requestRecordingS3SecretAccessKey与requestRecordingS3ForcePathStyle。底层存储抽象见 request-recording-storage.service.ts:resolveRecordingStorage会根据REQUEST_RECORDING_STORAGE(默认auto)做能力探测——S3 凭据完整时优先使用s3后端,否则回退到本地文件系统;若凭据只填了一半(例如只有 key 没有 secret),则判定为不完整配置而不启用 S3。也就是说,在 Heroku 上正确填写完整的 S3 配置,才能确保请求录制落到持久化对象存储,而不是被写入会被回收的临时文件系统。
运行时配置:Heroku 自动供应了什么
Heroku 会生成会话与加密密钥、将 Postgres 以DATABASE_URL注入、基于 Dockerfile.heroku 构建镜像(该文件仅一行:FROM docker.io/manifestdotbuild/manifest:6,即直接使用官方 Manifest 6.x 镜像),并启动 web dyno。heroku.yml 声明了构建方式:
build: docker: web: Dockerfile.heroku完整的运行时环境由 app.json 的env段定义,除了上文 S3 配置外,还包括:
| 配置变量 | 默认值 / 生成方式 | 说明 |
|---|---|---|
BETTER_AUTH_URL | 必填(手动输入) | 应用公网 URL,认证与会话来源 |
BETTER_AUTH_SECRET | generator: secret | 会话签名密钥,Heroku 自动生成安全随机值;auth.instance.ts 要求其长度至少 32 字符,否则启动即报错 |
MANIFEST_ENCRYPTION_KEY | generator: secret | 供应商凭据的静态加密密钥(at-rest encryption),与 Better Auth 会话密钥分离 |
REQUEST_RECORDING_STORAGE | s3 | 强制使用 S3 后端存储压缩后的请求录制 |
BIND_ADDRESS | 0.0.0.0 | 绑定所有网卡,让 Heroku 路由平台流量到 dyno |
MANIFEST_MODE | selfhosted | 以自托管模式运行 |
NODE_ENV | production | 生产环境设置 |
PGSSLMODE | no-verify | 对 Heroku Postgres 启用 TLS |
DB_POOL_MAX | 8 | 主数据库连接池上限 |
AUTH_DB_POOL_MAX | 4 | Better Auth 独立连接池上限 |
两个密钥变量在 app.json 中使用generator: "secret",部署时由 Heroku 平台自动生成并注入,无需手工填写。MANIFEST_ENCRYPTION_KEY对应仓库中的凭据加密链路——crypto.util.ts 与数据库迁移 1771900000000-EncryptApiKeys.ts 体现了对供应商 API Key 的静态加密,因此该密钥必须妥善保存;若丢失,已加密的凭据将无法解密。
打开 Manifest 并完成初始化
部署完成后访问应用地址。全新安装会被重定向到/setup(见 app.json 的success_url),在此创建第一个管理员账号——第一个创建成功的账号即成为管理员。
检查健康状态:
curl -fsS https://<your-app-name>.herokuapp.com/api/v1/health返回正常即说明后端、数据库与配置均就绪。查看运行日志:
heroku logs --tail -a <your-app-name>/api/v1/health端点的实现可参考 health.controller.ts,日志排查则关注启动阶段是否出现DATABASE_URL缺失、BETTER_AUTH_SECRET长度不足等报错。
连接池与 TLS:为什么是这些默认值
app.json 为连接池和 TLS 选择了保守配置,这是针对 Essential-0 套餐连接数上限的刻意设计:
PORT不固定:Heroku 会自动设置PORT环境变量,模板不写死端口;app.config.ts 默认读取PORT(回退3001)。PGSSLMODE=no-verify:对 Heroku 托管的DATABASE_URL启用 TLS 连接,同时无需改写平台托管的连接字符串。DB_POOL_MAX=8+AUTH_DB_POOL_MAX=4:主数据库(TypeORM)与 Better Auth 是两条独立连接池,合计上限 12,为 Essential-0 套餐的连接数留出余量。仓库中 auth.instance.ts 的注释明确说明:Better Auth 独立的池必须与 TypeORM 池分开计数,否则两者会共同耗尽 Postgres 的max_connections。若日后升级到更大的 Postgres 套餐,再相应调大这两个值。
拆除资源
测试完成后销毁应用以停止计费:
heroku apps:destroy -a <your-app-name>外部录制存储桶不属于 Heroku 应用的一部分:若需要保留数据可继续持有用于恢复;不再需要时请单独导出并删除桶内容,避免产生持续的存储费用。
关键注意事项
- 不要把请求录制写到 dyno 文件系统:Heroku 在 dyno 停止或重启时会丢弃整个文件系统,任何落盘数据都会丢失;这也是教程强制要求 S3 兼容外部存储的原因。
- S3 凭据务必完整:从 request-recording-storage.service.ts 的判定逻辑可知,只有 bucket、region 齐全且凭据成对出现(或都为空时依赖文件系统回退)才会启用 S3 后端;缺少任一项会导致回退或禁用录制存储。
- 妥善保管两个自动生成的密钥:
BETTER_AUTH_SECRET与会话签名、MANIFEST_ENCRYPTION_KEY与凭据静态加密直接相关,丢失MANIFEST_ENCRYPTION_KEY将无法解密已存储的供应商凭据。 - 单实例适用:与仓库中其他卷挂载型部署模板一致,Heroku 模板面向单 web dyno;需要水平扩展前,应确保录制已接入 S3 兼容存储(本模板已满足)。
延伸阅读
- 仓库根目录 README.md 中"Deploy with one click"表格对多个平台的部署形态做了横向对比,其中明确说明 Heroku 属于"部署时收集外部 S3 兼容设置"的路径。
- 自托管通用指南:docker/DOCKER_README.md,Docker 一键安装脚本见 docker/install.sh。
- 其他平台参考:deploy/aws/TUTORIAL.md、deploy/gcp/TUTORIAL.md、deploy/fly/TUTORIAL.md、deploy/coolify/TUTORIAL.md、deploy/easypanel/TUTORIAL.md、deploy/digitalocean/TUTORIAL.md、deploy/koyeb/TUTORIAL.md。
【免费下载链接】llm-gatewayConnect Your Agents And Harnesses With Any Provider 🦚项目地址: https://gitcode.com/GitHub_Trending/manifest7/llm-gateway
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考