---
title: "OmniRoute Fly.io 部署指南"
version: 3.8.2
lastUpdated: 2026-05-13
---

# OmniRoute Fly.io 部署指南

本文档记录 OmniRoute 在 Fly.io 上的实际部署方法，适用于两类场景：

- 首次把当前项目部署到 Fly.io
- 后续代码更新后继续发布
- 新项目参考同样流程部署

本文基于当前项目已经验证通过的配置整理，应用名为 `omniroute`。

---

## 1. 部署目标

- 平台：Fly.io
- 部署方式：本地 `flyctl` 直接发布
- 运行方式：使用仓库内现有 `Dockerfile` 和 `fly.toml`
- 数据持久化：Fly Volume 挂载到 `/data`
- 访问地址：`https://omniroute.fly.dev/`

---

## 2. 当前项目关键配置

当前仓库中的 `fly.toml` 已确认包含以下关键项：

```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`，否则数据库和密钥会写到容器临时目录

---

## 3. 必备工具

### 3.1 安装 Fly CLI

Windows PowerShell：

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

如果安装脚本在当前环境失败，也可以手动下载 `flyctl` 二进制并放到 `PATH` 中。

### 3.2 登录 Fly 账号

```powershell
flyctl auth login
```

### 3.3 检查登录状态

```powershell
flyctl auth whoami
flyctl version
```

---

## 4. 首次部署当前项目

### 4.1 获取代码并进入目录

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

### 4.2 确认应用名

打开 `fly.toml`，重点看这一行：

```toml
app = 'omniroute'
```

如果你准备部署到自己的新应用，可改成全局唯一名称，例如：

```toml
app = 'omniroute-yourname'
```

注意：

- 控制台里要看的是与 `fly.toml` 里 `app` 一致的应用
- 以前如果用过别的名字，例如 `oroute`，不要和 `omniroute` 混淆

### 4.3 创建应用

如果该应用尚不存在：

```powershell
flyctl apps create omniroute
```

如果你已经改成别的应用名，把 `omniroute` 替换成你的名字。

### 4.4 首次部署

```powershell
flyctl deploy
```

---

## 5. 必配参数

本项目在 Fly.io 上建议至少配置以下参数。

### 5.1 已验证使用的参数

这些参数已经在当前 `omniroute` 应用上实际部署：

- `API_KEY_SECRET`
- `DATA_DIR`
- `JWT_SECRET`
- `MACHINE_ID_SALT`
- `NEXT_PUBLIC_BASE_URL`
- `OMNIROUTE_WS_BRIDGE_SECRET` (生产环境必需 / required in production / obrigatório em produção — 用于 WebSocket 桥接鉴权 / used for WebSocket bridge authentication)
- `STORAGE_ENCRYPTION_KEY`

### 5.2 关于 `INITIAL_PASSWORD`

当前项目没有设置 `INITIAL_PASSWORD`，因为本次部署按需求不使用它。

如果不设置：

- 启动日志会提示默认密码是 `CHANGEME`
- 部署后应尽快在系统设置中修改登录密码

如果你希望无人值守初始化后台密码，也可以后续补：

- `INITIAL_PASSWORD`

---

## 6. 推荐参数说明

### 6.1 Secrets 中设置

建议放入 Fly Secrets：

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

### 6.2 当前项目推荐值

| 变量名                 | 推荐值                      |
| ---------------------- | --------------------------- |
| `DATA_DIR`             | `/data`                     |
| `NEXT_PUBLIC_BASE_URL` | `https://omniroute.fly.dev` |

说明：

- `DATA_DIR=/data` 非常关键，必须与 Fly Volume 挂载点一致
- `NEXT_PUBLIC_BASE_URL` 用于调度器和前端回调等场景

### 6.3 OAuth 回调地址配置 (OAuth callback URL / URL de callback OAuth)

如果你需要在 Fly.io 部署上启用 OAuth 登录类的 provider（例如 Antigravity、Gemini、Cursor 等），必须确保以下两点：
(If you need to enable OAuth-based providers — e.g. Antigravity, Gemini, Cursor — on the Fly.io deployment, make sure of the following two points. / Se precisar habilitar providers via OAuth — p.ex. Antigravity, Gemini, Cursor — na implantação Fly.io, garanta os dois pontos abaixo.)

1. **设置 `NEXT_PUBLIC_BASE_URL` 指向你公开的 HTTPS 域名 (set `NEXT_PUBLIC_BASE_URL` to the public HTTPS domain / defina `NEXT_PUBLIC_BASE_URL` para o domínio HTTPS público)**

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

   如果你使用了自定义域名 (if using a custom domain / se usar um domínio personalizado)，请替换为对应域名 (e.g. `https://omniroute.yourdomain.com`)。

2. **在 provider 控制台配置回调 URL (configure the callback URL on the provider console / configure a URL de callback no painel do provider)**

   通常格式为 (typical format / formato típico)：

   ```text
   <NEXT_PUBLIC_BASE_URL>/api/oauth/<provider>/callback
   ```

   例如 (e.g. / p.ex.)：
   - `https://omniroute.fly.dev/api/oauth/gemini/callback`
   - `https://omniroute.fly.dev/api/oauth/antigravity/callback`
   - `https://omniroute.fly.dev/api/oauth/cursor/callback`

   如果 `NEXT_PUBLIC_BASE_URL` 与 provider 控制台中注册的回调 URL 不一致，OAuth 流程会在浏览器回跳阶段失败 (mismatch between `NEXT_PUBLIC_BASE_URL` and the registered callback URL will cause OAuth to fail at the browser redirect step / divergência entre `NEXT_PUBLIC_BASE_URL` e a URL de callback registrada quebra o OAuth no redirect do navegador)。

---

## 7. 一键设置参数

下面命令会生成安全随机值，并把当前项目需要的参数一次性写入 Fly Secrets。

说明：

- 不包含 `INITIAL_PASSWORD`
- 适用于当前项目 `omniroute`

```powershell
$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 32` 生成 (on Linux / macOS, you can also use `openssl rand -hex 32` / em Linux / macOS, também é possível usar `openssl rand -hex 32`)：

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

说明 (notes / observações)：

- `OMNIROUTE_WS_BRIDGE_SECRET` 在生产环境必需，缺失会导致 WebSocket 桥接握手失败 (required in production; missing it breaks WebSocket bridge handshake / obrigatório em produção; sem ele o handshake da ponte WebSocket falha)

如果你还要加初始密码：

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

---

## 8. 查看当前参数

```powershell
flyctl secrets list -a omniroute
```

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

- 看的应用是不是 `omniroute`
- `fly.toml` 的 `app` 是否和控制台应用一致

---

## 9. 后续更新发布

代码有更新后，发布步骤很简单：

```powershell
git pull
flyctl deploy
```

如果只更新参数，不改代码：

```powershell
flyctl secrets set KEY=value -a omniroute
```

Fly 会自动滚动更新机器。

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

如果当前仓库是 fork，并且你要同步上游 `https://github.com/diegosouzapw/OmniRoute` 的更新，推荐按下面流程执行。

先确认远程：

```powershell
git remote -v
```

应至少包含：

- `origin` 指向你自己的 fork
- `upstream` 指向原仓库

如果没有 `upstream`，先添加：

```powershell
git remote add upstream https://github.com/diegosouzapw/OmniRoute.git
```

同步上游前，先抓取最新提交和标签：

```powershell
git fetch upstream --tags
```

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

```powershell
git describe --tags --always
git show --no-patch --oneline v3.4.7
```

> 注 (note / nota)：当前项目版本为 `v3.8.0` (current project version is `v3.8.0` / a versão atual do projeto é `v3.8.0`)。下文中的 `v3.4.7` 仅为历史示例 (the `v3.4.7` references below are kept as historical examples only / as referências a `v3.4.7` abaixo são apenas exemplos históricos)；实际发布时请使用 `:latest` 或当前版本标签 (e.g. `:v3.8.0`) (use `:latest` or the current version tag — e.g. `:v3.8.0` — for actual releases / use `:latest` ou a tag da versão atual — p.ex. `:v3.8.0` — em releases reais)。

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

```powershell
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/main`：

```powershell
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` 时使用的实际流程 (示例为历史版本，当前实际版本是 `v3.8.0` / example refers to a historical version; the current actual version is `v3.8.0` / o exemplo refere-se a uma versão histórica; a versão atual é `v3.8.0`)。

---

## 10. 发布后检查

### 10.1 查看应用状态

```powershell
flyctl status -a omniroute
```

### 10.2 查看启动日志

```powershell
flyctl logs --no-tail -a omniroute
```

### 10.3 检查网站可访问

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

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

---

## 11. 成功标志

部署成功后，日志里应看到类似内容：

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

这两个点很关键：

- `/data/server.env` 说明运行时密钥落到了持久卷
- `/data/storage.sqlite` 说明数据库写入持久卷

如果你看到的是 `/app/data/...`，说明 `DATA_DIR` 没配对，需要立即修正。

---

## 12. 常见问题

### 12.1 `Secrets` 页面是空的

通常有两种原因：

- 你还没执行 `flyctl secrets set`
- 你打开的是另一个应用，例如 `oroute`，不是 `omniroute`

### 12.2 `flyctl deploy` 报 `app not found`

先创建应用：

```powershell
flyctl apps create omniroute
```

### 12.3 `fly.toml` 解析失败

重点检查：

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

### 12.4 数据没有持久化

检查以下两点：

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

### 12.5 不设置 `INITIAL_PASSWORD` 是否能跑

可以运行，但会回退到默认 `CHANGEME`。生产环境建议尽快修改后台密码。

---

## 13. 新项目复用建议

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

1. 修改 `fly.toml` 里的 `app`
2. 修改 `NEXT_PUBLIC_BASE_URL`
3. 保持 `DATA_DIR=/data`
4. 重新生成 `API_KEY_SECRET`、`JWT_SECRET`、`MACHINE_ID_SALT`、`STORAGE_ENCRYPTION_KEY`
5. 首次部署后检查日志是否写入 `/data`

不要直接复用旧项目的密钥。

---

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

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

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

如果只是正常发版，核心就是：

```powershell
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`
