proxy
| Name | Last commit date |
|---|---|
| .github | 1 year ago |
| auths | 1 year ago |
| cmd | 1 year ago |
| docs | 1 year ago |
| examples | 1 year ago |
| internal | 1 year ago |
| sdk | 1 year ago |
| .dockerignore | 1 year ago |
| .env.example | 1 year ago |
| .gitignore | 1 year ago |
| .goreleaser.yml | 1 year ago |
| config.example.yaml | 1 year ago |
| docker-build.ps1 | 1 year ago |
| docker-build.sh | 1 year ago |
| docker-compose.yml | 1 year ago |
| Dockerfile | 1 year ago |
| go.mod | 1 year ago |
| go.sum | 1 year ago |
| LICENSE | 1 year ago |
| MANAGEMENT_API.md | 1 year ago |
| MANAGEMENT_API_CN.md | 1 year ago |
| README.md | 1 year ago |
| README_CN.md | 1 year ago |
CLI Proxy API
English | 中文
A proxy server that provides OpenAI/Gemini/Claude/Codex compatible API interfaces for CLI.
It now also supports OpenAI Codex (GPT models) and Claude Code via OAuth.
So you can use local or multi-account CLI access with OpenAI(include Responses)/Gemini/Claude-compatible clients and SDKs.
Chinese providers have now been added: Qwen Code, iFlow.
Features
- OpenAI/Gemini/Claude compatible API endpoints for CLI models
- OpenAI Codex support (GPT models) via OAuth login
- Claude Code support via OAuth login
- Qwen Code support via OAuth login
- iFlow support via OAuth login
- Streaming and non-streaming responses
- Function calling/tools support
- Multimodal input support (text and images)
- Multiple accounts with round-robin load balancing (Gemini, OpenAI, Claude, Qwen and iFlow)
- Simple CLI authentication flows (Gemini, OpenAI, Claude, Qwen and iFlow)
- Generative Language API Key support
- AI Studio Build multi-account load balancing
- Gemini CLI multi-account load balancing
- Claude Code multi-account load balancing
- Qwen Code multi-account load balancing
- iFlow multi-account load balancing
- OpenAI Codex multi-account load balancing
- OpenAI-compatible upstream providers via config (e.g., OpenRouter)
- Reusable Go SDK for embedding the proxy (see
docs/sdk-usage.md)
Installation
Prerequisites
- Go 1.24 or higher
- A Google account with access to Gemini CLI models (optional)
- An OpenAI account for Codex/GPT access (optional)
- An Anthropic account for Claude Code access (optional)
- A Qwen Chat account for Qwen Code access (optional)
- An iFlow account for iFlow access (optional)
Building from Source
-
Clone the repository:
git clone https://github.com/luispater/CLIProxyAPI.git cd CLIProxyAPI -
Build the application:
Linux, macOS:
go build -o cli-proxy-api ./cmd/serverWindows:
go build -o cli-proxy-api.exe ./cmd/server
Installation via Homebrew
brew install cliproxyapi
brew services start cliproxyapi
Installation via CLIProxyAPI Linux Installer
curl -fsSL https://raw.githubusercontent.com/brokechubb/cliproxyapi-installer/refs/heads/master/cliproxyapi-installer | bash
Thanks to brokechubb for building the Linux installer!
Usage
GUI Client & Official WebUI
EasyCLI
A cross-platform desktop GUI client for CLIProxyAPI.
Cli-Proxy-API-Management-Center
A web-based management center for CLIProxyAPI.
Set remote-management.disable-control-panel to true if you prefer to host the management UI elsewhere; the server will skip downloading management.html and /management.html will return 404.
You can set the MANAGEMENT_STATIC_PATH environment variable to choose the directory where management.html is stored.
Authentication
You can authenticate for Gemini, OpenAI, Claude, Qwen, and/or iFlow. All can coexist in the same auth-dir and will be load balanced.
-
Gemini (Google):
./cli-proxy-api --loginIf you are an existing Gemini Code user, you may need to specify a project ID:
./cli-proxy-api --login --project_id <your_project_id>The local OAuth callback uses port
8085.Options: add
--no-browserto print the login URL instead of opening a browser. The local OAuth callback uses port8085. -
OpenAI (Codex/GPT via OAuth):
./cli-proxy-api --codex-loginOptions: add
--no-browserto print the login URL instead of opening a browser. The local OAuth callback uses port1455. -
Claude (Anthropic via OAuth):
./cli-proxy-api --claude-loginOptions: add
--no-browserto print the login URL instead of opening a browser. The local OAuth callback uses port54545. -
Qwen (Qwen Chat via OAuth):
./cli-proxy-api --qwen-loginOptions: add
--no-browserto print the login URL instead of opening a browser. Use the Qwen Chat's OAuth device flow. -
iFlow (iFlow via OAuth):
./cli-proxy-api --iflow-loginOptions: add
--no-browserto print the login URL instead of opening a browser. The local OAuth callback uses port11451.
Starting the Server
Once authenticated, start the server:
./cli-proxy-api
By default, the server runs on port 8317.
API Endpoints
List Models
GET http://localhost:8317/v1/models
Chat Completions
POST http://localhost:8317/v1/chat/completions
Request body example:
{
"model": "gemini-2.5-pro",
"messages": [
{
"role": "user",
"content": "Hello, how are you?"
}
],
"stream": true
}
Notes:
- Use a
gemini-*model for Gemini (e.g., "gemini-2.5-pro"), agpt-*model for OpenAI (e.g., "gpt-5"), aclaude-*model for Claude (e.g., "claude-3-5-sonnet-20241022"), aqwen-*model for Qwen (e.g., "qwen3-coder-plus"), or an iFlow-supported model (e.g., "tstars2.0", "deepseek-v3.1", "kimi-k2", etc.). The proxy will route to the correct provider automatically.
Claude Messages (SSE-compatible)
POST http://localhost:8317/v1/messages
Using with OpenAI Libraries
You can use this proxy with any OpenAI-compatible library by setting the base URL to your local server:
Python (with OpenAI library)
from openai import OpenAI
client = OpenAI(
api_key="dummy", # Not used but required
base_url="http://localhost:8317/v1"
)
# Gemini example
gemini = client.chat.completions.create(
model="gemini-2.5-pro",
messages=[{"role": "user", "content": "Hello, how are you?"}]
)
# Codex/GPT example
gpt = client.chat.completions.create(
model="gpt-5",
messages=[{"role": "user", "content": "Summarize this project in one sentence."}]
)
# Claude example (using messages endpoint)
import requests
claude_response = requests.post(
"http://localhost:8317/v1/messages",
json={
"model": "claude-3-5-sonnet-20241022",
"messages": [{"role": "user", "content": "Summarize this project in one sentence."}],
"max_tokens": 1000
}
)
print(gemini.choices[0].message.content)
print(gpt.choices[0].message.content)
print(claude_response.json())
JavaScript/TypeScript
import OpenAI from 'openai';
const openai = new OpenAI({
apiKey: 'dummy', // Not used but required
baseURL: 'http://localhost:8317/v1',
});
// Gemini
const gemini = await openai.chat.completions.create({
model: 'gemini-2.5-pro',
messages: [{ role: 'user', content: 'Hello, how are you?' }],
});
// Codex/GPT
const gpt = await openai.chat.completions.create({
model: 'gpt-5',
messages: [{ role: 'user', content: 'Summarize this project in one sentence.' }],
});
// Claude example (using messages endpoint)
const claudeResponse = await fetch('http://localhost:8317/v1/messages', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: 'claude-3-5-sonnet-20241022',
messages: [{ role: 'user', content: 'Summarize this project in one sentence.' }],
max_tokens: 1000
})
});
console.log(gemini.choices[0].message.content);
console.log(gpt.choices[0].message.content);
console.log(await claudeResponse.json());
Supported Models
- gemini-2.5-pro
- gemini-2.5-flash
- gemini-2.5-flash-lite
- gemini-2.5-flash-image
- gemini-2.5-flash-image-preview
- gemini-pro-latest
- gemini-flash-latest
- gemini-flash-lite-latest
- gpt-5
- gpt-5-codex
- claude-opus-4-1-20250805
- claude-opus-4-20250514
- claude-sonnet-4-20250514
- claude-sonnet-4-5-20250929
- claude-haiku-4-5-20251001
- claude-3-7-sonnet-20250219
- claude-3-5-haiku-20241022
- qwen3-coder-plus
- qwen3-coder-flash
- qwen3-max
- qwen3-vl-plus
- deepseek-v3.2
- deepseek-v3.1
- deepseek-r1
- deepseek-v3
- kimi-k2
- glm-4.6
- tstars2.0
- And other iFlow-supported models
- Gemini models auto-switch to preview variants when needed
Configuration
The server uses a YAML configuration file (config.yaml) located in the project root directory by default. You can specify a different configuration file path using the --config flag:
./cli-proxy-api --config /path/to/your/config.yaml
Configuration Options
| Parameter | Type | Default | Description |
|---|---|---|---|
port |
integer | 8317 | The port number on which the server will listen. |
auth-dir |
string | "~/.cli-proxy-api" | Directory where authentication tokens are stored. Supports using ~ for the home directory. If you use Windows, please set the directory like this: C:/cli-proxy-api/ |
proxy-url |
string | "" | Proxy URL. Supports socks5/http/https protocols. Example: socks5://user:pass@192.168.1.1:1080/ |
request-retry |
integer | 0 | Number of times to retry a request. Retries will occur if the HTTP response code is 403, 408, 500, 502, 503, or 504. |
remote-management.allow-remote |
boolean | false | Whether to allow remote (non-localhost) access to the management API. If false, only localhost can access. A management key is still required for localhost. |
remote-management.secret-key |
string | "" | Management key. If a plaintext value is provided, it will be hashed on startup using bcrypt and persisted back to the config file. If empty, the entire management API is disabled (404). |
remote-management.disable-control-panel |
boolean | false | When true, skip downloading management.html and return 404 for /management.html, effectively disabling the bundled management UI. |
quota-exceeded |
object | {} | Configuration for handling quota exceeded. |
quota-exceeded.switch-project |
boolean | true | Whether to automatically switch to another project when a quota is exceeded. |
quota-exceeded.switch-preview-model |
boolean | true | Whether to automatically switch to a preview model when a quota is exceeded. |
debug |
boolean | false | Enable debug mode for verbose logging. |
logging-to-file |
boolean | true | Write application logs to rotating files instead of stdout. Set to false to log to stdout/stderr. |
usage-statistics-enabled |
boolean | true | Enable in-memory usage aggregation for management APIs. Disable to drop all collected usage metrics. |
api-keys |
string[] | [] | Legacy shorthand for inline API keys. Values are mirrored into the config-api-key provider for backwards compatibility. |
gemini-api-key |
object[] | [] | Gemini API key entries with optional per-key base-url and proxy-url overrides. |
gemini-api-key.*.api-key |
string | "" | Gemini API key. |
gemini-api-key.*.base-url |
string | "" | Optional Gemini API endpoint override. |
gemini-api-key.*.headers |
object | {} | Optional extra HTTP headers sent to the overridden Gemini endpoint only. |
gemini-api-key.*.proxy-url |
string | "" | Optional per-key proxy override for the Gemini API key. |
generative-language-api-key |
string[] | [] | (Legacy alias) View-only list mirrored from gemini-api-key. Writes through the legacy management endpoint update the underlying Gemini entries. |
codex-api-key |
object | {} | List of Codex API keys. |
codex-api-key.api-key |
string | "" | Codex API key. |
codex-api-key.base-url |
string | "" | Custom Codex API endpoint, if you use a third-party API endpoint. |
codex-api-key.proxy-url |
string | "" | Proxy URL for this specific API key. Overrides the global proxy-url setting. Supports socks5/http/https protocols. |
claude-api-key |
object | {} | List of Claude API keys. |
claude-api-key.api-key |
string | "" | Claude API key. |
claude-api-key.base-url |
string | "" | Custom Claude API endpoint, if you use a third-party API endpoint. |
claude-api-key.proxy-url |
string | "" | Proxy URL for this specific API key. Overrides the global proxy-url setting. Supports socks5/http/https protocols. |
claude-api-key.models |
object[] | [] | Model alias entries for this key. |
claude-api-key.models.*.name |
string | "" | Upstream Claude model name invoked against the API. |
claude-api-key.models.*.alias |
string | "" | Client-facing alias that maps to the upstream model name. |
openai-compatibility |
object[] | [] | Upstream OpenAI-compatible providers configuration (name, base-url, api-keys, models). |
openai-compatibility.*.name |
string | "" | The name of the provider. It will be used in the user agent and other places. |
openai-compatibility.*.base-url |
string | "" | The base URL of the provider. |
openai-compatibility.*.api-keys |
string[] | [] | (Deprecated) The API keys for the provider. Use api-key-entries instead for per-key proxy support. |
openai-compatibility.*.api-key-entries |
object[] | [] | API key entries with optional per-key proxy configuration. Preferred over api-keys. |
openai-compatibility.*.api-key-entries.*.api-key |
string | "" | The API key for this entry. |
openai-compatibility.*.api-key-entries.*.proxy-url |
string | "" | Proxy URL for this specific API key. Overrides the global proxy-url setting. Supports socks5/http/https protocols. |
openai-compatibility.*.models |
object[] | [] | Model alias definitions routing client aliases to upstream names. |
openai-compatibility.*.models.*.name |
string | "" | Upstream model name invoked against the provider. |
openai-compatibility.*.models.*.alias |
string | "" | Client alias routed to the upstream model. |
When claude-api-key.models is specified, only the provided aliases are registered in the model registry (mirroring OpenAI compatibility behaviour), and the default Claude catalog is suppressed for that credential.
Example Configuration File
# Server port
port: 8317
# Management API settings
remote-management:
# Whether to allow remote (non-localhost) management access.
# When false, only localhost can access management endpoints (a key is still required).
allow-remote: false
# Management key. If a plaintext value is provided here, it will be hashed on startup.
# All management requests (even from localhost) require this key.
# Leave empty to disable the Management API entirely (404 for all /v0/management routes).
secret-key: ""
# Disable the bundled management control panel asset download and HTTP route when true.
disable-control-panel: false
# Authentication directory (supports ~ for home directory). If you use Windows, please set the directory like this: `C:/cli-proxy-api/`
auth-dir: "~/.cli-proxy-api"
# API keys for authentication
api-keys:
- "your-api-key-1"
- "your-api-key-2"
# Enable debug logging
debug: false
# When true, write application logs to rotating files instead of stdout
logging-to-file: true
# When false, disable in-memory usage statistics aggregation
usage-statistics-enabled: true
# Proxy URL. Supports socks5/http/https protocols. Example: socks5://user:pass@192.168.1.1:1080/
proxy-url: ""
# Number of times to retry a request. Retries will occur if the HTTP response code is 403, 408, 500, 502, 503, or 504.
request-retry: 3
# Quota exceeded behavior
quota-exceeded:
switch-project: true # Whether to automatically switch to another project when a quota is exceeded
switch-preview-model: true # Whether to automatically switch to a preview model when a quota is exceeded
# Gemini API keys
gemini-api-key:
- api-key: "AIzaSy...01"
base-url: "https://generativelanguage.googleapis.com"
headers:
X-Custom-Header: "custom-value"
proxy-url: "socks5://proxy.example.com:1080"
- api-key: "AIzaSy...02"
# Codex API keys
codex-api-key:
- api-key: "sk-atSM..."
base-url: "https://www.example.com" # use the custom codex API endpoint
proxy-url: "socks5://proxy.example.com:1080" # optional: per-key proxy override
# Claude API keys
claude-api-key:
- api-key: "sk-atSM..." # use the official claude API key, no need to set the base url
- api-key: "sk-atSM..."
base-url: "https://www.example.com" # use the custom claude API endpoint
proxy-url: "socks5://proxy.example.com:1080" # optional: per-key proxy override
# OpenAI compatibility providers
openai-compatibility:
- name: "openrouter" # The name of the provider; it will be used in the user agent and other places.
base-url: "https://openrouter.ai/api/v1" # The base URL of the provider.
# New format with per-key proxy support (recommended):
api-key-entries:
- api-key: "sk-or-v1-...b780"
proxy-url: "socks5://proxy.example.com:1080" # optional: per-key proxy override
- api-key: "sk-or-v1-...b781" # without proxy-url
# Legacy format (still supported, but cannot specify proxy per key):
# api-keys:
# - "sk-or-v1-...b780"
# - "sk-or-v1-...b781"
models: # The models supported by the provider. Or you can use a format such as openrouter://moonshotai/kimi-k2:free to request undefined models
- name: "moonshotai/kimi-k2:free" # The actual model name.
alias: "kimi-k2" # The alias used in the API.
Git-backed Configuration and Token Store
The application can be configured to use a Git repository as a backend for storing both the config.yaml file and the authentication tokens from the auth-dir. This allows for centralized management and versioning of your configuration.
To enable this feature, set the GITSTORE_GIT_URL environment variable to the URL of your Git repository.
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
MANAGEMENT_PASSWORD |
Yes | The password for management webui. | |
GITSTORE_GIT_URL |
Yes | The HTTPS URL of the Git repository to use. | |
GITSTORE_LOCAL_PATH |
No | Current working directory | The local path where the Git repository will be cloned. Inside Docker, this defaults to /CLIProxyAPI. |
GITSTORE_GIT_USERNAME |
No | The username for Git authentication. | |
GITSTORE_GIT_TOKEN |
No | The personal access token (or password) for Git authentication. |
How it Works
- Cloning: On startup, the application clones the remote Git repository to the
GITSTORE_LOCAL_PATH. - Configuration: It then looks for a
config.yamlinside aconfigdirectory within the cloned repository. - Bootstrapping: If
config/config.yamldoes not exist in the repository, the application will copy the localconfig.example.yamlto that location, commit, and push it to the remote repository as an initial configuration. You must haveconfig.example.yamlavailable. - Token Sync: The
auth-diris also managed within this repository. Any changes to authentication tokens (e.g., through a new login) are automatically committed and pushed to the remote Git repository.
PostgreSQL-backed Configuration and Token Store
You can also persist configuration and authentication data in PostgreSQL when running CLIProxyAPI in hosted environments that favor managed databases over local files.
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
MANAGEMENT_PASSWORD |
Yes | Password for the management web UI (required when remote management is enabled). | |
PGSTORE_DSN |
Yes | PostgreSQL connection string (e.g. postgresql://user:pass@host:5432/db). |
|
PGSTORE_SCHEMA |
No | public | Schema where the tables will be created. Leave empty to use the default schema. |
PGSTORE_LOCAL_PATH |
No | Current working directory | Root directory for the local mirror; the server writes to <value>/pgstore. If unset and CWD is unavailable, /tmp/pgstore is used. |
How it Works
- Initialization: On startup the server connects via
PGSTORE_DSN, ensures the schema exists, and creates theconfig_store/auth_storetables when missing. - Local Mirror: A writable cache at
<PGSTORE_LOCAL_PATH or CWD>/pgstoremirrorsconfig/config.yamlandauths/so the rest of the application can reuse the existing file-based logic. - Bootstrapping: If no configuration row exists,
config.example.yamlseeds the database using the fixed identifierconfig. - Token Sync: Changes flow both ways—file updates are written to PostgreSQL and database records are mirrored back to disk so watchers and management APIs continue to operate.
Object Storage-backed Configuration and Token Store
An S3-compatible object storage service can host configuration and authentication records.
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
MANAGEMENT_PASSWORD |
Yes | Password for the management web UI (required when remote management is enabled). | |
OBJECTSTORE_ENDPOINT |
Yes | Object storage endpoint. Include http:// or https:// to force the protocol (omitted scheme → HTTPS). |
|
OBJECTSTORE_BUCKET |
Yes | Bucket that stores config/config.yaml and auths/*.json. |
|
OBJECTSTORE_ACCESS_KEY |
Yes | Access key ID for the object storage account. | |
OBJECTSTORE_SECRET_KEY |
Yes | Secret key for the object storage account. | |
OBJECTSTORE_LOCAL_PATH |
No | Current working directory | Root directory for the local mirror; the server writes to <value>/objectstore. If unset, defaults to current CWD. |
How it Works
Document preview limited. Open the file to continue