Enterprise-grade AI routing gateway ā 40+ LLM providers, PostgreSQL 17, OpenAI-compatible API
1.5K
docker pull rickicode/axonrouter:latest
Every release is published with an immutable sha-<short> tag, a semver tag on
tagged releases, and latest tracking the release branch.
ghcr.io/rmz17x/axonrouter carries the identical image as a mirror.
Connect all your AI coding agents to 40+ LLM providers with pure PostgreSQL 17 concurrency, dedicated Hono API gateway, and zero file-lock bottlenecks.
ā” AxonRouter vs 9Routerā ⢠š Quick Start (Docker)ā ⢠š” Featuresā ⢠š ļø Supported Toolsā ⢠š Providersā ⢠š Setupā
AxonRouter is an enterprise-grade, high-concurrency fork of decolua/9router (9Router)ā . While 9Router targets local single-user developer setups using embedded SQLite (data.sqlite), AxonRouter is purpose-built for heavy multi-agent concurrency, containerized environments, and production deployments.
Fork Lineage:
decolua/9router(local SQLite) ārickicode/9router-Xā AxonRouter (Pure PostgreSQL 17 SSOT + Dedicated Hono Gateway cluster).
| Architectural Component | 9Router Original | AxonRouter (Enterprise Edition) |
|---|---|---|
| Database Engine | SQLite file-based (better-sqlite3 / sql.js) ā locks on parallel writes | Pure PostgreSQL 17 ā connection pooling via postgres.js, ACID transactions, zero file locks |
| API Gateway Layer | Integrated inside Next.js server event loop | Dedicated Hono API Gateway (gateway/server.js) ā multi-worker Node cluster on port 3778 |
| Cache & Cooldowns | In-memory Map (unindexed, wipes on reload) | In-Memory Speed Layer (memoryStore.js) ā TTL keys, owner-token mutexes, zero hot-path DB tax |
| Usage Logging | Monolithic unpartitioned tables | Native Monthly Range Partitioning (usage_history, request_details) with auto-rolling tables |
| Failover & Recovery | Basic sequential fallback | Combo Fusion, Difficulty Scoring & Circuit Breaker ā negative-availability memoization |
| Client Error Isolation | Client 4xx errors can lock provider accounts | Strict 4xx Error Isolation ā client errors (400, 404, 413, 499) never freeze upstream accounts |
| Deployment Model | Local Single-User CLI / Web | Docker Compose Production Stack (Web Dashboard 3777 + Hono Gateway 3778 + PostgreSQL 17) |
The public LLM API (/v1/*) runs in a dedicated Hono gateway process (axonrouter-api, port 3778), fully separated from the dashboard (axonrouter-web, port 3777). Heavy streaming traffic from dozens of concurrent coding agents never contends with the dashboard's event loop.
/v1/chat/completions, /v1/messages, /v1/models, /v1/embeddings, audio/video endpoints.GATEWAY_WORKERS=4) across CPU cores.@/... module alias resolver (gateway/alias-resolver.mjs, registered at boot) with no bundler/webpack pass.3778 for low-latency streamingIncoming Request (Claude Code, Cursor, Codex, OpenClaw, Cline...)
ā
ā¼
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Port 3778: Dedicated Hono API Gateway (Cluster Mode) ā
ā or Port 3777: Standalone Hono server (Vite SPA build) ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā
ā¼
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā src/sse/services/auth.js ā
ā ⢠Provider / combo credential resolution via mutex locks ā
ā ⢠Negative-availability pre-check (fast-fail on exhaustion)ā
ā ⢠LKG (Last-Known-Good) route memory ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā
ā¼
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā open-sse/handlers/chatCore.js ā
ā ⢠Format detection (OpenAI / Claude / Gemini / Kiro) ā
ā ⢠Bidirectional wire format normalization & translation ā
ā ⢠Upstream dispatch, retry backoff & stream forwarding ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā ā
ā¼ ā¼
āāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā
ā PostgreSQL 17 ā ā In-Memory Speed ā
ā (Partitioned DB) ā ā Layer (TTL Maps) ā
āāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā
AxonRouter ships as a containerized stack: Docker is required (the installer will offer to install it for you if missing). Running without Docker is supported only for manual local development ā see Local Node.js Developmentā .
The production stack orchestrates:
http://localhost:3778http://localhost:3777valkey/valkey:8-alpine image ā realtime speed layer, no persistence)5432 (private to Docker network)Everything lives in one compose file (docker-compose.yml). Three switches pick the topology:
| What | Command |
|---|---|
| Split stack (default) | docker compose up -d |
| Built-in PostgreSQL 17 | COMPOSE_PROFILES=builtin-db docker compose up -d |
| Combined ā API + web in ONE container | docker compose --profile combined up -d axonrouter |
The combined container runs both servers under one supervisor (docker/entrypoint-combined.mjs): a dead web server fails the container so Docker restarts it, a crashed gateway is restarted within a budget, and SIGTERM reaches both.
All published GHCR images are multi-arch (linux/amd64 + linux/arm64) ā the same compose stack works on x86 servers and ARM boxes (Raspberry Pi, Graviton, Ampere).
Every push to main / release (and every v* tag) rebuilds the images and pushes them to GitHub Container Registry:
| Image | What it runs | Ports |
|---|---|---|
rickicode/axonrouter-web:latest | Web Dashboard + Control Plane | 3777 |
rickicode/axonrouter-api:latest | Standalone Hono API Gateway | 3778 |
rickicode/axonrouter:latest | Combined ā both in one container | 3777, 3778 |
Two pipelines publish the same three images, so the registry is correct no matter which remote you push to: GitLab CI (.gitlab-ci.yml, the source of truth) and GitHub Actions (.github/workflows/docker-publish.yml, the mirror). See DOCKER.mdā for the required CI variables and the tag policy.
The installer does everything interactively without needing to clone the git repository:
Install Docker now? (yes/no) and installs it automatically via get.docker.com.docker-compose.yml and .env.example directly from GitHub into ~/AxonRouter. Zero git clone required..env (JWT_SECRET, API_KEY_SECRET, ENCRYPTION_KEY, POSTGRES_PASSWORD, INITIAL_PASSWORD) ā press Enter to accept auto-generated values.Start AxonRouter now? (yes/no) and launches the stack with docker compose up -d using pre-built multi-arch GHCR images.curl -sSL https://raw.githubusercontent.com/rickicode/AxonRouter/main/scripts/install.sh | sh
docker-compose.yml location)The default install path is ~/AxonRouter (your home directory) ā wherever you run the command. Pass an explicit path as the first argument to override it:
| Environment | Command | Resulting compose file |
|---|---|---|
| Default (any OS user) | run the installer | ~/AxonRouter/docker-compose.yml |
| Custom location | curl ⦠| sh -s -- /your/path | /your/path/docker-compose.yml |
Default example (installs to ~/AxonRouter):
curl -sSL https://raw.githubusercontent.com/rickicode/AxonRouter/main/scripts/install.sh | sh
Native PowerShell installer (recommended ā installs Docker Desktop via winget if missing, generates secrets, starts the stack):
irm https://raw.githubusercontent.com/rickicode/AxonRouter/main/scripts/install.ps1 | iex
C:\Users\<you>\AxonRouter\docker-compose.yml& ([scriptblock]::Create((irm https://raw.githubusercontent.com/rickicode/AxonRouter/main/scripts/install.ps1))) -Path D:\AxonRouter\\wsl$\<distro>\home\<user>\AxonRouter\docker-compose.yml| Port | Service | Deskripsi & Contoh URL |
|---|---|---|
3777 | Web Dashboard & Control Plane | http://localhost:3777 (manajemen router, provider API keys, proxy pool, metrics) |
3778 | High-Throughput Hono API Gateway (/v1) | Endpoint cepat multi-worker untuk AI agent (Cursor, Claude Code, Cline): ⢠http://localhost:3778/v1/chat/completions (OpenAI format)⢠http://localhost:3778/v1/messages (Anthropic format)⢠http://localhost:3778/v1/models (Daftar model aktif) |
Base URL Klien: Untuk menghubungkan Cursor, Claude Code, Cline, atau SDK OpenAI, arahkan Base URL ke:
http://localhost:3778/v1
Jika Anda lupa password dashboard, Anda bisa meresetnya kapan saja dengan perintah satu baris:
# Reset ke default (12345677):
curl -sSL https://raw.githubusercontent.com/rickicode/AxonRouter/main/scripts/reset-password.sh | sh
# Atau reset ke password baru pilihan Anda:
curl -sSL https://raw.githubusercontent.com/rickicode/AxonRouter/main/scripts/reset-password.sh | sh -s -- "password_baru_anda"
irm https://raw.githubusercontent.com/rickicode/AxonRouter/main/scripts/reset-password.ps1 | iex
All compose commands run from the install directory:
cd ~/AxonRouter # default install location
docker compose up -d # start
docker compose ps # status
docker compose logs -f # logs
docker compose down # stop
1. Install Docker (skip if the installer already offered and you accepted):
curl -sSL https://get.docker.com | sh
2. One-command install (recommended):
sh install.sh
The installer ships inside the image: it pulls rickicode/axonrouter:latest, extracts docker-compose.yml + .env.example, generates secrets, and starts the stack. No git clone needed.
Configure .env with your secure secrets (e.g. via openssl rand -hex 32):
JWT_SECRET ā Session cookie signing keyINITIAL_PASSWORD ā Initial dashboard admin passwordAPI_KEY_SECRET ā HMAC secret for gateway tokensPOSTGRES_PASSWORD ā PostgreSQL database passwordDATABASE_URL ā PostgreSQL connection string3. Launch Container Stack:
# Run production stack using GHCR images:
docker compose up -d
# Or build locally from source (same compose file):
docker compose build && docker compose up -d
# Or run API + web in ONE container:
docker compose --profile combined up -d axonrouter
http://localhost:3777/dashboardhttp://localhost:3778/v1AxonRouter intentionally separates the web dashboard and the public LLM API into two independent processes:
| Aspect | Dashboard (Port 3777) | API Gateway (Port 3778) |
|---|---|---|
| Process | Hono server serving the Vite SPA (dist/) | Standalone Hono multi-worker cluster |
| Entry | server.js ā src/server/webServer.mjs | gateway/server.js |
| Purpose | Management UI, settings, live observability | High-throughput /v1/* inference routing |
| Concurrency | Single Node event loop | Node cluster across CPU cores (GATEWAY_WORKERS) |
| Failure isolation | Dashboard restart never drops live agent streams | Gateway crash never kills the dashboard |
Advantages of this split:
Local Docker networks and agentic workspaces can reach the gateway via container DNS:
http://axonrouter-api:3778/v1, or from WSL/VM hosts viahttp://host.docker.internal:3778/v1.
AxonRouter supports direct credential rotation and wire translation across 40+ providers:
docker compose up -d
Mode manual ā hanya untuk pengembangan lokal. Produksi berjalan dengan Docker saja. Membutuhkan Node.js 22+ dan PostgreSQL 17 yang sudah berjalan:
# 1. Install dependencies
npm install
# 2. Configure environment
cp .env.example .env
# Set DATABASE_URL=postgres://axonrouter:password123@localhost:5432/axonrouter
# 3. Start development servers
npm run server # Web + API server on port 3777 (run `npm run build` first)
npm run dev # Vite dev UI on port 5173, proxying /api and /v1 to :3777
node gateway/server.js # Standalone Hono Gateway on port 3778
AxonRouter is open-source software licensed under the MIT Licenseā .
open-sse/providers/registry/freeai.js). api.free.ai is registered as an official provider (id: freeai, aliases: ["free"]) with a built-in transport (https://api.free.ai/v1/chat/completions, validate https://api.free.ai/v1/models) and the 7 verified free chat models as a seed ā qwen7b, qwen3-8b, qwen-coder, qwen3-coder, deepseek-r1, deepseek-r1-7b, mistral (passthroughModels accepts the rest). Connections are now added by API key only, no hand-entered custom baseUrl. The live /v1/models catalogue uses a non-standard {models:[...]} shape, so there is no modelsFetcher. aliases: ["free"] preserves the legacy free/<model> prefix so existing combos keep routing.openai-compatible-chat-freeai custom-URL connections were repointed to provider = freeai (custom baseUrl/nodeName removed); the legacy free/ prefix and any freeai/ references resolve to the same connections.Retry-After fixed (open-sse/utils/error.js, open-sse/config/errorConfig.js). AxonRouter relayed an upstream retryAfter hint verbatim into its own Retry-After header. A broker 402 like broker GNK reserve exhausted carrying retryAfter: 1800 (30 min) reached clients whose own retry cap is lower (OpenAI Node SDK default maxDelayMs = 90s), which then threw Provider requested 1800000ms wait, exceeds retry.maxDelayMs (90000ms) instead of backing off. unavailableResponse now clamps the relayed Retry-After to MAX_RELAY_RETRY_AFTER_S = 90, so the hint stays within typical client retry caps and never crashes the caller ā the upstream's real reset is still tracked internally for AxonRouter's own cooldowns.reserve exhausted classified as capacity, not a payment fault (open-sse/config/errorConfig.js). A broker-side reserve outage (broker GNK reserve exhausted, etc.) is now matched by a text rule (reserve exhausted) ā modelWide 15-min cooldown, shouldFallback: true, lockAll: false. Previously it fell through to the bare status: 402 billing rule; now accounts are never locked (every account on the provider shares the same broker reserve, so locking is wrong) and the model is parked provider-wide so the fleet stops re-hitting the dead broker.exhausted (src/sse/handlers/chat.js, src/domain/accountExhaustionProviders.js). The chat handler treated ANY 402 as account-wide credit death via markAccountExhaustedFromCredits, and the credit-quota regex matched the word "exhaust" ā so a broker GNK reserve exhausted 402 marked every gonka account exhausted in lockstep (they share one broker reserve), making "many accounts" useless until each was manually reset. A new isSharedReserveExhaustion guard skips the terminal mark; the 402 now rides a transient model/broker cooldown bounded by the broker's own retryAfter hint instead.Content type
Image
Digest
sha256:daeb4c28bā¦
Size
109.4 MB
Last updated
about 16 hours ago
docker pull rickicode/axonrouter-api