durindoor
Health Uyari
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 7 GitHub stars
Code Gecti
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Gecti
- Permissions — No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
DurinDoor is a self-hosted AI gateway that gives developer tools and applications one stable API in front of many upstream AI providers.
Add provider credentials once in a self-hosted dashboard, then point any OpenAI-compatible tool at a single local endpoint with unified usage tracking, provider combos, and request logs.
🗺️ Explore
- Why DurinDoor?
- How it works
- Quick start
- Connect your tools
- What DurinDoor handles
- API surface
- Architecture
- Security and operations
- Documentation
- Contributing
- Acknowledgments
🚪 Why DurinDoor?
DurinDoor is a self-hosted AI gateway that sits between your tools and your providers. It keeps provider credentials on your own machine and exposes one local API every OpenAI-compatible client can speak.
- One local endpoint — Configure tools once against
http://localhost:20128/v1instead of wiring each app to a different provider. - Reusable provider connections — Add an OAuth login, API key, cookie, or compatible endpoint once; every tool shares it.
- Account and combo fallback — Chain multiple connections for resilience, or stack models behind one stable name so a failed attempt retries the next option.
- Format translation — Send OpenAI-shaped requests and have them translated for Claude, Gemini, Kiro, Cursor, Ollama, Vertex, and other upstream formats.
- Usage visibility — Inspect provider, model, tokens, cost estimates, latency, and fallback outcome per request in the dashboard.
- Self-hosted state — Storage, credentials, and logs live in your
DATA_DIR; you control where it runs and who can reach it.
DurinDoor is a fork of 9router. Existing installations can keep their data, keys, and headers.
🧭 How it works
flowchart LR
Client[OpenAI-compatible tool] -->|/v1 request + DurinDoor key| Route[/Compatibility API/]
Route --> Handler[Auth + model/alias/combo resolution]
Handler --> Core[Routing and translation core]
Core -->|translate request| Provider[Upstream provider]
Provider -->|stream or JSON| Core
Core -->|translate response| Client
Core --> DB[(SQLite usage + logs)]
- A client sends a request to
/v1with a DurinDoor API key and a model string (provider model, alias, or combo name). - DurinDoor validates the key, resolves the model, and selects an available provider connection.
- If the client and provider speak different formats, the request and response are translated; the upstream call is made with stored credentials.
- Usage, latency, and outcome are written to local SQLite, and the response streams back to the client in the client's format.
The model field accepts several shapes, resolved before any upstream call:
| Model string | Example | Resolves to |
|---|---|---|
| Provider model | openai/gpt-4.1 |
A provider ID plus an upstream model. |
| Provider alias | cc/claude-sonnet |
A registry alias for an upstream model. |
| Compatible node | openai-compatible-lab/model-name |
A custom provider node plus its model. |
| Model alias | daily-coder |
A user-defined alias mapped to another model. |
| Combo name | coding-default |
An ordered fallback chain of models. |
Credential selection avoids accounts that are temporarily locked, expired, or excluded by the current fallback attempt, and refreshes OAuth tokens when the upstream supports refresh.
See Architecture and Smart Routing for the internal request lifecycle and failure handling.
⚡ Quick start
Requirements: Node.js 20.20.2 and npm 10.8.2 (also bundled in the Docker image).
Install the CLI globally and start the gateway:
npm install -g durindoor
durindoor
On first run DurinDoor creates DATA_DIR and initializes the database. Default surfaces:
| Surface | URL |
|---|---|
| Dashboard | http://localhost:20128/dashboard |
| API base | http://localhost:20128/v1 |
| Health check | http://localhost:20128/api/health |
- Open the dashboard and sign in with the
INITIAL_PASSWORDyou set (or the local default). Change it before exposing the instance. - Add a provider connection under Providers (OAuth login, API key, compatible endpoint, or local provider).
- Create a DurinDoor API key under API Keys. New keys have the shape
sk-<machine>-<key>-<crc>; oldersk-*keys remain supported. The full key is shown once — store it. - Send a request:
curl http://localhost:20128/v1/chat/completions \
-H "Authorization: Bearer YOUR_DURINDOOR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "MODEL_ID",
"messages": [
{"role": "user", "content": "Reply with one short sentence."}
],
"max_tokens": 32
}'
Replace MODEL_ID with a model ID, alias, or combo name from your dashboard.
Other ways to run DurinDoor
Run without installing (npx, evaluation only)npx durindoor
Use npx for quick evaluation. For daily use, install globally or run from source.
git clone https://github.com/bloodf/durindoor.git
cd durindoor
npm install --no-audit --no-fund
npm run build
npm start
For development, npm run dev serves on port 20127 (production uses 20128).
Pin a version tag for production; do not rely on latest for stability:
docker run -d \
--name durindoor \
-p 127.0.0.1:20128:20128 \
-v "$HOME/.durindoor:/app/data" \
-e DATA_DIR=/app/data \
-e JWT_SECRET="change-me" \
-e INITIAL_PASSWORD="change-me" \
ghcr.io/bloodf/durindoor:3.9.0
See Cloud Deployment for the full production compose setup, and Upgrading before moving between versions.
See Installation for the full configuration reference, data paths, and environment variables.
More in the Quick Start and Installation guides.
🧩 Connect your tools
Point any OpenAI-compatible client at one base URL with your DurinDoor key:
Base URL: http://localhost:20128/v1
API key: your DurinDoor API key
Model: a model ID, alias, or combo name from the dashboard
Integration guides for popular tools:
- Claude Code
- OpenAI Codex
- Cursor
- Cline
- Roo Code
- Continue
- Ollama + Claude Code
- Other OpenAI-compatible tools
Claude-compatible clients may expect ANTHROPIC_BASE_URL; see the per-tool guide.
From Python with the OpenAI SDK:
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:20128/v1",
api_key="YOUR_DURINDOOR_API_KEY",
)
resp = client.chat.completions.create(
model="MODEL_ID",
messages=[{"role": "user", "content": "Reply with one short sentence."}],
max_tokens=32,
)
print(resp.choices[0].message.content)
For more SDK examples and the dashboard workflow, see the Usage Guide.
✨ What DurinDoor handles
Compatible API families
| Family | Notes |
|---|---|
| Chat Completions | OpenAI-compatible /v1/chat/completions, the common entry point for most tools. |
| Responses | /v1/responses with compatibility rewrites for selected clients. |
| Claude Messages | /v1/messages for Claude-compatible clients and translation testing. |
| Models | /v1/models lists models available through configured providers, aliases, and nodes; /v1/models/{provider}/{model} returns one exact configured model. |
| Embeddings | /v1/embeddings routed to embedding-capable providers. |
| Images | /v1/images/generations and /v1/images/edits. Provider-dependent. |
| Audio | /v1/audio/speech, /v1/audio/transcriptions, /v1/audio/translations, /v1/audio/voices. Provider-dependent. |
| Web search / fetch | /v1/search and /v1/web/fetch through dedicated search providers. |
| Realtime | OpenAI-Realtime-shaped /v1/realtime WebSocket; text conversations only. |
| Rerank / moderation | /v1/rerank and /v1/moderations with providers that support them. |
| Token counting | /v1/messages/count_tokens. Provider support varies. |
A route existing does not mean every provider supports it; modalities are provider-dependent.
Routing, combos, and visibility
| Capability | What it does |
|---|---|
| Smart routing | Resolves model strings, selects an available connection, translates formats, and records usage. |
| Account fallback | Retries another active connection for the same provider and model. |
| Combos | Chain models behind one stable name; a failed member falls through to the next. |
| Usage and quota tracking | Request logs, cost estimates, provider limits, and reset windows in the dashboard. |
| Compression | Opt-in prompt compression before upstream dispatch; fail-open by design. |
| MCP Gateway | Expose multiple MCP servers behind managed keys and routes. |
| Realtime | Text WebSocket sessions in the OpenAI Realtime shape. |
Common combo strategies:
| Strategy | Typical order |
|---|---|
| Reliability first | Most reliable paid provider, then secondary provider, then local fallback. |
| Cost control | Subscription or local model, then low-cost API, then premium model. |
| Latency first | Fast local or small model, then balanced model, then larger model. |
| Capability first | Strongest model, then compatible backup, then simpler fallback. |
A combo member can still use multiple accounts for the same provider before falling through to the next member. Use request logs to confirm which model served each request.
Providers and local/custom endpoints
| Connection type | Credential shape |
|---|---|
| OAuth | Browser login, device code, or OAuth callback. |
| API key | Provider API key or token. |
| Compatible endpoint | OpenAI-compatible or Anthropic-compatible URL. |
| Local provider | Local URL, no remote account. |
See Provider Connections, Provider Nodes and Custom Providers, and Free and Local Providers. All modality support is provider-dependent.
🔌 API surface
Base URL: http://localhost:20128/v1 (use your HTTPS origin for remote deployments).
Authorization: Bearer YOUR_DURINDOOR_API_KEY
Use DurinDoor API keys generated in the dashboard; do not send upstream provider keys to client-facing routes.
| Endpoint | Method | Purpose |
|---|---|---|
/v1/chat/completions |
POST | OpenAI-compatible chat (most tools). |
/v1/responses |
POST | Responses API with compatibility rewrites. |
/v1/messages |
POST | Claude Messages for Claude-compatible clients. |
/v1/messages/count_tokens |
POST | Token counting (provider-dependent). |
/v1/models and /v1/models/{provider}/{model} |
GET | Available models or one exact configured provider-prefixed model. |
/v1/embeddings |
POST | Embeddings. |
/v1/images/generations |
POST | Text-to-image. |
/v1/images/edits |
POST | Image edits. |
/v1/audio/speech |
POST | Text-to-speech. |
/v1/audio/transcriptions |
POST | Transcription. |
/v1/audio/translations |
POST | Translation. |
/v1/audio/voices |
GET | Available voices. |
/v1/search |
POST | Web search. |
/v1/web/fetch |
POST | Web fetch. |
/v1/realtime |
WS | Realtime text WebSocket. |
/v1/rerank |
POST | Rerank (provider-dependent). |
/v1/moderations |
POST | Moderation (provider-dependent). |
/api/health |
GET | Health check (no provider setup needed). |
Full details, per-key model and lifetime policy fields, and compatibility notes are in the API Reference.
🏗️ Architecture
DurinDoor is a Next.js gateway with a dashboard and an OpenAI-compatible compatibility API.
| Area | Responsibility |
|---|---|
| Dashboard routes | Browser UI for providers, combos, usage, endpoint setup, tools, tunnels, MITM, MCP, and settings. |
| Compatibility API | OpenAI-compatible and related client-facing routes under /v1 and /v1beta. |
Routing layer (src/sse) |
Request entry, auth, model/combo resolution, and service dispatch. |
Core engine (open-sse) |
Provider execution, translation, streaming, fallback, token refresh, and usage extraction. |
open-sse translators |
Convert between OpenAI, Anthropic Claude, Gemini, Responses, Kiro, Cursor, CommandCode, Ollama, Vertex, and other formats. |
| SQLite persistence | Driver, migrations, repositories, and backups under DATA_DIR. |
Two fallback layers operate inside the routing core: account fallback picks another active connection for the same provider and model, and combo fallback moves to the next model in an ordered combo chain. The OpenAI-pivot translation layer keeps client and provider formats separate so one client can reach many upstreams.
See Architecture for the request lifecycle, routing internals, and extension points.
🔐 Security and operations
DurinDoor stores provider credentials and routes model traffic — treat it as sensitive infrastructure.
- Prefer localhost-only binding. The CLI binds
0.0.0.0by default, so rundurindoor --host 127.0.0.1for local-only use. Source runs default to127.0.0.1whenHOSTNAMEis unset. Docker setsHOSTNAME=0.0.0.0inside the container; keep it private with host-side mapping such as-p 127.0.0.1:20128:20128. Do not expose the dashboard publicly with only the default password. - Separate DurinDoor keys from upstream credentials. Client tools use DurinDoor API keys; upstream provider keys, OAuth tokens, and cookies stay in
DATA_DIRand are never sent to client-facing routes. - Set explicit production secrets. Define
JWT_SECRET,API_KEY_SECRET, and a strongINITIAL_PASSWORDbefore any remote exposure. - Use HTTPS and restrict dashboard access. Reverse proxy with auth, VPN, firewall, or trusted-network allowlist; set
AUTH_COOKIE_SECURE=truebehind HTTPS. - Back up
DATA_DIR. Protectdb/data.sqlite,db/backups/,auth/, andmitm/as secrets. - Review the security docs before exposure. See Security and Production Hardening, Startup and Runtime Operations, and Environment Variables.
- Keep request logging off by default. Detailed logs may include prompts, responses, and file names; set
ENABLE_REQUEST_LOGS=falseunless actively debugging, with a defined retention and access policy. - Treat tunnels as exposure. HTTPS tunnels make the gateway reachable from another network — keep dashboard auth on, prefer dedicated keys, and disable tunnels when unused.
Compatibility notes
DurinDoor is a fork of 9router. These compatibility names remain supported so prior installations can migrate without losing data:
- Storage path
~/.9router(override withDATA_DIR). - Legacy API keys in the
sk-<8 hex>shape alongside currentsk-<machine>-<key>-<crc>keys. - Internal headers prefixed
X-9Router-and theirX-DurinDoor-equivalents.
📚 Documentation
The canonical documentation is Markdown in this repository; GitHub-rendered Markdown is the source of truth.
- Index — docs/README.md
- Getting started
- Providers — connections, custom nodes, free and local
- Features — Smart Routing, Combos, Usage and Quota Tracking, Compression, MCP Gateway, Realtime
- Reference — API Reference, Environment Variables, Architecture
- Operations — Security, Startup, Troubleshooting, FAQ
- Community and project — Security Policy, Contributing, Code of Conduct, Changelog, License, Issues, Discussions
🤝 Contributing
Contributions are welcome. Read Contributing, Local Development, and Architecture before opening a pull request, and follow the pull request template.
🎨 Durin DS design system preview
A warm "Moria stone" / "Parchment" design language for the next DurinDoor
dashboard, previewed in Storybook before any production wiring. The work
lives entirely in src/shared/ui/ (tokens, 25 primitives, shell, page
mocks) so upstream 9router PRs remain mechanically portable.
- Full reference: docs/development/durin-ds.md
- Quick tour: src/shared/ui/README.md
Run the preview:
cd .omc/wt-durin-ds
npm install --no-audit --no-fund
npm run storybook # http://localhost:6006
Use the Theme toolbar (sun/moon icon) to flip between **Dark — Moria
Acknowledgments
DurinDoor is a fork of 9router, created by decolua. This project builds on that foundation with a new identity, enhanced features, and an emphasis on keeping the doors of your AI stack open. Upstream documentation and branding remain the property of their respective authors and are not presented as DurinDoor's source of truth.
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi