12k
All articles

How to Run Your Own AI Model Router with 9router

Run 9router as a self-hosted AI model router: install with npm or Docker, verify models with curl, connect coding tools, and secure the OpenAI-compatible API.

OpenReplay Team
OpenReplay Team
How to Run Your Own AI Model Router with 9router

9router is an open-source, MIT-licensed routing proxy that runs on your own machine or server and puts every AI provider you connect behind one OpenAI-compatible endpoint at http://localhost:20128/v1.

If you use Claude Code in one terminal, Cline in your editor and the OpenAI SDK in a side project, you probably have three sets of keys and three base URLs, and each tool needs its own config change whenever you switch models. 9router replaces that with a single local endpoint. This guide covers installing it with npm or Docker, checking it with curl, pointing your tools at it, and locking it down before anything outside localhost can reach it.

Key Takeaways

  • 9router installs with npm install -g 9router and starts with 9router. The dashboard and the OpenAI-compatible API both listen on port 20128 by default.
  • A GET request to http://localhost:20128/v1/models lists every model and combo the router can serve, so it is the fastest way to check that a provider is connected.
  • A combo is a named, ordered list of models that you pass as the model value. The router moves to the next model when the current one runs out of quota, gets rate-limited or returns an error.
  • If INITIAL_PASSWORD is not set, the first dashboard login uses 123456. Set your own password and keep the dashboard’s “Require API key” setting on before exposing the instance beyond localhost.

What Is 9router?

9router is a self-hosted proxy that accepts OpenAI-format requests, routes them to whichever upstream provider you have configured, and translates between OpenAI, Claude and Gemini request formats as needed. The project README lists 40+ supported providers, and the CLI ships as the 9router npm package.

The main difference between 9router and OpenRouter is where the router runs. OpenRouter is a hosted service that you send requests to. 9router is software that you run yourself, and OpenRouter appears in its provider list, so you can put an OpenRouter account behind your own router.

OpenRouter9router
Where it runsVendor’s cloudYour machine or server
Who holds provider credentialsThe service, behind one OpenRouter keyYour local 9router instance
Base URL for toolshttps://openrouter.ai/api/v1http://localhost:20128/v1

Why Run a Self-Hosted Model Router

A local router gives every tool the same endpoint and keeps provider credentials in one place, so you can change models without touching tool configs or application code.

  • One endpoint. Every OpenAI-compatible client uses the same base URL.
  • Keys in one place. You add provider accounts once, in the dashboard. Each tool only needs a 9router API key.
  • Model switching by string. Changing models means changing the model value and nothing else.
  • Combos. A combo is a named, ordered list of models that you use as the model name. When the first model runs out of quota, gets rate-limited (429) or returns an error, the router tries the next one.

The usual pattern is to put your preferred model first and cheaper models after it. To compare per-token prices before you choose the fallbacks, use the LLM API cost calculator.

How to Install and Run 9router

9router installs as a global npm CLI with npm install -g 9router and starts with the 9router command. The server listens on port 20128.

npm install -g 9router
9router
# Dashboard: http://localhost:20128
# API:       http://localhost:20128/v1

If you don’t want a global install, npx 9router runs it once.

To run it in Docker, use the official decolua/9router image, which is also published at ghcr.io/decolua/9router:

docker run -d --name 9router \
  -p 20128:20128 \
  -v "$HOME/.9router:/app/data" \
  -e DATA_DIR=/app/data \
  -e INITIAL_PASSWORD='change-me' \
  decolua/9router:latest

The volume mount keeps the SQLite database (/app/data/db/data.sqlite inside the container) when the container restarts. New releases come out often and the latest tag moves with them, so pin a specific version tag if you need reproducible deploys.

After 9router starts, finish setup in the dashboard:

  1. Open http://localhost:20128 and log in to the dashboard.
  2. Add at least one provider account.
  3. Create an API key for your tools.

Verify the Router with curl

The quickest way to verify that 9router is working is a GET request to /v1/models, sent before you configure any tool. The response is a JSON list of every model and combo the router can serve, in the standard OpenAI list format.

curl http://localhost:20128/v1/models

The model list answers without a key. Chat requests are different: the dashboard’s “Require API key” setting is on by default, so they need a key from the dashboard. Sending the key with the model list request is a good habit too, because a key that is limited to certain models only sees those models:

curl http://localhost:20128/v1/models \
  -H "Authorization: Bearer $NINE_ROUTER_API_KEY"

If a model ID from your provider shows up in the list, routing works. If the list is empty, the provider is not connected yet.

Point Your Tools at 9router

Any client that accepts a custom OpenAI base URL can use 9router. Set the base URL to http://localhost:20128/v1 and supply an API key created in the dashboard.

OpenAI SDK

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "http://localhost:20128/v1",
  apiKey: process.env.NINE_ROUTER_API_KEY, // created in the 9router dashboard
});

const res = await client.chat.completions.create({
  model: "<an id or combo name from /v1/models>",
  messages: [{ role: "user", content: "Say hello" }],
});
console.log(res.choices[0].message.content);

To switch to another model or a combo, change the model string. Nothing else in the code changes.

Coding Agents

In Cline, choose OpenAI Compatible as the API provider and fill in three values: the base URL http://localhost:20128/v1, your dashboard API key, and a model ID copied from /v1/models. Terminal agents that let you bring your own provider, such as OpenCode, take the same three values.

Pi with pi-9router-ext

The pi-9router-ext extension connects the Pi coding agent to 9router through two environment variables:

pi install npm:pi-9router-ext
NINE_ROUTER_BASE_URL=http://localhost:20128 NINE_ROUTER_API_KEY=<key> pi
# inside Pi:
/9router-models

When it starts, the extension reads chat models from /v1/models. In the 0.2.4 release, it also queries /v1/models/web to find 9router’s web search and fetch routes. Run /9router-models inside Pi to see what it found.

How Do You Secure 9router Before Exposing It?

To secure 9router before another machine can reach it, set a dashboard password and the JWT and API key secrets, and leave “Require API key” switched on. The defaults are fine on localhost, but not beyond it. If INITIAL_PASSWORD is not set, the first dashboard login uses 123456 until a password is saved. Set these values from the official .env.example before you open a port or deploy to a public host:

INITIAL_PASSWORD=<long-random-string>   # first login otherwise uses 123456
JWT_SECRET=<long-random-string>         # listed under "Required" in .env.example
API_KEY_SECRET=<long-random-string>     # the example default is publicly known
AUTH_COOKIE_SECURE=true                 # set when serving behind an HTTPS reverse proxy

The API key check itself is a dashboard setting. Open the Endpoint page and confirm that Require API key is on, so requests without a valid key are rejected. It is on by default, and the dashboard shows a warning if the endpoint is reachable from a remote host without it.

Only set AUTH_COOKIE_SECURE=true when TLS terminates in front of 9router. Over plain HTTP, the browser will not send the auth cookie back.

Conclusion

A self-hosted router like 9router gives all your tools one endpoint and one set of credentials, and changing models only means changing the model string. Install it, check that /v1/models lists your provider’s models, then point one tool at http://localhost:20128/v1. Set the password and the secrets, and keep “Require API key” on, before the router leaves localhost.

FAQs

How do I run 9router on a port other than 20128?

Start the npm CLI with 9router --port 8080 to use a custom port. When running from source, set the PORT environment variable, together with NEXT_PUBLIC_BASE_URL pointing at the same port. In Docker, change the host side of the port mapping, for example -p 8080:20128. Every tool then needs the new base URL, such as http://localhost:8080/v1.

Where does 9router store its configuration and data?

9router stores its data in the directory set by DATA_DIR, which defaults to ~/.9router, and keeps its SQLite database at db/data.sqlite inside that directory. If JWT_SECRET is not set, an auto-generated signing secret is stored there too, at ~/.9router/jwt-secret. The official Docker image sets DATA_DIR to /app/data, so mounting a volume at /app/data persists everything.

How do I point tools on another machine at a remote 9router server?

Run npx 9router connect http://server-host:20128 on the client machine. The command starts no local server. It logs in with the dashboard password, reuses or creates an API key named cli- followed by the hostname, and writes each selected tool's config. It backs up each original config once with a .bak-9router suffix. Use --tools claude,codex to choose tools up front, and --reset to undo.

Can 9router use more than one account for the same provider?

Yes. 9router supports multiple accounts per provider and spreads requests across them using round-robin or priority-based routing. When one account hits its quota, the router switches to the next account. This is separate from combos: account rotation keeps the same model and changes the credentials behind it, while a combo moves to a different model.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.