首次启动前,Linux 绑定挂载需给非 root 容器用户 10001:10001 写权限;全新安装没有客户端 Key,必须先创建门户账号和 Key,否则请求会被拒绝;config.yaml 需对 10001 用户可读,若要在面板保存配置还需可写。
CliRelay
kittorsMIT活跃维护自托管的 AI 网关,把 OpenAI、Claude、Gemini、Codex 等编码 CLI 统一到一个兼容端点,并提供多租户控制台、请求日志和费用配额管理。
Self-hosted AI gateway for coding CLIs — one OpenAI/Claude/Gemini/Codex-compatible endpoint, with a multi-tenant web console, request logs, and spend quotas.
git clone https://github.com/kittors/CliRelay.git
cd CliRelay
docker compose up -dREADME 未说明硬件要求;部署依赖 PostgreSQL 15+ 和 Redis 7+,推荐用 Docker Compose 启动。
自托管 AI 网关,把多种编码 CLI 订阅和 API Key 统一到一个兼容端点,并带多租户控制台
自托管的 AI 网关,把 OpenAI、Claude、Gemini、Codex 等编码 CLI 统一到一个兼容端点,并提供多租户控制台、请求日志和费用配额管理。
核心能力
- 用单一端点兼容 OpenAI、Anthropic、Gemini 协议
- 按渠道组路由,支持轮询、填充优先和会话粘性调度
- 账号配额耗尽或失败时自动冷却并故障转移
- 记录每个请求的 token、延迟和成本,并提供监控中心
- 按门户账号分组客户端 Key,设置日、周期和终身配额
容易踩的坑
- v0.6.0v0.6.0 - Privacy Masking, Per-Model Quotas, Virtual Models, and Alerts最新正式版2026-11-07 · 2026-11-07 13:25 UTC
v0.6.0 - Privacy Masking, Per-Model Quotas, Virtual Models, and Alerts
The largest release since v0.5.0: 52 pull requests since v0.5.9. Pair it with codeProxy v0.7.0 and update the panel first. Back up your database before upgrading: one migration permanently masks the client API keys stored in the request log. See Upgrade Notes.
Highlights
1. Privacy masking
- Sensitive values are replaced with placeholders before a request leaves CliRelay, and the reply gets the real values back. Upstream providers and third-party relays see only the placeholders. The masking engine is ported from magpie (#1235).
- Per-tenant settings, portal access, masking records and their management APIs (#1237). Only the tenant admin decides what is masked (#1239, #1240).
- Outbound secret masking per tenant, with the secrets restored in replies (#1229).
2. Sensitive-word guard
- Words and RE2 rules that block, replace or log. They are layered platform → tenant → key, with scan scopes (#1219). Portal accounts can keep their own words (#1232, #1233).
- Moderation now covers tool output, history and respelled keywords, and scans the newest input (#1203). Platform-shared channels apply the credential owner's profile (#1199).
3. Per-model quotas and model routes
- Per-model quotas, windowed request and token limits, and model routes for accounts, permission templates and keys (#1168).
- Requests in flight count against a key's budgets (#1215).
4. Routing and scheduling
- Virtual models: one model name that falls back across channel groups (#1223).
- Route simulation: see where a request would go, stage by stage and credential by credential (#1220). Each request also records its route trace, and the requests in flight can be listed (#1221).
- Streams fail over before the first byte by default. There is also a first-token timeout and an opt-in, bounded busy wait (#1214).
- Quota spending: quota that a reset is about to wipe out is spent first (#1217). Channel groups can follow upstream models (#1198).
- Cooldowns:
- they follow upstream retry hints, Codex 401s are told apart, and a single model can be retried right away (#1209);
- each channel and account can override cooling (#1195);
- OpenAI-compatible upstreams'
Retry-Afteron 429 is honoured (#1193).
5. Operations
- Quota, account and spending alerts with chat or webhook delivery, plus pool capacity (#1224).
- A loop guard that stops repeated replies and tool-call loops. It stays off until a tenant or key opts in (#1222).
- Prometheus metrics on
/metrics(#1212), and dry runs of payload rules on a sample body (#1218). - Deploys no longer cut off in-flight requests: the new build starts in the idle slot and the old one drains before it stops (#1169). The single-node setup gets an offsite database backup and a watchdog that only checks the active slot (#1200).
6. Tenancy and accounts
- The system tenant's proxies and AI accounts can be shared with other tenants (#1157).
- Warmups stay inside the caller's tenant, and a shared platform account doesn't reveal whose it is (#1227).
- CliRelay counts copies of a tenant's accounts that other tenants hold (#1230).
- CC Switch import presets for OpenCode, OpenClaw and Hermes, each with an explicit Codex context window (#1158, #1159). Codex accounts can use the Ultrafast tier (#1180).
7. Protocol fixes
- Codex:
- live quota windows, the Chat cache key, zstd request bodies, and recovery of reasoning ciphertext (#1210);
- only an explicit imagegen call pins the image tool, and image calls carry no effort (#1241);
- the Responses WebSocket lets Codex send only what each turn adds (#1242).
- Claude:
- requests are shaped for each model's request surface (#1204);
- unpaired
tool_use/tool_resultblocks are repaired before sending (#1205); - Opus 4.7 and later get adaptive thinking (#1197);
- prefixing tools no longer copies the request repeatedly
- v0.5.9v0.5.9 - Gemini Images on /v1/images, config.yaml Saves That Stop Losing Settings, and Codex Models That Survive Restarts2026-10-11 · 2026-10-11 22:19 UTC
查看更新说明
v0.5.9 - Gemini Images on /v1/images, config.yaml Saves That Stop Losing Settings, and Codex Models That Survive Restarts
Pair it with codeProxy v0.6.2, which adds the Gemini image pickers and shows why a config.yaml save was rejected. Either upgrade order works; see Upgrade Notes.
PUT /v0/management/config.yamlnow rejects saves it used to accept and then silently lose, so scripts that write config.yaml should read the Upgrade Notes first.Highlights
1. Antigravity's Gemini image model on
/v1/imagesand the console- What was wrong:
gemini-3.1-flash-imageon Antigravity already returned pictures through the chat endpoints, but nothing on the images side could reach it./v1/images/*, the console's image page and the model probe listed only gpt-image, Grok and MiniMax, and the Antigravity executor did not understand an images request. - What's new:
/v1/images/generationsand/v1/images/editsserve Gemini image models while an Antigravity credential offers them. A model Antigravity publishes later needs no code change.aspect_ratioandimage_sizemap onto Gemini's image settings: the fourteen ratios upstream accepts (1:1to21:9) and the512/1K/2K/4Ktiers. AWIDTHxHEIGHTsize maps to the nearest ratio and tier, so existing clients keep working.- Ratios are sent in upstream's own spelling.
21:9used to be reduced to7:3, which upstream rejects (#1148). - Reference images can be uploaded or sent as base64 data URIs. Remote URLs are not fetched, and masks are refused.
- Responses report the real
output_format(Gemini returns JPEG), the pixelsizeand tokenusage. A request that returns no image (a safety block, a text-only answer) fails as an invalid request, so the account is not cooled down. - The chat endpoints are unchanged.
2. config.yaml saves no longer report success while losing settings
- What was wrong:
PUT /v0/management/config.yamlanswered200 {"ok": true}in two cases where the change then existed nowhere:- The runtime settings a save spelled out (
proxy-url,debug,request-retry,payloadand others) were stored one key at a time, after the file was written. A key that failed to store was only logged. The reload then stripped it from the file and restored the old stored value. - The sections the database owns (
routing,proxy-pool,api-keys,api-key-entries,api-key-permission-profiles) were written to the file, then dropped or overridden by the stored value. Hand-typed API keys even worked as keys of that one node until its next start.
- The runtime settings a save spelled out (
- The fix:
- Runtime settings are stored first, in one transaction. If that fails, nothing changes and the save is rejected with
409 config_version_conflictor with a500that gives the cause. - A save that would change a database-owned section is rejected with
422 config_yaml_database_owned_sectionsbefore anything is stored or written. The message names each section and the page where it is edited: Channel Groups, Outbound Proxies, API Keys or Portal Account Permissions. A copy of the stored value still passes, as do the published example keys and sections the database does not hold yet. - Once the database holds API keys, a reload drops
api-keys/api-key-entriesfrom config.yaml, so hand-typed keys no longer act as keys of one node only. - Only hand-typed YAML is affected. The panel's dedicated pages use their own endpoints.
- Runtime settings are stored first, in one transaction. If that fails, nothing changes and the save is rejected with
3. Codex model lists survive restarts
- What was wrong: on 2026-10-11 a deploy restarted production, and for half an hour Codex clients got
502 unknown provider for model gpt-6.1-sol. The live model list was kept only in memory, and fetching it again failed. The fetch looked up each credential'sproxy_idin the system tenant's proxy pool instead of the credential's own tenant, and the system pool still pointed at retired proxy endpoints. - The fix:
- Every model list fetched fr
- What was wrong:
- v0.5.8v0.5.8 - Go Security Update, Sign-in Lockout Warnings, and No More Idle HTTP/2 Connection Pile-ups2026-10-09 · 2026-10-09 16:20 UTC
查看更新说明
v0.5.8 - Go Security Update, Sign-in Lockout Warnings, and No More Idle HTTP/2 Connection Pile-ups
This release fixes eleven Go standard library and
golang.org/x/netvulnerabilities; upgrade promptly. Pair it with codeProxy v0.6.1, whose sign-in forms use the fields added here to show the attempts left and to count a lock down. Either upgrade order works; see Upgrade Notes.Highlights
1. Go 1.26.9 security update
- What was wrong: v0.5.7 was built with Go 1.26.6 and
golang.org/x/netv0.57.0. govulncheck now reports eleven vulnerabilities, GO-2026-6603 to GO-2026-6617, that CliRelay's code can reach:- HTTP/2 server: a crash from an HPACK encoder race, memory exhaustion from trailer headers, excessive CPU from repeated window changes, and a flow-control accounting error;
- HTTP/2 client: malformed framing-related headers were accepted;
- HTTP/1: connections could fall out of sync after a CONNECT response, on the server and on the client;
- Header parsing:
Rangeheaders had no size limit, and MIME header parsing could bypass its memory limit; crypto/tls: malformed ECH extension references were not rejected;- Windows only:
os.Rootdirectory creation could follow junctions out of the root.
- The fix:
- Builds use Go 1.26.9 and
golang.org/x/netv0.60.0, and govulncheck reports no vulnerabilities that the code reaches. - The Docker image built its updater binary with Go 1.26.1; it now uses 1.26.9 as well.
- Builds use Go 1.26.9 and
- Upgrade promptly: CliRelay is both an HTTP server and an HTTP/2 client.
2. Sign-in warns before it locks, and says how long a lock lasts
- What was wrong: users were locked out of sign-in without warning and then given the wrong explanation, so they kept guessing.
- The admin sign-in locked on the third wrong password, without saying so.
- During that lock, wrong passwords still got "invalid credentials". Only the correct password got
account_locked, which the panel shows as "This account is disabled or locked. Contact your tenant administrator." In production, an administrator typed the correct password during a lock, read that message, and gave up for an hour and a half. - Neither the admin nor the portal sign-in said how many attempts were left. The failure that tripped a lock looked like one more wrong password.
- Throttle rejections carried the wait only in the
Retry-Afterheader, which the panel does not read.
- The fix:
-
The admin panel and the portal now share one cooldown ladder:
Failures Lock 5 1 minute 10 5 minutes 15 15 minutes 20 30 minutes 25, and every 5th after 60 minutes The count restarts after 15 minutes without a failure. There is no permanent lock. The admin panel's first lock moves from 3 failures to 5, matching the portal.
-
The admin sign-in checks the lock before it checks the password. A sign-in during a lock gets
429 login_cooldown, whatever password is typed.account_lockednow means only a lock set by an administrator. -
A wrong password that does not trip a lock gets
401 invalid_credentialswithdetails.remaining_attempts. For an ordinary run of mistypes the number is the same whether or not the username exists, so it does not reveal which accounts exist. -
The wrong password that trips a lock gets
429, with the longest of the per-IP, per-account and cooldown waits. -
login_rate_limitedandlogin_cooldownresponses carrydetails.retry_after_secondsin the body, as well as theRetry-Afterheader.
-
3. Idle HTTP/2 connections to chatgpt.com no longer pile up
- What was wrong: a user reported 373 connections from one relay to
chatgpt.com:443. They were hours old, and each was exchanging only about 4.7 kB an hour in each direction. Production showed the same: 218 such connections 3.5 hours after a deploy. Two problems combined:- The Codex quota probe built
- What was wrong: v0.5.7 was built with Go 1.26.6 and
- v0.5.7v0.5.7 - Monitor Center API, Credential Imports, and Faster Recovery From Dead Connections2026-10-07 · 2026-10-07 18:40 UTC
查看更新说明
v0.5.7 - Monitor Center API, Credential Imports, and Faster Recovery From Dead Connections
Pair this release with codeProxy v0.6.0. The redesigned panel's monitor center, guided "Add AI account" dialog and credential imports use the endpoints added here. Upgrade the backend first; see Upgrade Notes.
Highlights
1. Monitor center endpoints
- What was missing: the monitor page could only read
/usage/chart-data: request counts, a success rate and token totals. There were no latency percentiles, first-token times, failure sources, rankings or live traffic. - Overview:
GET /v0/management/usage/monitor/overview.- Ranges
1h,6h,24h,today,7d,14dand30d, filterable by portal user or API key, model and channel. - Totals compared with the previous period of equal length, and continuous zero-filled series.
- Latency and first-token P50 / P90 / P95 / P99 / max / avg with a histogram.
- Model, channel and portal-user rankings with sparklines, a weekday × hour heatmap, the consumer → model → channel flow, and recent failures.
- Ranges
- Realtime:
GET /v0/management/usage/monitor/realtimecovers the last hour per minute, current and peak RPM / TPM, and a five-minute window. It is cheap enough to poll every 15 seconds. - Built to stay cheap:
- Totals, series, rankings, heatmap and flows read the rollup buckets, so they cover the whole history.
- Percentiles read request details only inside their retention window, and the response says where coverage starts.
- A section that fails is logged and returned empty instead of failing the page.
- Both endpoints are tenant-scoped and need
monitor.read.
- Timezone label: services started without
TZreported their zone asLocal. The label is now the IANA name, or the UTC offset (UTC+08:00) when the zone has no name. Bucket edges are unchanged.
2. Add AI accounts from credentials you already hold
- What's new: besides the browser and device sign-ins, an account can now be added from a credential you hold. CliRelay exchanges it for the same tokens a browser login would mint and saves the account under the caller's tenant. Four imports are supported:
- a claude.ai session cookie;
- an OpenAI / Codex CLI refresh token;
- a Google / Antigravity refresh token;
- a Grok web SSO cookie.
- Errors that say what went wrong:
- A bad credential returns
422. It is never401, which the panel would read as its own session expiring. - A Cloudflare challenge returns
502and is reported as an egress problem rather than a bad credential. A timeout returns504. - Secrets an upstream echoes back are masked in the message.
- A bad credential returns
- The permission is
auth_files.oauth, the same as for OAuth sign-in.
3. OAuth sign-ins report how they finish
- What was wrong: the panel only received a URL and a state, so it showed one generic "paste the callback URL" box for every provider, including device-code providers where there is nothing to paste. A login that had expired, or that had been replaced by a newer one, also read as
{"status":"ok"}, which the panel showed as success. - The fix:
- The
*-auth-urlendpoints now returnflow(redirect,codeordevice),expires_at, and for device loginsuser_code,verification_uriandexpires_in. - Claude accepts
?callback_mode=code. Anthropic's own code page is then used, so a remote panel never sends the browser to a localhost forwarder. - Expired and superseded logins are reported as such. Late callbacks get
409withoauth_login_expiredoroauth_login_superseded, on a single node and in cluster mode.
- The
4. Dead HTTP/2 connections are detected in about 45 seconds instead of about 15 minutes
- What was wrong: the fingerprinted transports, for Anthropic and the TLS-fingerprinted providers, reuse one HTTP/2 connection per host. A connection that had silently died still looked usable. A request written onto it was retransmitted
- What was missing: the monitor page could only read
- v0.5.6v0.5.6 - 多节点集群、滚动发布与 Codex 新模型即时可用 / Multi-node Cluster, Rolling Deploys, and Live Codex Models2026-09-30 · 2026-09-30 02:02 UTC
查看更新说明
v0.5.6 - 多节点集群、滚动发布与 Codex 新模型即时可用 / Multi-node Cluster, Rolling Deploys, and Live Codex Models
核心更新亮点 / Highlights
1. Codex 新模型不用再等一次发版 / New Codex models work without a release
- 请求带上当前官方 CLI 版本:ChatGPT 会按客户端版本拒绝模型。
gpt-6.1-sol在codex_cli_rs/0.149.1和清单里写的0.153.0上都会被拒,当前稳定版0.159.1可以通过。请求现在使用官方 Codex CLI 的最新稳定版本;版本源暂时不可用时,退回到已经验证能过门的版本,有更新的版本会自动跟上。 - 根目录渠道自动带上新模型:默认渠道组的允许列表不再挡住 Codex 刚刚发现的模型。模型广场不用再去根目录渠道手动勾选。已经排除的模型仍然排除,其它渠道组保持原来的固定名单。
2. 多节点集群 / Multi-node cluster
- 共享运行时状态:凭证、配置、路由、会话亲和、账号并发、API Key 与终端用户限额、冷却、登录节流可以跨节点共享。
- 节点身份与就绪:进程带上节点身份,
/readyz能区分本节点和集群。用量日志在数据库中断时仍会留下,配额在最近一次用量读数上继续放行。 - DNS 与出口:
clirelay-dnswatch按节点健康和出口探测调整记录,避免把流量切到出不了网的节点。 - 备份:PostgreSQL 基础备份、WAL 归档,以及每周恢复演练。
3. 发布改为单实例替换 / Deploys replace the one live process
- 不再另起第二个槽:同一台机器上的第二个进程会抢同一个集群节点身份。发布现在替换 nginx 正在转发的那一个进程,失败时把上一份二进制换回去。
- 多节点仍逐台滚动:一台健康之后才继续下一台,并支持经跳板机连接。
详细改动记录 / Detailed Changes
后端 CliRelay
- fix(codex):请求使用当前官方 CLI 版本;默认渠道组自动接纳 Codex 发现的新模型(#1109)。
- feat(cluster):PostgreSQL 协调器、Redis 共享状态、跨节点限额 / 会话 / 冷却 / 配置 / 凭证(#1092–#1099)。
- feat(deploy):逐节点滚动发布、节点自己的资源限制、可选跳板机(#1094、#1098)。
- feat(egress):
/readyz/egress,DNS 优先选择出口正常的节点(#1100)。 - feat(cluster):基础备份、WAL 与每周恢复演练(#1107)。
- fix(update):更新器缺失时返回 503 而不是 502(#1106)。
- fix(cluster):降级节点重新加入时不再拖住整个集群;蓝绿继任者保留原节点的成员行(#1099、#1105)。
升级提示 / Upgrade Notes
- 单节点部署会替换当前正在服务的进程,切换期间有短暂中断,不再并行启动第二个槽。
- 集群模式需要按
deploy/cluster的说明准备 PostgreSQL、Redis 和节点身份。没打开集群配置的单节点行为与原来一致,只是发布方式改成单实例替换。 - 面板请搭配 codeProxy v0.5.4。
未进入本次发版、仍开在
dev上的 PR:#1108、#1104、#1101、#1086、#1085。 - 请求带上当前官方 CLI 版本:ChatGPT 会按客户端版本拒绝模型。
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
Contents
- What is CliRelay?
- Highlights
- How a request flows
- A tour of the control panel
- Supported providers
- Quick start
- Connect your tools
- Configuration essentials
- Deployment options
- Architecture
- Documentation
- Contributing
- License and acknowledgements
What is CliRelay?
A heavily extended fork of CLIProxyAPI, rebuilt around a production management layer, a web control panel and day-2 operations.
CliRelay turns AI CLI subscriptions, OAuth credentials, provider API keys and OpenAI-compatible upstreams into one managed API layer. Clients talk to a single endpoint using the OpenAI, Anthropic or Gemini protocol; CliRelay authenticates them with its own client keys, picks a healthy upstream account, translates the request when needed, and records what happened.
It is built to be run by a team. Tenants keep their accounts, keys and data apart; users get roles with fine-grained permissions; every security-sensitive change lands in an audit log; and portal accounts let end users hold several API keys and check their own usage without asking an admin.
PostgreSQL 15+ is the source of truth for runtime data. Redis 7+ holds caches, locks, rate limits, queues and other rebuildable state.
Highlights
| 🔌 One endpoint, every provider | Claude, Codex, Gemini CLI, Antigravity, Vertex, Bedrock, xAI/Grok, Qwen, Kimi, iFlow, OpenCode Go, ClinePass, Ollama Cloud, Command Code and any OpenAI-compatible upstream behind http://your-host:8317, speaking OpenAI Chat / Responses, Anthropic Messages and Gemini. |
| 🧭 Routing that survives bad days | Channel groups and custom paths decide where traffic may go; round-robin, fill-first and session-sticky scheduling spread it; cooldowns and automatic failover move it off exhausted or failing accounts. |
| 📈 See everything | A monitor center with a health score, per-minute live traffic, P50–P99 latency and time to first token, failure analysis and a portal user → model → channel traffic flow, plus a searchable log of every request with tokens, latency and cost. |
| 💳 Control spend | Client keys grouped under portal accounts, reusable permission profiles, daily / period / lifetime quotas, RPM and TPM limits, per-model pricing and one-click period resets. |
| 🏛️ Built for teams | Tenants, users, roles, resource.action permissions, a curated menu per tenant and an audit trail for security-sensitive changes. |
| 🖥️ Operate from the browser | A /manage control panel to add accounts with guided sign-in or credential import, edit config visually, manage models and pricing, and check for updates — in English, Simplified Chinese and Russian. |
How a request flows
flowchart LR
subgraph clients["Your tools"]
cc["Claude Code"]
cx["Codex CLI"]
gc["Gemini CLI"]
oa["Any OpenAI-compatible client"]
end
subgraph relay["CliRelay :8317"]
auth["Client key<br/>portal account · permission profile"]
quota["Quotas & rate limits"]
route["Channel group routing<br/>scheduling · cooldown · failover"]
exec["Provider executors<br/>protocol translation"]
auth --> quota --> route --> exec
end
subgraph upstreams["Upstream accounts"]
oauth["OAuth accounts<br/>Claude · Codex · Gemini · Antigravity · Grok · Qwen · Kimi · iFlow"]
keys["Provider keys<br/>OpenAI-compatible · Vertex · Bedrock · OpenCode Go · ClinePass · Ollama Cloud"]
end
clients --> auth
exec --> oauth
exec --> keys
relay -. "request logs, usage rollups" .-> pg[("PostgreSQL")]
relay -. "cache, locks, limits" .-> rd[("Redis")]
- Authenticate. A client key resolves to its portal account and permission profile, which decide the allowed channel groups, models and quotas.
- Admit. Daily, period and lifetime spending, request quotas, RPM, TPM and concurrency are checked before anything reaches an upstream — for HTTP and for Responses WebSocket turns alike.
- Route. The request goes to a healthy channel (an AI account or a provider key) inside the allowed groups, following the scheduling strategy; failures cool the channel down and fail over to the next one.
- Translate and record. The executor speaks the upstream's protocol, streams the answer back, and writes a request log row and usage rollups that power the dashboards.
A tour of the control panel
The control panel (kittors/codeProxy) is served by CliRelay at /manage. The screenshots below follow its own navigation and were taken from a live deployment; names, keys, addresses and accounts are replaced with sample values.
Observability
| Monitor center — traffic and reliability over time | Monitor center — rankings, traffic flow and active hours |
|---|---|
| Dashboard | Request logs |
|---|---|
- Monitor center answers four questions at a glance: is it healthy, is it slow, what is failing, and where is traffic going.
- The health score combines success rate, the share of traffic on failing channels and P95 latency against the previous period, and explains each check.
- Six tiles cover requests, success rate, P95 latency, time to first token, tokens with cache hit rate, and cost — each with a period-over-period change and a sparkline.
- Below them: a trend view, the latency distribution (P50 / P90 / P95 / P99), failures by channel, model or portal user, model / channel / user rankings, a traffic-flow diagram and a weekday × hour heatmap. Click any row to filter the whole page.
- Dashboard summarises requests, success rate, tokens, cost, failures and cache ratio for today, 7 or 30 days, next to a live system monitor (CPU, memory, disk, database and log storage).
- Request logs list every call with its channel, portal user and key, cache / input / output tokens, latency and cost. Filter by user, model, channel and status, and open the request and response bodies when body storage is enabled.
| Model performance, channel health and portal users | Dark theme |
|---|---|
Access and credentials
| Add an AI account | Import credentials you already hold |
|---|---|
| AI accounts | AI providers |
|---|---|
| Portal accounts | Portal account permissions |
|---|---|
| Content moderation | CC Switch config |
|---|---|
- Add AI account groups every way in by what you will do — sign in with a browser, enter a device code, or import a credential — and walks through the steps that provider actually has, including which address to copy back and why the landing page does not load.
- Credential import turns a held credential (Claude session key, Codex or Antigravity refresh token, Grok SSO cookie) into an account. It explains where to find each one and what handing it over means, accepts many at once, and retries failed rows on their own.
- AI accounts show each OAuth account with its plan, quota windows, success rate and subscription expiry; AI providers hold API-key upstreams with base URL, headers, proxy binding and per-key model lists.
- Portal accounts own one or more client keys and share a quota; permission profiles bundle channel groups, models, limits and an optional system prompt so a new user is set up in one pick.
- Content moderation profiles can be tested against sample text and bound to accounts, keys or a provider default; CC Switch config builds one-click import presets for Claude Code and Codex.
Models and routing
| Model plaza | Model catalog |
|---|---|
| Channel groups | Outbound proxies |
|---|---|
- Model plaza shows every model the current tenant can reach, with capabilities, the channels that serve it and its price per million tokens.
- Model catalog is where models, owners, capabilities and pricing are maintained, with an optional OpenRouter sync and a built-in model test.
- Channel groups decide which channels a key may use and how traffic is spread inside the group; groups can follow new upstream models automatically.
- Outbound proxies are defined once and bound to the accounts or provider keys that need a fixed egress IP.
Organization
| Tenants | Users |
|---|---|
| Roles and permissions | Audit logs |
|---|---|
- Tenants carry their own accounts, keys, routing and data, with a lease period; administrators switch the effective tenant from the header.
- Roles grant
resource.actionpermissions such asproviders.testormodels.write, which decide the pages, buttons and API calls each user gets. - Audit logs record who changed what, from where, and whether it succeeded.
System
| Visual config editor | System info |
|---|---|
| Menu management | Sign-in |
|---|---|
- Config edits the running configuration through grouped forms with inline validation, or as YAML in the source editor; a recommended low-resource profile tunes small hosts in one click.
- System info shows the API and management endpoints, backend and panel versions, and checks for updates.
- Menu management curates which entries a tenant sees and which permission each requires.
Supported providers
| Provider / channel | How it connects | Notes |
|---|---|---|
| Anthropic Claude | OAuth (browser or code page), session-key import, API key | Claude Code and Claude-compatible clients; Messages and Responses entrypoints |
| OpenAI Codex | OAuth, refresh-token import, API key | Responses over HTTP and WebSocket, image generation bridge |
| Google Gemini | OAuth (Gemini CLI), API key | Gemini CLI and AI Studio style flows |
| Antigravity | OAuth, refresh-token import | Gemini and Claude model families, quota warmup |
| Vertex AI | Service-account JSON, API key | Custom base URL, headers, aliases and exclusions |
| AWS Bedrock | API key or SigV4 | Region-aware Bedrock Runtime with Claude model mappings |
| xAI / Grok | OAuth, SSO-cookie import | Grok CLI identity and quota metadata |
| Qwen | Device code | Qwen Code style sign-in |
| Kimi | Device code | Kimi CLI identity headers |
| iFlow | OAuth, cookie | iFlow and related model families |
| OpenCode Go | API key | Usage windows read with the same key; vision fallback model |
| ClinePass | API key | OpenAI-compatible routing with model-access control |
| Ollama Cloud | API key | OpenAI-compatible routing with model-access control |
| Command Code | API key | Plan usage windows and model access |
| OpenAI-compatible upstreams | API key | OpenRouter and any service that speaks Chat Completions |
| Amp | Upstream key and model mappings | Amp CLI and IDE integration |
Quick start
Docker Compose is the recommended installation. It starts CliRelay, PostgreSQL 15, Redis 7 and the updater sidecar.
git clone https://github.com/kittors/CliRelay.git
cd CliRelay
# Linux bind mounts need write access for the non-root container user:
# sudo chown -R 10001:10001 auths logs data
docker compose up -d
On the first start, the clirelay-init service creates .env and config.yaml if they are missing and generates the secrets it needs (CLIRELAY_ADMIN_PASSWORD, CLIRELAY_POSTGRES_PASSWORD, CLIRELAY_UPDATER_TOKEN). Existing non-empty values are kept.
| What | Where |
|---|---|
| API endpoint | http://localhost:8317 |
| Control panel | http://localhost:8317/manage — sign in as admin with CLIRELAY_ADMIN_PASSWORD from .env |
| Logs | docker compose logs -f cli-proxy-api |
| Restart / stop | docker compose restart cli-proxy-api / docker compose down |
| Terminal UI | docker compose exec cli-proxy-api ./cli-proxy-api -tui |
Then, in the control panel:
- Add an upstream — AI Accounts → Add AI account to sign in with a subscription or import a credential, or AI Providers for an API key.
- Create a client key — Portal Accounts → Create user; each portal account holds one or more keys. A fresh install ships with no client key and rejects client requests until you create one; the
your-api-key-*values inconfig.example.yamlare placeholders that are always rejected. - Point your tools at CliRelay — see below.
[!NOTE] The container runs as
10001:10001;config.yamlmust be readable by it, and writable if you want to save config from the panel. If a Synology/DSM shared-folder ACL blocks the entrypoint'schown, fix ownership on the host and restartcli-proxy-api. If you pre-setCLIRELAY_ADMIN_PASSWORD, use at least 12 characters with an upper-case letter, a lower-case letter and a symbol; a weaker value is replaced on the next start.
Connect your tools
Use a client key created in the panel wherever a tool expects an API key.
Claude Code
export ANTHROPIC_BASE_URL=http://localhost:8317
export ANTHROPIC_AUTH_TOKEN=sk-your-client-key
claude
Codex CLI (~/.codex/config.toml)
model_provider = "clirelay"
[model_providers.clirelay]
name = "openai"
base_url = "http://localhost:8317/v1"
requires_openai_auth = true
Any OpenAI-compatible client
curl http://localhost:8317/v1/chat/completions \
-H "Authorization: Bearer sk-your-client-key" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-5.5", "messages": [{"role": "user", "content": "Hello"}]}'
[!TIP] CC Switch Config in the panel builds a one-click import link for Claude Code and Codex, with the model mapping and channel group already filled in.
Full client guides: help.router-for.me.
Configuration essentials
Everything below can be changed in the panel's Config page or in config.yaml.
| Setting | What it controls |
|---|---|
port, host | Where the API and panel listen (default 8317, all interfaces). |
remote-management | Whether the management API accepts non-local callers, whether /manage is served, and which repository the panel updates from (panel-github-repository, default kittors/codeProxy). |
routing.strategy | Default scheduling inside a group: round-robin, fill-first or session-sticky. |
request-retry, max-retry-interval, quota-exceeded | How many times a failed request is retried and what happens when an account's quota runs out. |
proxy-url, proxy pool | Global and per-account outbound proxies. |
request-log-storage | Whether full request / response bodies are kept, for how long and up to what size. Off by default; metadata and request details are always recorded. |
auto-update | Update checks and the channel they follow (main by default, dev for preview builds). |
cors-allow-origins | Browser and extension origins allowed to call the API. |
# Keep full bodies for 7 days, capped at 2 GB
request-log-storage:
store-content: true
content-retention-days: 7
max-total-size-mb: 2048
# Follow dev builds, or turn update checks off
auto-update:
enabled: true
channel: dev
Config and credential storage can also live in PostgreSQL, Git or an S3-compatible object store instead of local files, selected through environment-based bootstrap settings.
Deployment options
| Setup | When to use it | Guide |
|---|---|---|
| Single node, Docker Compose | Personal use, small teams, NAS | Quick start · Production checklist |
| Behind nginx or another reverse proxy | Public HTTPS, custom domain | Reverse proxy (Chinese) |
| Several nodes on one shared PostgreSQL | Spreading traffic, automatic failover, rolling deploys | Multi-instance deployment · Node bootstrap (Chinese) |
Online updates run through the updater sidecar: the panel shows the target version, each stage as it happens, and the result, and reconnects on its own if the API restarts during the update.
Architecture
CliRelay/
├── cmd/server/ # Binary entry point and CLI modes
├── internal/api/ # HTTP server, management routes, middleware
├── internal/auth/ # Provider OAuth, cookie and device-code flows
├── internal/runtime/ # Executors per provider, scheduling, cooldown
├── internal/translator/ # OpenAI ⇄ Anthropic ⇄ Gemini ⇄ Responses translation
├── internal/identity/ # Tenants, users, roles, permissions, menus, audit logs
├── internal/usage/ # Request logs, rollups, monitor endpoints, retention
├── internal/config/ # Config parsing, defaults, migrations
├── internal/store/ # Local, Git, PostgreSQL and object-store persistence
├── internal/managementasset/ # /manage panel hosting and asset sync
├── internal/tui/ # Terminal management UI
├── sdk/ # Embeddable Go SDK, handlers and executors
├── deploy/ # Cluster building blocks and deploy scripts
└── docker-compose.yml # Default container deployment
| Layer | Technology |
|---|---|
| Runtime | Go 1.26, Gin, Docker Compose |
| Data | PostgreSQL 15+ via Ent, Redis 7+ for rebuildable state |
| Proxy core | OpenAI Chat Completions and Responses, Anthropic Messages, Gemini; SSE and WebSocket |
| Operations | /manage web panel, Bubble Tea terminal UI, updater sidecar |
Documentation
| Document | Description |
|---|---|
| Getting started | Installation and client setup guides |
| Management API | REST reference for the management endpoints |
| Amp CLI | Using Amp CLI and IDE extensions with CliRelay |
| Production checklist | Shared gateways and NAS installations |
| PostgreSQL / Redis runtime | Runtime data stack setup and validation |
| Multi-instance deployment | Several nodes on one PostgreSQL: failover, switchover, rolling deploys |
| SDK usage · advanced · access · watcher | Embedding the proxy in Go applications |
Contributing
git clone https://github.com/kittors/CliRelay.git
cd CliRelay
git fetch origin
git switch -c feature/your-change origin/dev
# make your change, then
git push origin feature/your-change # and open a pull request against dev
Please target pull requests at dev, not main; main is updated by releases. See CONTRIBUTING.md for the branch and merge workflow.
License and acknowledgements
CliRelay is released under the MIT License.
It stands on the core proxy logic of router-for-me/CLIProxyAPI. Our thanks to the original project and all its contributors — their foundation made it possible to build the management layer, request logging, quota control and the control panel on top.
Privacy masking (internal/privacymask) is ported from yetone/magpie: its rules for finding keys, tokens, passwords and personal data, its placeholders and the way it puts values back in replies. Thank you to magpie's author and contributors; the ported files keep magpie's MIT copyright notice (internal/privacymask/MAGPIE_LICENSE).