OmniRoute AI router â lean image with failover and Codex reliability fixes
2.7K
OmniRouteâ with a few reliability fixes on top, in a lean image.
OmniRoute is a self-hosted AI router: one OpenAI-compatible endpoint in front of 160+ providers, with account pooling, automatic fallback, combos and a web dashboard. This image is the upstream release plus a small, focused patch set, and every patch is dropped as soon as upstream ships its own fix.
Unofficial community build. Not affiliated with the OmniRoute project. For the stock image see upstream.
docker run -d --name omniroute \
-p 127.0.0.1:20128:20128 \
-v omniroute-data:/app/data \
-e JWT_SECRET="$(openssl rand -base64 48)" \
-e API_KEY_SECRET="$(openssl rand -hex 32)" \
-e INITIAL_PASSWORD="change-me-now" \
borodulin/omniroute:latest
Open http://localhost:20128â and sign in with INITIAL_PASSWORD.
services:
omniroute:
image: borodulin/omniroute:v3.8.51-r3
container_name: omniroute
restart: unless-stopped
stop_grace_period: 40s
environment:
DATA_DIR: /app/data
JWT_SECRET: ${JWT_SECRET} # openssl rand -base64 48
API_KEY_SECRET: ${API_KEY_SECRET} # openssl rand -hex 32
INITIAL_PASSWORD: ${INITIAL_PASSWORD}
REQUIRE_API_KEY: "true" # see "Before you expose it" below
volumes:
- ./data:/app/data
ports:
- "127.0.0.1:20128:20128"
The full list of settings is in upstream's .env.exampleâ .
| Patch | Why you'd want it | |
|---|---|---|
| âąī¸ | Cooldown is no longer reported as quota exhaustion | A 5-second blip on one account no longer takes a whole pool offline for hours |
| đ§Š | Codex client version 0.162.0 | Newer Codex models stop failing with "requires a newer version of Codex" |
| đĒļ | Lean image, no Chromium | Smaller pull, smaller attack surface |
When a pool mixes an account that is genuinely out of quota with a healthy account that is cooling down for a few seconds after a network error, upstream reports the quota reset time â hours or even days away â and marks the failure non-retryable. Requests fail even though a working account is seconds from being available again.
This build reports the nearer transient cooldown instead, so the built-in wait-and-retry logic rides it out. Pools that really are out of quota behave exactly as before.
The default Codex client fingerprint is bumped from 0.156.1 to 0.162.0. An outdated version makes OpenAI refuse newer models with "requires a newer version of Codex". You can still override it per deployment with CODEX_CLIENT_VERSION.
Tags from v3.8.50-codex159 onward are built from upstream's runner-base target: no Chromium, no Playwright. Providers that only need an API key or OAuth are unaffected. Web-cookie providers that drive a real browser (Gemini Web, Claude Web with Turnstile) need a -web tag â the last one published is v3.8.50-web-codex156.
| Tag | Upstream | Notes |
|---|---|---|
latest | v3.8.51 | Always the newest build below |
v3.8.51-r3 | v3.8.51 | Codex client 0.162.0. Recommended |
v3.8.51-r2 | v3.8.51 | Clean rebuild 2026-10-09 on a refreshed base image with current Debian security updates. Codex client 0.159.0 |
v3.8.51 | v3.8.51 | Original build, 2026-09-30. Codex client 0.159.0 |
v3.8.50-codex159 | v3.8.50 | First lean build |
v3.8.50-web-codex156 | v3.8.50 | Last build with Chromium |
Older vX.Y.Z-web tags are kept for rollbacks. Version tags are never overwritten â a rebuild gets a new -rN suffix, so pinning a tag pins the content.
linux/amd64 only. Base image: node:26-trixie-slim. Runs as the non-root node user (UID 1000) and ships a built-in HEALTHCHECK.
REQUIRE_API_KEY=true on anything reachable from a network. The upstream default is false, which leaves /v1/* open to anyone who can reach the port.127.0.0.1:20128:20128 + Caddy / Traefik / nginx) rather than publishing the port directly.INITIAL_PASSWORD. The upstream default is CHANGEME.JWT_SECRET and API_KEY_SECRET stable across restarts â dashboard sessions are signed and stored API keys are encrypted with them.docker compose pull omniroute && docker compose up -d omniroute
Database migrations run automatically on start; a pre-migration backup is written to the data directory first.
If you bind-mount the data directory and see attempt to write a readonly database, the directory is owned by root from an older image. Fix it once:
docker run --rm -v "$PWD/data:/data" alpine chown -R 1000:1000 /data
Health endpoint: GET /api/monitoring/health.
Fixes that started here and no longer need a patch:
/chat/completions are detected and routed correctly (upstream PR #3490, since v3.8.18)Upstream is MIT-licensed.
Content type
Image
Digest
sha256:ef7ffbf67âĻ
Size
680.6 MB
Last updated
8 days ago
docker pull borodulin/omniroute