Vuncloud Blog
← Back to Dev Notes

OmniRoute from zero: a free local AI gateway for Claude, GPT, Gemini, and DeepSeek

One /v1 · your accounts · loopback only12 min read

Code on dual monitors with a keyboard in front, for a local OmniRoute AI gateway setup

Cursor, Claude Code, Codex, and Gemini CLI each keep their own base URL and secret. Once you add providers, rate limits and “this one returned 429 today” scatter across those configs. OmniRoute collapses that into one OpenAI-compatible endpoint on your machine. Clients remember http://127.0.0.1:20128/v1. Claude, GPT, Gemini, DeepSeek, and the rest of the catalog attach in the dashboard. The license is MIT. The release line this walkthrough follows is release/v3.8.53. Ports, commands, and routing rules below match that README. Provider counts move with the version.

“Free” means the gateway software has no license fee. Quota lives on the provider accounts you connect. The project publishes a /dashboard/free-tiers estimate of third-party free tiers and states that the figure is an aggregate, not a token grant from OmniRoute. Subscriptions you already pay for can use the same base URL through their own account flow. If you are comparing list prices, see the monthly coding-tool bill and the OpenRouter pricing notes. OpenRouter is a hosted router. OmniRoute is the gateway on your machine.

20128
Dashboard and /v1 share one local port
MIT
The app is free; model quota stays with the provider
auto
Routes only across connected, eligible targets

Where the gateway sits

Think of it as a socket that runs only on your machine. Upstream is still OpenAI, Anthropic, Google, DeepSeek, or another catalog provider. Downstream is any client that speaks OpenAI Chat Completions or Responses. The v3.8.53 docs cite about 375 providers and about 1,475 raw model IDs, some of them flagged for free-tier discovery. Those counts are re-audited and belong to the live dashboard catalog, not to an old screenshot.

  • You hold two keys. The provider API key or OAuth session stays inside OmniRoute. Cursor and scripts use the gateway key from Dashboard → Endpoints.
  • Model ids exist after you connect. Call /v1/models first. README examples look like openai/gpt-5.4 and glm/glm-5.2 — provider, slash, model. Use the id your list actually returns.
  • The client list is wide. The project names Claude Code, Codex, Cursor, Cline, Continue, OpenCode, Copilot, OpenClaw, and others. Anything with a custom OpenAI base URL only needs the address. omniroute run launches seven of the CLIs for you.
Quota sits with the provider

The README’s line is bring your own provider accounts. A free tier may require signup, approval, or a payment method, and it can close. Providers marked tos: avoid stay out of auto by default. Connecting the account does not flip that policy.

Install from zero: npm and Docker

You need Node.js on the machine. The short path:

npm install -g omniroute
omniroute

npm warn ERESOLVE and peer-dependency warnings are called out in the docs as safe to ignore at first. The dashboard opens at http://127.0.0.1:20128. The API is http://127.0.0.1:20128/v1. For a proxy without the dashboard, run omniroute serve --headless or set OMNIROUTE_HEADLESS=1.

npm 11 must allow install scripts

npm 11 can block package lifecycle scripts. OmniRoute’s postinstall has to run so the native runtime files are in place. The allow-list printed for 3.8.53 is:

npm install -g --allow-scripts=omniroute,keytar,onnxruntime-node,@parcel/watcher,@swc/core,protobufjs,esbuild omniroute

If npm names a different set, use that warning’s package list. Allowing scripts means those packages’ install scripts will execute — do it after you trust the source. On CI or a slow machine, OMNIROUTE_SKIP_POSTINSTALL=1 skips only the native SQLite warm-up. The binary copy step still runs.

Size Docker for a coding agent

The image name in the docs is still diegosouzapw/omniroute. :latest tracks the highest published stable SemVer. It does not track git main. Pin a version for anything you keep. The published example binds loopback:

docker run -d --name omniroute --restart unless-stopped --stop-timeout 40 \
  -e OMNIROUTE_MEMORY_MB=8192 --memory=10g \
  -p 127.0.0.1:20128:20128 -v omniroute-data:/app/data diegosouzapw/omniroute:latest

The image defaults the heap to 1024MB, enough for the dashboard and short chat. Claude Code and Codex call POST /v1/responses. The docs say those long contexts need a larger V8 heap or the process hits a fatal out-of-memory error. One coding agent is the 8192 heap and at least 10g container in the command above. Two overlapping long requests move to a 10240–12288 heap and a 12–16g container. Apple Silicon uses the image’s arm64 build. The omniroute-data volume holds secrets. Back it up and delete it as confidential data.

Hands on two laptops while connecting Claude, GPT, Gemini, and DeepSeek through one OmniRoute endpoint
The client keeps a single base URL. Provider keys stay in the gateway.

Connect Claude, GPT, Gemini, and DeepSeek

Open Providers, pick one you are allowed to use, and paste an API key or finish that provider’s account flow. OmniRoute does not open the lab accounts for you:

ProviderWhat you bringWhere it goes
OpenAI (GPT)An API key from platform.openai.comProviders → OpenAI
Anthropic (Claude)A key from console.anthropic.com, or the account flow for a Claude subscription you already pay forProviders → Anthropic / that OAuth
GeminiA key from Google AI Studio, or Gemini CLI OAuthProviders → Gemini
DeepSeekAn API key from platform.deepseek.comProviders → DeepSeek

Free tiers are a separate list. They are not synonyms for those four keys. The first-run wizard can offer “set up free providers.” It builds the list from the current no-auth catalog and creates a connection only after you confirm each one. Names that have appeared there include Pollinations, Cloudflare AI, and SiliconFlow’s DeepSeek free tier. Terms, region, and whether the tier still exists belong to that provider. An older “keyless Claude” write-up does not enter auto when the provider is marked tos: avoid. Read the Free Tiers page for that day’s eligibility before you rely on it.

Web-cookie providers such as Gemini Web also need a browser runtime. The npm package includes Playwright and not the Chromium binary. Follow the repo’s Playwright Chromium note before the first call, or the request fails in the browser layer.

One address for the IDE and the CLI

Copy the gateway key from Endpoints. Then:

Base URL: http://127.0.0.1:20128/v1
API Key:  (Dashboard → Endpoints)
Model:    auto

Confirm the model list before the IDE talks:

curl http://127.0.0.1:20128/v1/models \
  -H "Authorization: Bearer YOUR_KEY"

curl http://127.0.0.1:20128/v1/chat/completions \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"auto","messages":[{"role":"user","content":"Hello"}]}'

Cursor, Cline, Continue, and any plugin with a custom OpenAI base URL take those three lines. Clients that cannot send a custom header can use the tokenized compatibility URL, for example http://127.0.0.1:20128/vscode/YOUR_KEY/chat/completions. When the client can send a header, prefer Authorization: Bearer.

You do not have to hand-edit every CLI config. The one-command launcher injects credentials into that process. Qwen and Gemini also get a throwaway isolated home:

omniroute run claude --model auto
omniroute run codex  --model auto
omniroute run gemini --model auto
omniroute configure codex

omniroute run covers Claude Code, Codex, Aider, Goose, OpenCode, Qwen Code, and Gemini CLI. configure writes the provider and model into that tool’s own config. Documented targets include codex, claude, opencode, qwen, aider, goose, gemini, cline, continue, and kilo. --dry-run prints the environment and arguments it would use. --api-key-env NAME keeps the secret in an environment variable name so it stays out of shell history.

auto, fallback, and who stays out

auto chooses among connections that are already connected and eligible. A fresh install with nothing attached can have no eligible target. That is expected. The chosen strategy, provider, and latency come back in X-OmniRoute-Decision. Read that header before the client log.

  • Quota-aware fallback. When one connection is exhausted, scheduling can move to another that still has room. v3.8.53 adds a strategy weighted by leftover quota and tries to keep one conversation on the same connection.
  • A subscription route can fail closed. The documented subscription combo spends only the subscription quota you already pay for. If that quota is gone, the request stops. It does not spill onto a different key that bills you. Keep paid API keys and subscription keys out of one “fallback anywhere” combo.
  • tos: avoid stays out by default. A successful connect is not membership in auto. To pin one gateway key to one model, set that key’s forcedModel instead of hard-coding an upstream URL in the client.

Compression is an optional pipeline and transparent to the client. The docs describe it as composable engines. The set that actually ran is in the X-OmniRoute-Compression response header. Savings depend on the model and the request. Treat the range on the README as a project claim, not a per-call guarantee. Memory is off by default. Credential masking is opt-in.

On a Cloud Mac: loopback plus SSH

The gateway fits a Mac that stays on: listen on loopback port 20128, and SSH-forward that port to your laptop. A Cloud Mac has a fixed region and SSH, and Apple Silicon can run the official arm64 image. Do not bind the admin UI to 0.0.0.0.

ssh -N -L 20128:127.0.0.1:20128 user@your-cloud-mac

After the tunnel is up, Cursor or omniroute run on the laptop still uses http://127.0.0.1:20128/v1. It looks local. The bytes land on the cloud Mac’s loopback. Provider secrets stay in the cloud volume or the user directory, not in Git. If OpenClaw is already on that Mac, point its model base URL at the same /v1 and leave a single copy of the provider keys in the gateway.

When the dashboard needs a login, the docs offer optional OIDC. Password login remains available. Remote control also has scoped tokens (connect, contexts, tokens) under the project’s Remote Mode. Use that path. Do not publish the dashboard on a public IP to save a step.

What to check when it stalls

  1. /v1/models is empty. No provider connection succeeded, or the client used the provider key where the gateway key belongs.
  2. auto reports no route. The only connections are excluded, or today’s free tier is not eligible. Use a paid key you know works, or put a concrete id from /v1/models in the model field.
  3. The global install cannot find a native module. Reinstall with npm 11’s --allow-scripts and the package names from that warning.
  4. A coding agent dies mid-request in Docker. Raise OMNIROUTE_MEMORY_MB and --memory to the coding-agent tier. Leave the 1024MB default for the dashboard only.
  5. The first web-provider call fails. Install Playwright’s Chromium, then retry. Change the routing policy after that succeeds.
  6. The counts look stale. 375 providers and 1,475 model IDs are the v3.8.53 doc figures. After an upgrade, trust the dashboard and the README.

FAQ

Short version: the software is free and the quota is the provider’s; the address is /v1 on local port 20128; auto uses eligible connections only; coding agents in Docker need more memory; leave the port on loopback and SSH-forward it. The full Q&A is in the FAQ structured data in the page head.

Dev Journal · Gateway

Keep the gateway on loopback, SSH it to your laptop

OmniRoute · 20128 · Cloud Mac

View Cloud Mac plans
Limited offer View plans