Sign inSign up

borodulin/omniroute

By borodulin

â€ĸUpdated 8 days ago

OmniRoute AI router — lean image with failover and Codex reliability fixes

Image
Networking
Machine learning & AI
0

2.7K

borodulin/omniroute repository overview

⁠borodulin/omniroute

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.

⁠Quick start

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.

⁠Docker Compose
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⁠.

⁠What's different from upstream

PatchWhy you'd want it
âąī¸Cooldown is no longer reported as quota exhaustionA 5-second blip on one account no longer takes a whole pool offline for hours
🧩Codex client version 0.162.0Newer Codex models stop failing with "requires a newer version of Codex"
đŸĒļLean image, no ChromiumSmaller pull, smaller attack surface
â âąī¸ Cooldown vs. quota

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.

⁠🧩 Codex client version

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.

⁠đŸĒļ Lean image

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.

⁠Tags

TagUpstreamNotes
latestv3.8.51Always the newest build below
v3.8.51-r3v3.8.51Codex client 0.162.0. Recommended
v3.8.51-r2v3.8.51Clean rebuild 2026-10-09 on a refreshed base image with current Debian security updates. Codex client 0.159.0
v3.8.51v3.8.51Original build, 2026-09-30. Codex client 0.159.0
v3.8.50-codex159v3.8.50First lean build
v3.8.50-web-codex156v3.8.50Last 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.

⁠Before you expose it

  • Set 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.
  • Bind to loopback and put a reverse proxy in front (127.0.0.1:20128:20128 + Caddy / Traefik / nginx) rather than publishing the port directly.
  • Change INITIAL_PASSWORD. The upstream default is CHANGEME.
  • Keep JWT_SECRET and API_KEY_SECRET stable across restarts — dashboard sessions are signed and stored API keys are encrypted with them.

⁠Upgrading

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.

⁠Already upstream

Fixes that started here and no longer need a patch:

  • Cursor compatibility — Responses-API-shaped bodies sent to /chat/completions are detected and routed correctly (upstream PR #3490, since v3.8.18)
  • TheOldLLM server-side request token (PR #3491, since v3.8.18)
  • Browser pool proxy taken from the database (PR #3492, since v3.8.18)
  • Proxy health probes deactivating working proxies — fixed upstream in v3.8.46
  • GPT-6 Astra in the Codex provider — upstream since v3.8.51

Upstream is MIT-licensed.

Tag summary

Content type

Image

Digest

sha256:ef7ffbf67â€Ļ

Size

680.6 MB

Last updated

8 days ago

docker pull borodulin/omniroute