news 2026/9/13 1:37:40

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 统一 AI 网关在 Fly.io 平台上的真实部署流程展开,覆盖首次部署、密钥/环境变量配置、后续更新发布、fork 同步与发布后验证五个环节,并深入对应源码解释DATA_DIR、Fly Volume 与运行时密钥持久化的底层机制。读完本文,你将能独立把一个 OmniRoute 实例部署到omniroute.fly.dev,正确配置API_KEY_SECRETJWT_SECRETSTORAGE_ENCRYPTION_KEY等核心参数,并通过日志判断数据库与密钥是否真正写入持久卷。


1. 部署目标与整体形态

OmniRoute 在 Fly.io 上的部署方式为:本地flyctl直接发布,复用仓库内现成的 fly.toml 与 Dockerfile,数据通过 Fly Volume 持久化到容器的/data目录,对外访问地址为https://omniroute.fly.dev/

部署目标可归纳为:

项目取值
平台Fly.io
发布方式本地flyctl直接部署
构建依据仓库内Dockerfile+fly.toml
数据持久化Fly Volume 挂载到容器/data
访问地址https://omniroute.fly.dev/
应用名omniroute

整个流程适用三类场景:首次把当前项目部署到 Fly.io、后续代码更新后继续发布、以及新项目参考同样的流程复用部署。


2. 仓库关键配置解析(fly.toml)

仓库根目录的 fly.toml 已包含可实际部署的完整配置,核心内容如下:

app = 'omniroute' primary_region = 'sin' [build] [processes] app = 'node run-standalone.mjs' [deploy] # release_command = "node ./dbsetup.js" [[mounts]] source = 'data' destination = '/data' auto_extend_size_threshold = 80 auto_extend_size_increment = '1GB' auto_extend_size_limit = '10GB' [http_service] internal_port = 20128 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 memory_mb = 1024 [env] TZ = "Asia/Shanghai" HOST = "0.0.0.0" HOSTNAME = "0.0.0.0" BIND = "0.0.0.0"

各关键项的作用如下:

  • app = 'omniroute':决定实际部署到哪个 Fly 应用。若部署到自己的新应用,需改为全局唯一名称,例如omniroute-yourname
  • primary_region = 'sin':指定主部署区域(新加坡),Fly 会按该区域就近调度机器。
  • [[mounts]]source = 'data'是 Fly 侧的 Volume 名称,destination = '/data'决定持久卷在容器内的挂载目录;auto_extend_size_*三项控制卷容量达到阈值后自动扩容(80% 阈值、每次 +1GB、上限 10GB)。
  • [processes] app = 'node run-standalone.mjs':指定应用主进程的启动命令。Fly 的[processes]表为每个命名进程单独调度机器,app进程对应的命令与 Dockerfile 末尾的CMD ["node", "dev/run-standalone.mjs"]语义一致,即以独立部署产物方式启动服务器。
  • [http_service] internal_port = 20128:Fly 负载均衡器把外部流量转发到容器内的 20128 端口,该端口与 Dockerfile 中的ENV PORT=20128EXPOSE 20128一一对应。
  • [vm]:机器规格为共享 CPU、1 核、1GB 内存。需要注意的是 Dockerfile 中运行时堆上限默认OMNIROUTE_MEMORY_MB=1024,两者需配套;若你在fusionTuning.maxPanel等配置上做了大并行度调优,需同步通过-e OMNIROUTE_MEMORY_MB=2048提高堆上限,否则可能出现内存压力。
  • [env]TZ=Asia/Shanghai设置容器时区;HOSTHOSTNAMEBIND全部绑定0.0.0.0,是为了适配 Fly 运行时网络对全接口监听的硬性要求。

2.1 为什么DATA_DIR=/data是部署成败的关键

fly.toml中并没有直接写DATA_DIR,但这恰恰是需要重点注意的地方。src/lib/dataPaths.ts 中的resolveDataDir的解析顺序是:

  1. 若显式配置了DATA_DIR,直接使用该路径;
  2. 否则回退到默认用户目录(Linux 上为~/.omniroute)。

而容器内默认用户目录是/home/node,属于容器临时文件系统。因此本项目在 Fly.io 上必须通过 Secrets 显式设置DATA_DIR=/data,否则数据库与密钥会写进容器临时目录,机器重建后数据全部丢失。这也是 fly.toml 中 Volume 挂载点选择/data的根本原因——保证挂载点与运行时数据目录完全一致。


3. 必备工具准备

3.1 安装 Fly CLI

Windows PowerShell 下执行官方安装脚本:

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

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

3.2 登录与校验

flyctl auth login flyctl auth whoami flyctl version

auth login会在浏览器中完成 OAuth 授权;whoami用于确认当前登录账号,version确认 CLI 版本正常。发布前先跑这两条可以提前暴露凭证问题。


4. 首次部署流程

4.1 获取代码

git clone https://github.com/diegosouzapw/OmniRoute.git cd OmniRoute

4.2 确认应用名

打开 fly.toml,确认app = 'omniroute'。如果你要部署到自己的新应用,改成全局唯一名称:

app = 'omniroute-yourname'

注意区分控制台里的应用名:以前如果用过别的名字(例如oroute),不要和omniroute混淆,后续所有命令都以fly.toml中的app为准。

4.3 创建应用(如尚不存在)

flyctl apps create omniroute

如果改了应用名,把omniroute替换成你的名字。

4.4 首次部署

flyctl deploy

Fly 会自动读取fly.toml、按Dockerfile构建镜像、创建并挂载data卷、调度机器并配置负载均衡。


5. 必配参数与源码依据

在 Fly.io 上部署 OmniRoute 至少要配置以下环境变量,它们的用途都能在源码中找到明确实现。

5.1 已验证使用的参数

当前omniroute应用实际部署并验证的参数包括:

  • API_KEY_SECRET
  • DATA_DIR
  • JWT_SECRET
  • MACHINE_ID_SALT
  • NEXT_PUBLIC_BASE_URL
  • STORAGE_ENCRYPTION_KEY

各参数的源码依据:

  • API_KEY_SECRET(必需):用于 API Key 的生成与校验。src/shared/utils/apiKey.ts 中,若未设置该变量会输出[SECURITY] API_KEY_SECRET is not set. API key CRC validation is disabled.,即 API Key 的 CRC 校验被禁用;src/instrumentation-node.ts 会在启动时自动生成并持久化 64 位十六进制随机值。
  • JWT_SECRET(必需):用于登录态与 JWT 签名。src/instrumentation-node.ts 显示,缺失时系统会自动生成 48 字节随机值并写入持久化存储。
  • STORAGE_ENCRYPTION_KEY(强烈推荐):用于加密存储供应商连接等敏感信息。src/lib/db/encryption.ts 明确说明:未设置时进入 passthrough 模式,凭据以明文写入 SQLite(日志提示[Encryption] STORAGE_ENCRYPTION_KEY not set. Storing plaintext (passthrough mode).)。生产环境必须设置,且更换密钥会导致既有密文无法解密(仓库中对应错误提示为 "Re-authenticate this account, or verify STORAGE_ENCRYPTION_KEY matches the key used to store it.")。
  • MACHINE_ID_SALT(推荐):用于生成稳定机器标识。src/shared/utils/machineId.ts 中getConsistentMachineId读取该盐值(默认endpoint-proxy-salt),对操作系统机器 ID 做 SHA-256 后取前 16 位作为稳定标识。在 Fly 这种按需重建机器的环境中,显式设置盐值可以保证标识稳定可复现。
  • INITIAL_PASSWORD(可选):首次部署时直接指定后台初始密码,详见 5.2。

5.2 关于INITIAL_PASSWORD

当前项目没有设置INITIAL_PASSWORD。如果不设置:

  • 启动日志会提示默认密码为CHANGEME,对应 scripts/build/bootstrap-env.mjs 中的警告逻辑:⚠️ INITIAL_PASSWORD is not set — using default 'CHANGEME'. Change it in Settings!
  • 部署后应尽快在系统设置中修改登录密码。

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


6. 推荐参数总表

6.1 建议放入 Fly Secrets 的参数

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

6.2 当前项目推荐值

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

说明:

  • DATA_DIR=/data非常关键,必须与 fly.toml 中[[mounts]] destination = '/data'的挂载点一致;
  • NEXT_PUBLIC_BASE_URL用于调度器回调、前端回调等场景,须填写最终对外可访问的公网地址。

7. 一键设置参数(PowerShell)

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

$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() flyctl secrets set ` API_KEY_SECRET=$apiKeySecret ` JWT_SECRET=$jwtSecret ` MACHINE_ID_SALT=$machineIdSalt ` STORAGE_ENCRYPTION_KEY=$storageKey ` DATA_DIR=/data ` NEXT_PUBLIC_BASE_URL=https://omniroute.fly.dev ` -a omniroute

如果你还要加初始密码:

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

脚本中各随机值的生成长度与源码中的预期一致:API_KEY_SECRETSTORAGE_ENCRYPTION_KEY为 32 字节(scripts/build/bootstrap-env.mjs 中randomBytes(32).toString("hex")生成 64 位十六进制),JWT_SECRET为 64 字节。也可以使用openssl rand -hex 32等工具替代生成。

7.1 一键设置背后的持久化机制

设置完成后,容器首次启动时 scripts/build/bootstrap-env.mjs 的bootstrapEnv会按三层优先级合并环境变量:持久化的server.env< 项目.env< 进程环境变量(含 Fly Secrets)。由于 Fly Secrets 会作为容器环境变量注入,因此优先级最高,能正确覆盖缺省值。

同时该函数还承担两件关键工作:

  1. 自动补齐缺失密钥:当JWT_SECRETSTORAGE_ENCRYPTION_KEYAPI_KEY_SECRET任一为空时自动生成随机值,并写入{DATA_DIR}/server.env(对应日志📁 Secrets persisted to: ...);
  2. 密钥一致性探测:若数据库中已存在enc:v1:前缀的加密凭据(provider_connections表的api_key/access_token等字段),会校验当前STORAGE_ENCRYPTION_KEY是否能正确解密,防止误用新密钥导致既有数据无法读取。

8. 查看当前参数

flyctl secrets list -a omniroute

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

  • 打开的应用是不是omniroute
  • fly.toml 的app是否与控制台应用一致。

9. 后续更新发布

代码有更新后的发布步骤:

git pull flyctl deploy

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

flyctl secrets set KEY=value -a omniroute

Fly 会自动滚动更新机器,无需手动重建。

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

如果当前仓库是 fork,需要同步上游https://github.com/diegosouzapw/OmniRoute的更新,推荐流程如下。

先确认远程:

git remote -v

应至少包含origin(指向自己的 fork)和upstream(指向原仓库)。如果没有upstream,先添加:

git remote add upstream https://github.com/diegosouzapw/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 应用名、挂载卷、区域等 fork 自定义部署配置不被覆盖。

如果你明确只想对齐某个发布标签(例如v3.4.7),可以先确认该标签是否已经包含在upstream/main中:

git merge-base --is-ancestor v3.4.7 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

这是当前项目升级到v3.4.7时使用的实际流程。


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

这两行的含义都可以在源码中得到印证:

  • Secrets persisted to: /data/server.env:来自 scripts/build/bootstrap-env.mjs,表示自动生成的运行时密钥已写入持久卷下的server.env
  • SQLite database ready: /data/storage.sqlite:来自 src/lib/db/core.ts,日志会同时打印DATA_DIR=SQLITE_FILE=的绝对路径,用于直接核对多副本/卷拓扑是否一致(同一问题在 src/app/api/storage/health/route.ts 的健康检查接口中也会以{DATA_DIR}/storage.sqlite形式暴露)。

如果你看到的是/app/data/...,说明DATA_DIR没配对,需要立即修正。这正是 Dockerfile 中ENV DATA_DIR=/app/data默认值与 Fly Volume 挂载点/data不一致导致的典型症状:Docker 本地部署默认数据目录是/app/data,而 Fly 上必须显式覆盖为/data才能命中持久卷。

另外,Dockerfile 内置的健康检查(HEALTHCHECK调用 scripts/dev/healthcheck.mjs 探测轻量/healthz端点)与check-permissions.sh入口脚本会在容器启动时检查数据卷属主,遇到权限问题会在日志中提前暴露。


12. 常见问题排查

12.1 Secrets 页面是空的

通常有两种原因:

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

12.2flyctl deployapp not found

先创建应用:

flyctl apps create omniroute

12.3fly.toml解析失败

重点检查:

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

12.4 数据没有持久化

检查以下两点:

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

二者缺一不可:Volume 挂载点与运行时数据目录必须指向同一路径,否则会出现"容器重启后数据丢失"或"多副本各写各的库"的假象。

12.5 不设置INITIAL_PASSWORD是否能跑

可以运行,但会回退到默认密码CHANGEME(对应 scripts/build/bootstrap-env.mjs 的启动警告)。生产环境建议尽快在系统设置中修改后台密码。


13. 新项目复用建议

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

  1. 修改 fly.toml 里的app
  2. 修改NEXT_PUBLIC_BASE_URL
  3. 保持DATA_DIR=/data
  4. 重新生成API_KEY_SECRETJWT_SECRETMACHINE_ID_SALTSTORAGE_ENCRYPTION_KEY
  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
    4. flyctl deploy
    5. flyctl logs --no-tail -a omniroute

延伸阅读

  • fly.toml:Fly 平台部署配置(应用名、区域、卷、端口、进程)
  • Dockerfile:多阶段镜像构建、运行时环境变量与非 root 运行
  • src/lib/dataPaths.ts:DATA_DIR解析与写入校验逻辑
  • scripts/build/bootstrap-env.mjs:server.env持久化与密钥自动生成
  • src/lib/db/core.ts:SQLite 初始化与启动日志
  • src/lib/db/encryption.ts:STORAGE_ENCRYPTION_KEY加解密与 passthrough 模式
  • src/shared/utils/machineId.ts:MACHINE_ID_SALT稳定机器标识实现
  • docs/ops/MONITORING_GUIDE.md 与 docs/ops/VM_DEPLOYMENT_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/13 1:32:13

PostgreSQL JSON类型深度解析:json与jsonb选型、索引机制及生产实践

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

作者头像 李华
网站建设 2026/9/13 1:31:34

如何用 AI SDK 在 SvelteKit 项目中完成第一次流式聊天 Agent 开发

如何用 AI SDK 在 SvelteKit 项目中完成第一次流式聊天 Agent 开发 【免费下载链接】ai The AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and agents 项目地址: https://git…

作者头像 李华
网站建设 2026/9/13 1:30:51

Claude与OpenAI大模型API核心技术对比与工程实践

1. 核心能力对比&#xff1a;Claude与OpenAI的基因差异Claude和OpenAI虽然都是当前领先的大模型API服务&#xff0c;但两者的技术路线和擅长领域存在显著差异。经过半年多的生产环境实测&#xff0c;我发现这种差异会直接影响开发效率和应用效果。1.1 文本处理能力的实测对比在…

作者头像 李华
网站建设 2026/9/13 1:26:27

Python+Django构建高并发校园食堂点餐系统

1. 项目背景与核心价值校园食堂点餐系统是每个高校信息化建设中不可或缺的一环。传统的人工排队点餐方式存在诸多痛点&#xff1a;高峰时段排队时间长、人工结算效率低、菜品信息不透明、订单管理混乱等。这套基于PythonDjango的解决方案&#xff0c;正是为了解决这些实际问题而…

作者头像 李华