| title | OmniRoute Fly.io Deployment Guide |
|---|---|
| version | 3.8.52 |
| lastUpdated | 2026-10-05 |
This document describes the actual deployment process for OmniRoute on Fly.io, covering two scenarios:
- Deploying the current project to Fly.io for the first time
- Publishing subsequent code updates
- New projects following the same deployment workflow
This guide is based on a verified working configuration for the current project. The application name is omniroute.
- Platform: Fly.io
- Deployment method: Local
flyctldirect publish - Runtime: Using the existing
Dockerfileandfly.tomlin the repository - Data persistence: Fly Volume mounted to
/data - Access URL:
https://omniroute.fly.dev/
The fly.toml in the current repository has been confirmed to contain the following key items:
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"Notes:
app = 'omniroute'determines which Fly application the deployment targetsdestination = '/data'determines the persistent volume mount directory- This project must set
DATA_DIR=/data, otherwise the database and keys will be written to the container's temporary directory
Windows PowerShell:
pwsh -Command "iwr https://fly.io/install.ps1 -useb | iex"If the install script fails in your environment, you can also manually download the flyctl binary and add it to your PATH.
flyctl auth loginflyctl auth whoami
flyctl versiongit clone https://github.com/diegosouzapw/OmniRoute.git
cd OmniRouteOpen fly.toml and verify the following line:
app = 'omniroute'If you are deploying to your own new application, you can change it to a globally unique name, for example:
app = 'omniroute-yourname'Note:
- Make sure the application you see in the console matches the
appvalue infly.toml - If you previously used a different name, such as
oroute, do not confuse it withomniroute
If the application does not yet exist:
flyctl apps create omnirouteIf you changed the application name, replace omniroute with your chosen name.
flyctl deployThis project recommends configuring at least the following parameters on Fly.io.
These parameters have been used in actual deployments on the current omniroute application:
API_KEY_SECRETDATA_DIRJWT_SECRETMACHINE_ID_SALTNEXT_PUBLIC_BASE_URLOMNIROUTE_WS_BRIDGE_SECRET(required in production — used for WebSocket bridge authentication)STORAGE_ENCRYPTION_KEY
The current project does not set INITIAL_PASSWORD because this deployment does not require it.
If it is not set:
- You create the dashboard password in the onboarding wizard on first visit. Complete the password step: skipping it turns dashboard login off, which leaves the dashboard open to anyone who can reach the app URL
- Fly's proxy reaches the app from a non-loopback address, so after you submit the password the wizard asks for a one-time bootstrap token, which the app prints to its log at that moment:
flyctl logs --no-tail -a omniroute | Select-String BOOTSTRAP. If that line has scrolled out of the log, restart the app and submit the wizard again to print a new token
To set the password unattended instead, add it before the first dashboard visit (once a password is saved, INITIAL_PASSWORD is ignored):
INITIAL_PASSWORD
The following variables are recommended for Fly Secrets:
| Variable | Recommendation | Description |
|---|---|---|
API_KEY_SECRET |
Required | Used for API Key generation and validation |
JWT_SECRET |
Required | Used for login sessions and JWT signing |
OMNIROUTE_WS_BRIDGE_SECRET |
Required in production | WebSocket bridge authentication secret |
STORAGE_ENCRYPTION_KEY |
Strongly recommended | Encrypts sensitive connection information at rest |
MACHINE_ID_SALT |
Recommended | Generates a stable machine identifier |
INITIAL_PASSWORD |
Optional | Sets the initial backend password at first deployment |
| OAuth/API private credentials | As needed | External platform authentication configuration |
| Variable | Recommended Value |
|---|---|
DATA_DIR |
/data |
NEXT_PUBLIC_BASE_URL |
https://omniroute.fly.dev |
Notes:
DATA_DIR=/datais critical and must match the Fly Volume mount pointNEXT_PUBLIC_BASE_URLis used by the scheduler, frontend callbacks, and similar scenarios
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:
-
Set
NEXT_PUBLIC_BASE_URLto your public HTTPS domainflyctl secrets set NEXT_PUBLIC_BASE_URL=https://omniroute.fly.dev -a omniroute
If you are using a custom domain, replace it with the corresponding domain (e.g.
https://omniroute.yourdomain.com). -
Configure the callback URL on the provider console
All OAuth providers share the single callback path
/callback— there is NO per-provider callback route:<NEXT_PUBLIC_BASE_URL>/callbackFor example, regardless of Gemini, Antigravity, Cursor, or GitLab Duo:
https://omniroute.fly.dev/callback
If
NEXT_PUBLIC_BASE_URLdoes not match the callback URL registered with the provider, the OAuth flow will fail at the browser redirect step.
The following commands generate secure random values and write all required parameters for the current project to Fly Secrets in one step.
Notes:
- Does not include
INITIAL_PASSWORD - Intended for the current project
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 omnirouteOn Linux / macOS, you can also use openssl rand -hex 32:
flyctl secrets set OMNIROUTE_WS_BRIDGE_SECRET=$(openssl rand -hex 32) -a omnirouteNotes:
OMNIROUTE_WS_BRIDGE_SECRETis required in production; missing it will break the WebSocket bridge handshake
If you also want to set an initial password, set it before the first dashboard visit:
flyctl secrets set INITIAL_PASSWORD=your-strong-password -a omnirouteflyctl secrets list -a omnirouteIf the Secrets page in the console does not show the expected variables, check:
- That you are viewing the
omnirouteapplication - That the
appvalue infly.tomlmatches the application in the console
After code updates, the release process is straightforward:
git pull
flyctl deployIf you only need to update parameters without changing code:
flyctl secrets set KEY=value -a omnirouteFly will automatically perform a rolling update of machines.
If the current repository is a fork and you want to sync updates from the upstream https://github.com/diegosouzapw/OmniRoute, follow the workflow below.
First, verify your remotes:
git remote -vYou should see at least:
originpointing to your own forkupstreampointing to the original repository
If upstream is not configured, add it:
git remote add upstream https://github.com/diegosouzapw/OmniRoute.gitBefore syncing with upstream, fetch the latest commits and tags:
git fetch upstream --tagsCheck the current version and upstream tags:
git describe --tags --always
git show --no-patch --oneline v3.4.7Note: The current project version is
v3.8.0. Thev3.4.7references below are kept as historical examples only. For actual releases, use:latestor the current version tag (e.g.:v3.8.0).
If you want to merge the latest upstream main while forcefully keeping your fork's fly.toml, follow this workflow:
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 mainNotes:
git merge upstream/mainsyncs the latest code from the original repositorygit checkout HEAD~1 -- fly.tomlrestores your fork's ownfly.tomlfrom before the merge- If upstream did not modify
fly.toml, this step will not introduce any differences - If upstream did modify
fly.toml, this step ensures your Fly application name, volume mount, region, and other fork-specific deployment configuration are not overwritten
If you want to align with a specific release tag (e.g. v3.4.7), first verify that the tag is already included in upstream/main:
git merge-base --is-ancestor v3.4.7 upstream/mainA successful return means upstream/main already contains that version; you can simply merge upstream/main.
After syncing with the original repository, follow this recommended release order:
git fetch upstream --tagsgit merge upstream/main- Restore the fork's
fly.toml git push origin mainflyctl deployflyctl status -a omnirouteflyctl logs --no-tail -a omniroute
This is the actual workflow used when upgrading the current project to v3.4.7 (the example refers to a historical version; the current actual version is v3.8.0).
flyctl status -a omnirouteflyctl logs --no-tail -a omniroutetry {
(Invoke-WebRequest -Uri "https://omniroute.fly.dev" -MaximumRedirection 5 -UseBasicParsing).StatusCode
} catch {
if ($_.Exception.Response) {
$_.Exception.Response.StatusCode.value__
} else {
throw
}
}A return value of 200 indicates the site is responding normally.
After a successful deployment, the logs should show content similar to:
[bootstrap] Secrets persisted to: /data/server.env
[DB] SQLite database ready: /data/storage.sqlite
These two points are critical:
/data/server.envconfirms the runtime secrets are written to the persistent volume/data/storage.sqliteconfirms the database is written to the persistent volume
If you see /app/data/... instead, DATA_DIR is misconfigured and must be corrected immediately.
There are usually two reasons:
- You have not yet run
flyctl secrets set - You are viewing a different application (e.g.
orouteinstead ofomniroute)
Create the application first:
flyctl apps create omnirouteCheck the following:
- Whether there are garbled characters in comments
- Whether TOML quoting and indentation are correct
Verify both of the following:
fly.tomlcontainsdestination = '/data'DATA_DIRis set to/data
Yes. With INITIAL_PASSWORD unset, you create the dashboard password in the onboarding wizard on first visit (section 5.2 covers the one-time bootstrap token and the password step).
If you are deploying a new project following this document, you only need to change these items:
- Change the
appvalue infly.toml - Change
NEXT_PUBLIC_BASE_URL - Keep
DATA_DIR=/data - Regenerate
API_KEY_SECRET,JWT_SECRET,MACHINE_ID_SALT, andSTORAGE_ENCRYPTION_KEY - After the first deployment, verify that logs are written to
/data
Do not reuse keys from a previous project.
The most commonly used commands for subsequent releases are:
flyctl auth whoami
flyctl status -a omniroute
flyctl secrets list -a omniroute
flyctl deploy
flyctl logs --no-tail -a omnirouteFor a normal release, the core command is simply:
flyctl deployFor a first-time deployment in a new environment, the core steps are:
flyctl auth loginflyctl apps create omnirouteflyctl secrets set ... -a omnirouteflyctl deployflyctl logs --no-tail -a omniroute