A high-performance, multi-provider LLM proxy in a single Rust binary — with an embedded React console, multi-tenant auth, and the same engine compiled to run natively, in Docker, or on the serverless edge (WebAssembly).
English · 简体中文
- 🪪 License: AGPL-3.0-or-later · 🐳 Image:
ghcr.io/leenhawk/gproxy - 🦀 Targets: native binary · Docker · edge wasm (Cloudflare / Deno / Netlify / Supabase / EdgeOne / Appwrite)
- 🖥️ Console: built in, served at
/console
GPROXY exposes a unified OpenAI / Anthropic / Gemini-compatible HTTP surface on top of many upstream LLM providers, and adds everything you need to run it as a shared service:
- Multi-provider routing — OpenAI, Anthropic, Gemini/Vertex, DeepSeek, Groq, OpenRouter, NVIDIA, Vercel AI Gateway, Claude Code, Codex, and any OpenAI-compatible custom endpoint.
- Two routing modes — aggregated
/v1/...(provider in the model name) and scoped/{provider}/v1/...(provider in the URL). - Cross-protocol translation — an OpenAI client can talk to a Claude upstream (and vice-versa); same-dialect requests take a minimal-parsing fast path.
- Multi-tenant auth — users, API keys, glob model permissions, RPM/RPD/token rate limits, USD quotas. Claude prompt caching, rewrite rules, circuit breakers.
- Pluggable storage — SQLite / PostgreSQL / MySQL, optional at-rest encryption.
- Embedded console — no separate frontend to deploy.
Fully self-contained: embedded console, file-based SQLite, no external services.
docker run -p 8787:8787 -e GPROXY_ADMIN_PASSWORD=change-me-min12char ghcr.io/leenhawk/gproxy
# then open http://localhost:8787/console (admin / change-me-min12char)The admin password must be at least 12 characters — the container exits on boot with
GPROXY_ADMIN_PASSWORD rejectedif it's shorter.Reaching the console over plain HTTP from a non-
localhostaddress (LAN IP, server IP, tunnel)? The session cookie isSecureby default, so the browser drops it and the console bounces you straight back to the login page even with the right password. Add-e GPROXY_INSECURE_COOKIES=1, or put it behind HTTPS. Plainhttp://localhost:8787works as-is.
The same router runs as a wasm edge function on six platforms. Prebuilt,
ready-to-deploy bundles live on the deploy branch
(no toolchain needed — the platforms have no cargo). Edge functions need an
external Turso control-plane DB (+ optional Upstash cache); full
walkthrough in docs/edge-deploy.md.
| Platform | Bundle | Deploy |
|---|---|---|
| Cloudflare Workers | deploy/cloudflare |
one-click button ☝️ / wrangler deploy |
| Netlify Edge | deploy/netlify |
one-click button ☝️ / netlify deploy --prod |
| Deno Deploy | — | deploy/deno/build.sh (CLI) |
| Supabase Edge | deploy/supabase |
supabase functions deploy gproxy (Docker/eszip, CLI) |
| EdgeOne Pages | deploy/eopages |
edgeone pages deploy (CLI) |
| Appwrite Functions | deploy/appwrite-deno |
appwrite push functions (deno-2.0, CLI) |
Pre-built binaries (linux/macOS/windows, x86_64 + aarch64) ship on every
release. Or cargo build --release.
GPROXY is configured by environment variables; live config then lives in the
database and is managed through /console.
| Variable | Default | Purpose |
|---|---|---|
GPROXY_HOST / GPROXY_PORT |
127.0.0.1 / 8787 |
bind address |
GPROXY_PERSISTENCE |
file |
file (SQLite under GPROXY_DATA_DIR) or db |
GPROXY_DSN |
— | DSN when persistence=db (Postgres/MySQL/SQLite) |
GPROXY_MASTER_KEY |
— | unseal stored secrets (absent = plaintext) |
GPROXY_ADMIN_USER / GPROXY_ADMIN_PASSWORD |
admin / random |
first-boot admin |
Upgrading from v1? Point a v2 binary at your existing v1 SQLite database and it
migrates in place on first boot (backing the old file up as *.v1.bak).
# Aggregated — provider/model in the body
curl http://127.0.0.1:8787/v1/chat/completions \
-H "Authorization: Bearer <your-key>" -H "Content-Type: application/json" \
-d '{"model":"openai-main/gpt-4.1-mini","messages":[{"role":"user","content":"Hello"}]}'Ops endpoints (/healthz, /version, /metrics) are admin-gated.
AGPL-3.0-or-later · Author: LeenHawk