
OmniRoute Fly.io 部署实战指南flyctl 发布流程、Secrets 配置与 /data 持久化【免费下载链接】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, RTKCaveman compression saves 15-95% tokens, MCP/A2A, Desktop/PWA. Built by 550 contributors项目地址: https://gitcode.com/GitHub_Trending/om/OmniRouteOmniRoute 是面向多模型路由的 AI 网关单端点聚合 352 家 Provider、1200 模型其仓库内自带了可直接上云的Dockerfile与fly.toml。本文以仓库中已验证的omniroute应用配置为蓝本完整讲解如何用本地flyctl把当前项目发布到 Fly.io从工具安装、首次部署、Secrets 参数体系到 fork 同步上游后的增量发布、发布后检查与故障排查帮助你在半小时内跑通一次部署、长期可升级的生产环境。1. 部署目标与整体方案本文记录的部署方案基于仓库中已验证通过的配置核心目标如下平台Fly.io部署方式本地flyctl直接发布不依赖 CI 流水线运行方式复用仓库内现有的Dockerfile与fly.toml不额外编写基础设施代码数据持久化Fly Volume 挂载到容器内/data数据库与密钥文件均落盘访问地址https://omniroute.fly.dev/文档覆盖三类场景首次把当前项目部署到 Fly.io、后续代码更新后的增量发布、以及新项目复用同一套流程部署。2. 仓库内 fly.toml 关键配置解读仓库根目录下的 fly.toml 是 Fly.io 部署的唯一配置源其中已验证包含以下关键项部署指南中的最小配置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 应用也是所有flyctl命令-a参数的默认目标destination /data决定持久卷的挂载目录本项目必须让DATA_DIR/data否则数据库和密钥会写入容器临时目录重启即丢失[processes] app node run-standalone.mjs定义主进程启动命令对应仓库 scripts/dev/run-standalone.mjs 入口[http_service] internal_port 20128容器内服务监听端口与 Dockerfile 中的EXPOSE 20128、ENV PORT20128保持一致。实际仓库的fly.toml还包含若干生产强化项可一并参考[[mounts]] source data destination /data auto_extend_size_threshold 80 auto_extend_size_increment 1GB auto_extend_size_limit 10GB [http_service] force_https true auto_stop_machines stop auto_start_machines true min_machines_running 1 processes [app] [[vm]] memory 1gb cpu_kind shared cpus 1卷容量在使用率达到 80% 时自动扩容每次增量 1GB、上限 10GBHTTP 服务强制 HTTPS机器空闲时可自动停止、有请求时自动启动且至少保留 1 台运行VM 规格为 1 vCPU / 1GB 内存对应 Dockerfile 中默认的OMNIROUTE_MEMORY_MB1024堆上限。3. 启动链路与持久化原理为什么 DATA_DIR 必须为 /data理解启动链路有助于排查部署问题。容器启动后按如下顺序执行Dockerfile 的ENTRYPOINT执行check-permissions.sh校验挂载卷属主防止非 root 用户无法写入/dataCMD执行node dev/run-standalone.mjs即仓库 scripts/dev/run-standalone.mjs该脚本首先调用bootstrapEnv()随后拉起server-ws.mjs带 WebSocket 桥接包装的 Next.js standalone 服务或回退到server.js。bootstrapEnv()的实现位于 scripts/build/bootstrap-env.mjs它是密钥持久化的关键若JWT_SECRET、STORAGE_ENCRYPTION_KEY、API_KEY_SECRET缺失会自动生成安全随机值生成的密钥会写入{DATA_DIR}/server.env日志输出[bootstrap] Secrets persisted to: 路径环境变量优先级从低到高为自动生成默认值 →{DATA_DIR}/server.env首次启动持久化→ 偏好.envDATA_DIR/.env→~/.omniroute/.env→./.env→process.envDocker-e/ Fly Secrets最高优先级。数据库初始化后src/lib/db/core.ts 会打印[DB] SQLite database ready: sqliteFile (DATA_DIRabsolute, SQLITE_FILEabsolute)因此在 Fly.io 上DATA_DIR/data是唯一的正确取值它保证server.env运行时密钥与storage.sqliteSQLite 数据库都落在 Fly Volume 上机器重建、滚动更新后数据不丢。若日志中出现/app/data/...Dockerfile 默认值说明环境变量被容器内默认值覆盖需立即修正。4. 必备工具安装 Fly CLI 并登录4.1 安装 Fly CLIWindows PowerShell 下执行pwsh -Command iwr https://fly.io/install.ps1 -useb | iex如果安装脚本在当前环境失败也可以手动下载flyctl二进制并加入PATH。4.2 登录 Fly 账号flyctl auth login4.3 检查登录状态flyctl auth whoami flyctl versionwhoami输出应显示你的 Fly 账号邮箱version输出flyctl版本号。5. 首次部署当前项目5.1 获取代码并进入目录git clone https://gitcode.com/GitHub_Trending/om/OmniRoute.git cd OmniRoute5.2 确认应用名打开 fly.toml重点确认这一行app omniroute如果你准备部署到自己的新应用可改成全局唯一名称例如app omniroute-yourname注意Fly 控制台里查看的应用必须与fly.toml中的app一致如果之前用过其他名字例如oroute不要与omniroute混淆。5.3 创建应用如果该应用尚不存在flyctl apps create omniroute若你已改名把omniroute替换成你的应用名。5.4 首次部署flyctl deployflyctl会依据fly.toml构建镜像走仓库 Dockerfile多阶段构建产物为 Next.js standalone 包、创建或复用名为data的 Fly Volume 并挂载到/data然后启动进程node run-standalone.mjs。6. 必配参数与推荐参数体系本项目在 Fly.io 上至少应配置以下参数全部通过 Fly Secrets 注入最终以环境变量形式进入process.env优先级最高。6.1 已验证使用的参数以下参数已在当前omniroute应用上实际部署验证API_KEY_SECRET— API Key 生成与校验DATA_DIR— 数据目录必须为/dataJWT_SECRET— 登录态与 JWT 签名MACHINE_ID_SALT— 生成稳定机器标识NEXT_PUBLIC_BASE_URL— 调度器、前端回调等使用的公网地址OMNIROUTE_WS_BRIDGE_SECRET— 生产必需WebSocket 桥接认证密钥STORAGE_ENCRYPTION_KEY— 加密存储敏感连接信息6.2 参数职责与源码依据变量名是否推荐说明源码依据API_KEY_SECRET必需API Key 生成与校验使用缺失时由 bootstrap-env.mjs 自动生成并持久化JWT_SECRET必需登录态和 JWT 签名使用同上自动生成为 64 字节 hexSTORAGE_ENCRYPTION_KEY强烈推荐加密存储敏感连接信息AES-256-GCM 字段加密同上若库中已有enc:v1:加密凭据而密钥丢失启动时会拒绝自动生成并提示恢复MACHINE_ID_SALT推荐生成稳定机器标识src/shared/utils/machineId.ts 中getConsistentMachineId用salt || process.env.MACHINE_ID_SALT || endpoint-proxy-salt对机器原始 ID 做 SHA-256 后取前 16 字符OMNIROUTE_WS_BRIDGE_SECRET生产必需WebSocket 桥接认证密钥src/app/api/internal/codex-responses-ws/route.ts 读取该变量并对收到的 secret 做 SHA-256 恒定时间比对缺失会导致 WS 桥接握手失败INITIAL_PASSWORD可选首次部署时直接指定后台初始密码未设置时 bootstrap-env.mjs 打印默认密码 CHANGEME警告OAuth/API 私密凭证按需各类外部平台鉴权配置如ANTIGRAVITY_OAUTH_CLIENT_SECRET、QODER_OAUTH_CLIENT_SECRET等可选 OAuth 密钥6.3 当前项目推荐值变量名推荐值DATA_DIR/dataNEXT_PUBLIC_BASE_URLhttps://omniroute.fly.devDATA_DIR/data非常关键必须与 Fly Volume 挂载点一致否则数据库与密钥落入容器临时目录NEXT_PUBLIC_BASE_URL用于调度器回调、前端回调等场景部署后若需要开启 OAuth 类 Provider如 Antigravity、Gemini、Cursor必须在 Provider 控制台把回调地址配置为NEXT_PUBLIC_BASE_URL/callback——所有 OAuth Provider 共用这一个回调路径不存在按 Provider 区分的独立回调路由。6.4 关于 INITIAL_PASSWORD当前项目部署时没有设置INITIAL_PASSWORD。不设置的表现启动日志会提示默认密码是CHANGEME部署后应尽快在系统设置中修改登录密码。如果希望无人值守初始化后台密码可以补设flyctl secrets set INITIAL_PASSWORD你的强密码 -a omniroute7. 一键设置参数下面命令会生成安全随机值并把当前项目需要的参数一次性写入 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_URLhttps://omniroute.fly.dev -a omniroute说明各密钥的长度选择与 bootstrap-env.mjs 的自动生成规格一致API_KEY_SECRET、STORAGE_ENCRYPTION_KEY为 32 字节 hexJWT_SECRET为 64 字节 hex确保与既有约定兼容OMNIROUTE_WS_BRIDGE_SECRET生产环境必须设置缺失会破坏 WebSocket 桥接握手。Linux / macOS 下也可以用openssl rand -hex 32生成flyctl secrets set OMNIROUTE_WS_BRIDGE_SECRET$(openssl rand -hex 32) -a omniroute如果你还要加初始密码flyctl secrets set INITIAL_PASSWORD你的强密码 -a omniroute8. 查看当前参数flyctl secrets list -a omniroute如果 Fly 控制台的Secrets页面没有显示你期待的变量先检查两点看的应用是不是omniroute而不是旧的oroute等其他应用fly.toml里的app是否和控制台应用一致。9. 后续更新发布代码有更新后发布步骤很简单git pull flyctl deploy如果只更新参数、不改代码flyctl secrets set KEYvalue -a omnirouteFly 会自动对机器执行滚动更新。9.1 跟踪原仓库更新并保留 fork 的 fly.toml如果当前仓库是 fork需要同步上游diegosouzapw/OmniRoute的更新推荐按下面流程执行。先确认远程git remote -v应至少包含origin指向你自己的 forkupstream指向原仓库。如果没有upstream先添加git remote add upstream https://gitcode.com/GitHub_Trending/om/OmniRoute.git同步上游前先抓取最新提交和标签git fetch upstream --tags查看当前版本和上游标签git describe --tags --always git show --no-patch --oneline v3.4.7如果你想合并上游最新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 自定义部署配置不被覆盖。如果你明确只想对齐某个发布标签例如v3.4.7可以先确认标签是否已包含在upstream/maingit merge-base --is-ancestor v3.4.7 upstream/main返回成功表示upstream/main已经包含该版本直接合并upstream/main即可。实际操作时建议以当前仓库最新版本标签为准如:latest或对应版本号文中的v3.4.7仅作为历史示例保留。9.2 同步上游后的标准发布顺序同步原仓库完成后推荐按下面顺序发布git fetch upstream --tagsgit merge upstream/main恢复 fork 的fly.tomlgit push origin mainflyctl deployflyctl status -a omnirouteflyctl logs --no-tail -a omniroute这就是当前项目升级时使用的实际流程。10. 发布后检查10.1 查看应用状态flyctl status -a omniroute10.2 查看启动日志flyctl logs --no-tail -a omniroute10.3 检查网站可访问try { (Invoke-WebRequest -Uri https://omniroute.fly.dev -MaximumRedirection 5 -UseBasicParsing).StatusCode } catch { if ($_.Exception.Response) { $_.Exception.Response.StatusCode.value__ } else { throw } }返回200说明站点已正常响应。若使用自定义域名把 URL 替换为对应域名。11. 成功标志日志中的两条关键记录部署成功后启动日志里应看到类似内容[bootstrap] Secrets persisted to: /data/server.env [DB] SQLite database ready: /data/storage.sqlite这两点很关键/data/server.env说明运行时密钥落到了持久卷由 scripts/build/bootstrap-env.mjs 写入/data/storage.sqlite说明数据库写入持久卷由 src/lib/db/core.ts 打印并附上DATA_DIR、SQLITE_FILE绝对值便于核对卷拓扑。如果你看到的是/app/data/...说明DATA_DIR没配对需要立即修正——此时数据写入了容器可写层而非 Fly Volume机器重建即丢失。12. 常见问题排查12.1 Secrets 页面是空的通常有两种原因你还没执行flyctl secrets set你打开的是另一个应用例如oroute不是omniroute。12.2 flyctl deploy 报 app not found先创建应用flyctl apps create omniroute12.3 fly.toml 解析失败重点检查注释里是否有乱码字符TOML 引号和缩进是否正确。12.4 数据没有持久化检查以下两点fly.toml中是否存在destination /dataDATA_DIR是否设置为/data。二者缺一不可卷挂载点与数据目录不一致时日志会出现/app/data/...路径见第 11 节。12.5 不设置 INITIAL_PASSWORD 是否能跑可以运行但会回退到默认密码CHANGEMEbootstrap-env.mjs 会打印相应警告。生产环境建议尽快在系统设置中修改后台密码或直接补设INITIAL_PASSWORD后重新部署。13. 新项目复用建议如果以后是新项目照着这份文档部署最少改这几项修改 fly.toml 里的app修改NEXT_PUBLIC_BASE_URL为你的公网域名保持DATA_DIR/data与卷挂载点严格一致重新生成API_KEY_SECRET、JWT_SECRET、MACHINE_ID_SALT、STORAGE_ENCRYPTION_KEY生产环境再加OMNIROUTE_WS_BRIDGE_SECRET首次部署后检查日志是否写入/data。不要直接复用旧项目的密钥密钥泄漏会波及 API Key 体系、JWT 会话与加密存储的敏感连接信息。14. 当前项目的最小发布清单当前项目后续最常用的命令如下flyctl auth whoami flyctl status -a omniroute flyctl secrets list -a omniroute flyctl deploy flyctl logs --no-tail -a omniroute如果只是正常发版核心就是flyctl deploy如果是新环境首次部署核心步骤就是flyctl auth loginflyctl apps create omnirouteflyctl secrets set ... -a omnirouteflyctl deployflyctl logs --no-tail -a omniroute延伸阅读英文原版指南docs/ops/FLY_IO_DEPLOYMENT_GUIDE.md简体中文版指南docs/i18n/zh-CN/docs/ops/FLY_IO_DEPLOYMENT_GUIDE.md部署配置文件fly.toml 与 Dockerfile启动入口与密钥引导scripts/dev/run-standalone.mjs、scripts/build/bootstrap-env.mjs数据库初始化与状态日志src/lib/db/core.ts部署相关的其余运维文档可参考 docs/ops 目录如 docs/ops/DOCKER_GUIDE.md、docs/ops/VM_DEPLOYMENT_GUIDE.md、docs/ops/REDIS_PRODUCTION_CONFIG.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, RTKCaveman compression saves 15-95% tokens, MCP/A2A, Desktop/PWA. Built by 550 contributors项目地址: https://gitcode.com/GitHub_Trending/om/OmniRoute创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考