news 2026/9/11 2:49:00

OmniRoute Fly.io 部署实战指南:首次发布、密钥配置与数据持久化运维

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OmniRoute Fly.io 部署实战指南:首次发布、密钥配置与数据持久化运维

OmniRoute Fly.io 部署实战指南:首次发布、密钥配置与数据持久化运维

【免费下载链接】OmniRouteNever stop coding. Free MIT AI gateway: one endpoint, 352 providers (150+ free), 1200+ models Kimi, Claude, GPT, Gemini, GLM, DeepSeek, MiniMax. Works with Claude Code, Codex, Cursor, OpenCode, Cline & Copilot. Quota-aware auto-fallback, RTK+Caveman compression saves 15-95% tokens, MCP/A2A, Desktop/PWA. Built by 550+ contributors项目地址: https://gitcode.com/GitHub_Trending/om/OmniRoute

导读

本文基于 OmniRoute 仓库中已实际验证通过的 Fly.io 部署指南(及其 孟加拉语译本),完整讲解如何将 OmniRoute 这个统一 AI 网关部署到 Fly.io:从flyctl环境准备、首次发布,到 Secrets 密钥体系、OAuth 回调配置、fork 同步发布与持久化验证。读完本文,你将掌握一套可直接复用的 Fly.io 云部署与滚动升级方案,并理解每个关键配置背后的源码实现原理。

1. 部署目标

  • 平台:Fly.io(云主机托管,自带边缘网络与卷存储)
  • 部署方式:本地flyctl直接发布,无需额外 CI/CD 编排
  • 运行方式:直接使用仓库内已有的 Dockerfile 与 fly.toml
  • 数据持久化:Fly Volume 挂载到容器内/data目录
  • 访问地址https://omniroute.fly.dev/
  • 应用名omniroute(本文所有命令均以该应用名为准)

覆盖三类场景:首次把当前项目部署到 Fly.io、后续代码更新继续发布、新项目参考同一流程部署。

2. 仓库现有配置解读:fly.toml 关键项

仓库根目录的fly.toml是本次部署的配置核心,已确认包含以下关键项:

app = 'omniroute' primary_region = 'sin' [[mounts]] source = 'data' destination = '/data' [processes] app = 'node run-standalone.mjs' [http_service] internal_port = 20128 [env] TZ = "Asia/Shanghai" HOST = "0.0.0.0" HOSTNAME = "0.0.0.0" BIND = "0.0.0.0"

要点说明:

  • app = 'omniroute'决定部署目标 Fly 应用,控制台看到的应用必须与之一致;
  • destination = '/data'决定持久卷挂载目录,本项目必须让DATA_DIR=/data,否则数据库和密钥会写到容器临时目录,重启即丢失;
  • [processes]中的node run-standalone.mjs是容器入口进程。

对比仓库中真实 fly.toml,还有几个文档之外的细节值得注意(均来自已验证配置):

  • 卷自动扩容[[mounts]]段额外声明了auto_extend_size_threshold = 80auto_extend_size_increment = '1GB'auto_extend_size_limit = '10GB',即卷使用率达 80% 时自动按 1GB 步长扩容、上限 10GB;
  • HTTP 服务强化force_https = true强制 HTTPS;auto_stop_machines = 'stop'auto_start_machines = true支持空闲停机、按需唤醒;min_machines_running = 1保证至少一台常驻;
  • 资源规格[[vm]]段为 1 核 shared CPU、1024MB 内存;
  • 部署钩子[deploy]中的release_command被注释掉,本部署不需要迁移命令。

在 Dockerfile 中可以看到与上述配置的对应关系:基础镜像为node:26-trixie-slimENV PORT=20128internal_port一致,ENTRYPOINT先执行 check-permissions.sh(校验数据卷属主),随后CMD ["node", "dev/run-standalone.mjs"]启动服务;镜像内置HEALTHCHECK(每 30s 探测healthcheck.mjs)。注意 Dockerfile 中默认ENV DATA_DIR=/app/data,这正是 Fly 部署时必须用环境变量覆盖为/data的原因。

3. 环境准备:安装 Fly CLI 并登录

3.1 安装 Fly CLI

Windows PowerShell 一键安装:

pwsh -Command "iwr https://fly.io/install.ps1 -useb | iex"

如果安装脚本在当前环境失败,也可以手动下载flyctl二进制并加入PATH

3.2 登录 Fly 账号

flyctl auth login

3.3 检查登录状态

flyctl auth whoami flyctl version

whoami输出当前登录账号,确认与目标组织一致后再继续。

4. 首次部署流程

4.1 获取代码并进入目录

git clone https://gitcode.com/GitHub_Trending/om/OmniRoute.git cd OmniRoute

4.2 确认应用名

打开 fly.toml,重点看这一行:

app = 'omniroute'

如果你要部署到自己的新应用,可改成全局唯一名称,例如:

app = 'omniroute-yourname'

注意两点:

  • 控制台里查看的应用必须与fly.tomlapp一致;
  • 如果以前用过别的名字(例如oroute),不要和omniroute混淆——它们对应不同的 Fly 应用,Secrets 互不通用。

4.3 创建应用

如果该应用尚不存在:

flyctl apps create omniroute

改名后请把omniroute替换成你的应用名。

4.4 首次部署

flyctl deploy

flyctl会依据fly.toml构建镜像并创建首批 Machine;若尚未配置 Secrets,可以先看下一节再部署,避免首次启动回退到弱默认值。

5. 必配参数:Fly Secrets 密钥体系

5.1 已验证使用的参数

以下参数已经在当前omniroute应用上实际部署验证:

  • API_KEY_SECRET
  • DATA_DIR
  • JWT_SECRET
  • MACHINE_ID_SALT
  • NEXT_PUBLIC_BASE_URL
  • OMNIROUTE_WS_BRIDGE_SECRET(生产环境必需,用于 WebSocket bridge 鉴权)
  • STORAGE_ENCRYPTION_KEY

5.2 关于INITIAL_PASSWORD

当前项目没有设置INITIAL_PASSWORD,因为本次部署按需求不使用它。如果不设置:

  • 启动日志会提示默认密码为CHANGEME(源码见 bootstrap-env.mjs 中的告警逻辑);
  • 部署后应尽快在系统设置中修改登录密码。

如果希望无人值守初始化后台密码,可后续补充INITIAL_PASSWORD

5.3 源码视角:这些密钥为什么"必需"

理解这些密钥的底层作用,才能判断取舍。核心逻辑集中在 bootstrap-env.mjs,它由 run-standalone.mjs 在进程启动时调用:

  • 密钥自动生成与持久化:首次启动时,若JWT_SECRETSTORAGE_ENCRYPTION_KEYAPI_KEY_SECRET缺失,bootstrap 会用randomBytes自动生成并写入{DATA_DIR}/server.env,因此只要DATA_DIR落在持久卷上,密钥就能跨重启、跨升级存活;这就是文档中/data/server.env成功标志的由来。
  • 环境变量优先级:自动生成值 <{DATA_DIR}/server.env< 首选.env文件 <process.env(Fly Secrets 注入的环境变量优先级最高),且空字符串值会被过滤,不会覆盖已持久化的真实密钥。
  • STORAGE_ENCRYPTION_KEY的约束:如果数据库中已存在enc:v1:前缀的加密凭据,bootstrap 会拒绝自动生成新密钥并报错,防止换钥匙导致数据不可解密;启动时还会用 scrypt 派生密钥做解密探测,密钥不匹配会给出告警。
  • MACHINE_ID_SALT:在 machineId.ts 中,getConsistentMachineId以操作系统机器标识(Windows MachineGuid / macOS IOPlatformUUID / Linux machine-id 文件等)加盐后做 SHA-256,取前 16 字符作为稳定机器 ID;MACHINE_ID_SALT就是这里的盐,不设置时回退到内置默认值endpoint-proxy-salt
  • OMNIROUTE_WS_BRIDGE_SECRET:在 management.ts 中,进程内 codex Responses-over-WebSocket 代理的内部调用通过请求头x-omniroute-ws-bridge-secret携带该密钥,服务端以 SHA-256 摘要 +timingSafeEqual做常数时间比较;缺失该密钥会直接破坏 WebSocket bridge 握手,因此生产环境必配。
  • NEXT_PUBLIC_BASE_URL:在 runtimeEnv.ts 中经 Zod 校验为合法 HTTP(S) URL,用于调度器、前端回调等场景的绝对地址生成。

6. 推荐参数说明

6.1 Secrets 设置建议

变量名是否推荐说明
API_KEY_SECRET必需API Key 生成与校验使用
JWT_SECRET必需登录态和 JWT 签名使用
OMNIROUTE_WS_BRIDGE_SECRET生产必需WebSocket bridge 鉴权密钥
STORAGE_ENCRYPTION_KEY强烈推荐加密存储敏感连接信息(AES-256-GCM)
MACHINE_ID_SALT推荐生成稳定机器标识
INITIAL_PASSWORD可选首次部署时直接指定后台初始密码
OAuth/API 私密凭证按需各类外部平台鉴权配置

6.2 当前项目推荐值

变量名推荐值
DATA_DIR/data
NEXT_PUBLIC_BASE_URLhttps://omniroute.fly.dev

说明:

  • DATA_DIR=/data非常关键,必须与 fly.toml 中 Fly Volume 挂载点一致,否则数据库与密钥落入容器临时目录(默认/app/data);
  • NEXT_PUBLIC_BASE_URL用于调度器和前端回调等场景,改动应用名时必须同步更新。

6.3 OAuth 回调地址配置(启用 OAuth Provider 时)

如果要在 Fly 部署上启用基于 OAuth 的 Provider(如 Antigravity、Gemini、Cursor 等),需确认两点:

  1. NEXT_PUBLIC_BASE_URL设置为你的公网 HTTPS 域名

    flyctl secrets set NEXT_PUBLIC_BASE_URL=https://omniroute.fly.dev -a omniroute

    使用自定义域名时替换为对应域名(例如https://omniroute.yourdomain.com)。

  2. 在 Provider 控制台配置回调地址

    所有 OAuth Provider共享唯一的回调路径/callback,不存在按 Provider 区分的回调路由

    <NEXT_PUBLIC_BASE_URL>/callback

    例如无论 Gemini、Antigravity、Cursor 还是 GitLab Duo,一律填写:

    • https://omniroute.fly.dev/callback

    如果NEXT_PUBLIC_BASE_URL与在 Provider 侧登记的回调地址不一致,OAuth 流程会在浏览器重定向环节失败。仓库中 OIDC 登录的回调实现可见 oidc/callback/route.ts:它校验codestate(常数时间比较防时序攻击)、从设置中读取 issuer/client 信息、基于x-forwarded-protoHost动态拼出绝对redirect_uri并完成授权码换令牌,因此回调域名必须与NEXT_PUBLIC_BASE_URL严格对应。

7. 一键设置参数

下面命令会生成安全随机值,并把当前项目需要的参数一次性写入 Fly Secrets(不包含INITIAL_PASSWORD,适用于当前项目omniroute):

$apiKeySecret = [Convert]::ToHexString((1..32 | ForEach-Object { Get-Random -Minimum 0 -Maximum 256 })).ToLower() $jwtSecret = [Convert]::ToHexString((1..64 | ForEach-Object { Get-Random -Minimum 0 -Maximum 256 })).ToLower() $machineIdSalt = [Convert]::ToHexString((1..32 | ForEach-Object { Get-Random -Minimum 0 -Maximum 256 })).ToLower() $storageKey = [Convert]::ToHexString((1..32 | ForEach-Object { Get-Random -Minimum 0 -Maximum 256 })).ToLower() $wsBridgeSecret = [Convert]::ToHexString((1..32 | ForEach-Object { Get-Random -Minimum 0 -Maximum 256 })).ToLower() flyctl secrets set ` API_KEY_SECRET=$apiKeySecret ` JWT_SECRET=$jwtSecret ` MACHINE_ID_SALT=$machineIdSalt ` STORAGE_ENCRYPTION_KEY=$storageKey ` OMNIROUTE_WS_BRIDGE_SECRET=$wsBridgeSecret ` DATA_DIR=/data ` NEXT_PUBLIC_BASE_URL=https://omniroute.fly.dev ` -a omniroute

在 Linux / macOS 上,也可以用openssl rand -hex生成(适合 Shell 环境):

flyctl secrets set OMNIROUTE_WS_BRIDGE_SECRET=$(openssl rand -hex 32) -a omniroute

注意:OMNIROUTE_WS_BRIDGE_SECRET生产环境必配,缺失会破坏 WebSocket bridge 握手(见 5.3 节源码分析)。

如果你还要加初始密码:

flyctl secrets set INITIAL_PASSWORD=你的强密码 -a omniroute

每次flyctl secrets set后 Fly 会自动滚动重启受影响 Machine。

8. 查看当前参数

flyctl secrets list -a omniroute

如果控制台Secrets页面没有显示你期待的变量,先检查:

  • 看的应用是不是omniroute
  • fly.tomlapp是否和控制台应用一致。

9. 后续更新发布

代码有更新后,发布步骤很简单:

git pull flyctl deploy

如果只更新参数、不改代码:

flyctl secrets set KEY=value -a omniroute

Fly 会自动滚动更新机器,期间服务基本不中断。

9.1 跟踪原仓库更新并保留 fork 的 fly.toml

如果当前仓库是 fork,且要同步上游更新,推荐按以下流程执行。先确认远程:

git remote -v

应至少包含:origin指向你自己的 fork,upstream指向原仓库。如果没有upstream,先添加(将原仓库地址替换为你实际的上游):

git remote add upstream <原仓库地址>

同步上游前,先抓取最新提交和标签:

git fetch upstream --tags

查看当前版本和上游标签:

git describe --tags --always git show --no-patch --oneline <目标版本标签>

说明:文档中v3.4.7属于历史示例版本;实际发布时应使用当前版本标签(例如:v3.8.0)或:latest,以仓库实际版本为准。

如果你想合并上游最新main,并强制保留 fork 当前的fly.toml,可按下面流程执行:

git merge upstream/main git checkout HEAD~1 -- fly.toml git add -- fly.toml git commit -m "chore(deploy): keep fork fly.toml" git push origin main

说明:

  • git merge upstream/main用于同步原仓库最新代码;
  • git checkout HEAD~1 -- fly.toml用于恢复合并前你 fork 自己的fly.toml
  • 如果上游没有改fly.toml,这一步不会带来额外差异;
  • 如果上游改了fly.toml,这一步能确保 Fly 应用名、挂载卷、区域等 fork 自定义部署配置不被覆盖。

如果你明确只想对齐某个发布标签,也可以先确认标签是否已包含在upstream/main

git merge-base --is-ancestor <目标版本标签> upstream/main

返回成功表示upstream/main已包含该版本,直接合并upstream/main即可。

9.2 同步上游后的标准发布顺序

  1. git fetch upstream --tags
  2. git merge upstream/main
  3. 恢复 fork 的fly.toml
  4. git push origin main
  5. flyctl deploy
  6. flyctl status -a omniroute
  7. flyctl logs --no-tail -a omniroute

这就是当前项目升级时使用的实际发布流程。

10. 发布后检查

10.1 查看应用状态

flyctl status -a omniroute

10.2 查看启动日志

flyctl logs --no-tail -a omniroute

10.3 检查网站可访问

try { (Invoke-WebRequest -Uri "https://omniroute.fly.dev" -MaximumRedirection 5 -UseBasicParsing).StatusCode } catch { if ($_.Exception.Response) { $_.Exception.Response.StatusCode.value__ } else { throw } }

返回200说明站点已正常响应。

11. 成功标志

部署成功后,日志里应看到类似内容:

[bootstrap] Secrets persisted to: /data/server.env [DB] SQLite database ready: /data/storage.sqlite

这两个点很关键:

  • /data/server.env说明运行时密钥落到了持久卷(由 bootstrap-env.mjs 写入,跨重启存活);
  • /data/storage.sqlite说明 SQLite 数据库写入持久卷。

如果你看到的是/app/data/...,说明DATA_DIR没配对(回退到了 Dockerfile 中的默认值),需要立即修正为/data并重新部署。

12. 常见问题

12.1 Secrets 页面是空的

通常有两种原因:

  • 你还没执行flyctl secrets set
  • 你打开的是另一个应用(例如oroute),不是omniroute

12.2 flyctl deploy 报 app not found

先创建应用:

flyctl apps create omniroute

12.3 fly.toml 解析失败

重点检查:

  • 注释里是否有乱码字符;
  • TOML 引号和缩进是否正确。

12.4 数据没有持久化

检查以下两点是否同时满足:

  • fly.toml中存在destination = '/data'
  • DATA_DIR设置为/data

另外可核对日志中数据库路径是否为/data/storage.sqlite(见第 11 节)。

12.5 不设置 INITIAL_PASSWORD 是否能跑

可以运行,但会回退到默认CHANGEME密码。生产环境建议尽快在系统设置中修改后台密码。

13. 新项目复用建议

如果以后是新项目照着这份文档部署,最少改这几项:

  1. 修改fly.toml里的app
  2. 修改NEXT_PUBLIC_BASE_URL
  3. 保持DATA_DIR=/data
  4. 重新生成API_KEY_SECRETJWT_SECRETMACHINE_ID_SALTSTORAGE_ENCRYPTION_KEY(生产环境还需OMNIROUTE_WS_BRIDGE_SECRET);
  5. 首次部署后检查日志是否写入/data

不要直接复用旧项目的密钥——STORAGE_ENCRYPTION_KEY与旧数据库绑定,换环境换库必须换钥匙;其他密钥复用也会放大泄露面。

14. 当前项目的最小发布清单

当前项目后续最常用的命令如下:

flyctl auth whoami flyctl status -a omniroute flyctl secrets list -a omniroute flyctl deploy flyctl logs --no-tail -a omniroute

如果只是正常发版,核心就是:

flyctl deploy

如果是新环境首次部署,核心就是:

  1. flyctl auth login
  2. flyctl apps create omniroute
  3. flyctl secrets set ... -a omniroute(第 7 节一键命令)
  4. flyctl deploy
  5. flyctl logs --no-tail -a omniroute

延伸阅读

  • 部署指南英文原版:docs/ops/FLY_IO_DEPLOYMENT_GUIDE.md
  • 部署入口与密钥引导:run-standalone.mjs / bootstrap-env.mjs
  • 容器镜像与启动命令:Dockerfile / docker-compose.yml
  • 机器标识与 WS bridge 鉴权:machineId.ts / management.ts
  • 运行时环境校验:runtimeEnv.ts
  • 本地/自建部署对比参考:DOCKER_GUIDE.md、SETUP_GUIDE.md

【免费下载链接】OmniRouteNever stop coding. Free MIT AI gateway: one endpoint, 352 providers (150+ free), 1200+ models Kimi, Claude, GPT, Gemini, GLM, DeepSeek, MiniMax. Works with Claude Code, Codex, Cursor, OpenCode, Cline & Copilot. Quota-aware auto-fallback, RTK+Caveman compression saves 15-95% tokens, MCP/A2A, Desktop/PWA. Built by 550+ contributors项目地址: https://gitcode.com/GitHub_Trending/om/OmniRoute

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

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

Goldie 编码 Agent:自动搞定 App Store 截图、预览视频与合规校验

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 2:46:22

算法市场怎么做?AI应用架构师驱动企业AI落地的5个关键步骤

这两年走访了不少正在做数字化改造的传统企业&#xff0c;发现一个高频现象&#xff1a;底座搭得很豪华&#xff0c;湖仓一体、数据中台、AI中台一个不少&#xff0c;可真正到了“算法”这一层&#xff0c;项目就开始失速。业务部门说算法团队不接地气&#xff0c;算法团队说业…

作者头像 李华