* refactor(settings): 按业务语义重排配置分区,收敛默认态展示密度 - 路由策略并入亲和分区(路由与调度),validation_interval 移出超时分组并入重试/凭据健康, models_dev_auto_sync_enabled 从请求转发移至数据与维护,header_rules 与 inject_usage_options 合并为上游请求改写;6 个分区拆为 7 个语义更清晰的分区。 - 新增 SettingRow 承载默认态单行展示、覆盖态才展开控件与说明文字,默认态徽标与操作按钮收敛, 避免逐字段重复常驻的说明文案。 * refactor(settings): 抽取 SettingRow 为共享组件并同步分组设置页展示密度 - SettingRow 从设置页移至 components/config,替换分组设置页运行时区块里的 RuntimeOverrideRow,行为对齐:默认态收敛徽标/按钮、覆盖态才展开控件与说明。 - RuntimeOverrideRow 无剩余引用,一并删除。 - 顺带修正分组页 inject_usage_options 折叠态展示 help 文案而非当前值的问题, 改为展示已启用/已禁用,说明文字移入 help 提示。 - 请求亲和沿用原有 SegmentedControl 三态控件,未纳入本次迁移。 * fix(settings): 按反馈调整 SettingRow 交互细节 - 提示统一用已有 AppTooltip 组件,替换原生 title;且不论是否覆盖,说明都只在 标签旁以 tooltip 展示,不再于覆盖态额外常驻一份。 - 覆盖/恢复默认按钮从行尾移到值后面,改回可见的按钮样式,不再靠悬停淡入。 - 覆盖态不再叠加“显式覆盖”徽标,仅保留左侧强调色与底色区分;待恢复/环境变量 锁定两种状态的徽标保留。 - 路由策略改用 SegmentedControl 二选一切换,替换下拉选择,和代理等控件观感一致。 - 各分区行列表之间补上小间距,避免行与行贴在一起。 * fix(settings): 覆盖/恢复默认按钮改为图标 + tooltip 文字按钮换成小方形图标按钮:覆盖用 PencilLine,恢复默认用 RotateCcw,配色沿用 原有 action/warning 两种 tone;按钮不再显示文字,改为 hover/聚焦时通过 AppTooltip 展示对应文案,无障碍上保留 aria-label。 * fix(settings): 覆盖/恢复默认图标去掉按钮底色,仅悬停反馈 去掉常驻边框和背景色,图标默认裸露显示,与旁边的说明提示图标风格保持一致; 悬停/聚焦时才出现对应 tone 的浅色背景。 * fix(settings): 覆盖图标恢复悬停显示 未覆盖态(含待恢复默认)的“覆盖”图标恢复为鼠标悬停/键盘聚焦到该行才显示, 平时隐藏;已覆盖态的“恢复默认”图标保持常驻可见,因为该行本身已有强调色和 底色区分,不需要靠图标常驻来提示。窄屏和纯触屏环境下始终显示,避免无法触发。 * refactor(settings): 移除 inject_usage_options 并统一设置页控件尺寸 移除 inject_usage_options 配置,改为始终注入: - 该开关只在「OpenAI Completions + 原生透传 + 流式」这一条路径生效(转换路径的 usage 来自 SDK,Anthropic/Gemini 原生流自带 usage),默认即为开启,暴露为用户 配置的收益远低于理解成本。 - 后端删除设置键、分组覆盖与渠道约束校验,IncludeUsage 固定为 ObserveUsage; 新增迁移 0008 清理 system_settings 行与分组 overrides 中的历史键,否则解析器 会以 "unknown runtime setting" 拒绝整份配置。 - 前端删除两处设置行、资源投影字段与三语文案。 设置页与分组设置页的控件: - 新增 --setting-control-height,并在 .setting-row/.setting-block 上覆盖 --control-compact/xs/sm,让输入框、切换控件、下拉统一小一档;变量继承进子组件, 不需要和组件自身 scoped 样式比优先级。 - 固定行内容高度,折叠态与覆盖态不再有高度差,点开编辑时行不会跳动。 - 块级说明(CORS 策略、下游响应头规则)从常驻小字改为标签旁 tooltip,与设置行一致。 分组设置页删除只读的渠道展示:顶部已有渠道信息,此处重复且不可编辑。 * fix(storage): 修复迁移 0008 在 PostgreSQL 上的两处方言问题 - 反引号是 MySQL/SQLite 语法,PostgreSQL 解析 `key` = ? 直接报 syntax error, 导致启动中断。改用 GORM 结构体条件,由驱动按方言自行加引号。 - 往 json 列写 []byte 时 PostgreSQL 驱动按 bytea 处理,报 invalid input syntax for type json。改为写字符串。 已在 SQLite / PostgreSQL 16 / MySQL 8 三种方言上实跑升级路径:注入历史的 system_settings 行与分组 overrides 后启动,确认键被清除、分组只剩其余覆盖、 迁移正常记账。 * refactor(settings): 合并上游 Header 到跨域分区,统一控件尺寸与请求头/响应头命名 - 分组页控件尺寸未跟着变小,是因为上一轮的尺寸变量覆盖只挂在 .setting-row/ .setting-block 上;分组页的姓名/验活模型输入框、权重与请求亲和的 SegmentedControl 都不在这两个类名内。改为挂在 .settings__content/.group-settings__content 内容区 (不含侧边导航与保存栏),覆盖 --control-compact/xs/sm/md 四个尺寸变量,让设置页 和分组页的所有交互控件统一收敛到 26px。 - "上游请求改写"分区被删除,header_rules 合并进浏览器访问分区,与 CORS、 下游响应头规则放在一起(顺序:CORS → 上游请求头规则 → 下游响应头规则); 该分区原本只剩 header_rules 一项(inject_usage_options 上一轮已删除), 单独占一个侧边菜单已经没有意义。 - 请求头/响应头命名统一:全局设置页"全局 Header Rules"改名"上游请求头规则", 与已有的"下游响应头规则"对称;分组页"HeaderRules"同步改名"上游请求头规则"。 新分区标题定为"Header 与跨域"。 - 清理合并后失效的 settings.headers.* 键(title/currentPublishedRuleCount/ defaultSource/overrideSource/pendingRestoreSource/override/restoreDefault/ inherited/resetPending/replacementWarning/securityNotice),改用已有的 settings.runtime.* 通用状态词汇,与 CORS、下游响应头规则保持一致。 已用真实浏览器验证:分区合并后的顺序与文案、校验横幅跳转到正确分区并定位到 非法输入框、分组页控件高度与设置页一致。 * refactor(group-settings): 统一请求亲和与上游请求头规则的覆盖交互 请求亲和由三态 SegmentedControl 改为 SettingRow 覆盖/恢复默认模式; 上游请求头规则由 details 折叠改为 SettingBlock,并补上独立的覆盖开关, 与设置页的交互模式完全一致;同步移除废弃的展开态路由状态与文案。 * fix(group-settings): 恢复默认时不再回显未保存的旧覆盖值 分组已保存覆盖值后,草稿中点击恢复默认会读到仍是旧覆盖值的 effective 快照,导致视觉上"看起来没变"。为出站代理、超时/次数类、请求亲和、 上游请求头规则补充待恢复态:展示占位文案与徽标,保存后才回填真实的 全局生效值,与设置页面的重置反馈保持一致。 * feat(group-settings): 验活模型改为可搜索候选输入 复用参数覆盖规则里模型输入的 datalist 模式,把分组当前模型作为候选, 输入即过滤;候选取上游模型 ID(验活按该值请求上游),别名作为副标题 展示。后端不限制该值,仍保留自由输入。 * fix(settings): 按 review 处理迁移账本断言与三处设置项细节 - 外部数据库契约里的迁移账本断言硬编码到 0007,只在 PostgreSQL/MySQL 下 执行,本地 SQLite 会跳过,导致 0008 落库后仅 CI 报错 - 下游响应头规则的待恢复态未取草稿值,取消覆盖后仍回显旧规则,与同区的 上游请求头规则表现不一致 - 连接与可靠性分区的数字输入清空后写入 0,其中重试次数与拉黑阈值的 0 合法, 会被静默保存;改为与路由分区一致按 NaN 处理 - 修正 pendingRestoreSource 的英文文案
GPT-Load
A self-hosted AI gateway for multi-channel, multi-credential setups
API keys, subscription accounts, traffic scheduling, failure handling, request logs, and usage accounting — behind a single entry point.
English · 中文 · 日本語 | Official Website
Sponsors
Sponsor details (collapsible)
![]() |
Protect and accelerate websites and APIs, serving users in mainland China and around the world, and extend acceleration and security capabilities to native/mobile apps through a client SDK — self-built private-deployment CDN | subscription-based high-protection CDN | an independently controllable, flexibly composable CDN network. |
![]() |
Thanks to APIMart for sponsoring this project! APIMart is a low-cost API platform for AI image & video generation — GPT-Image-2 from $0.006/image, 160+ images per dollar. One async API covers both image and video: submit a task, get an ID, fetch results via polling or callback. Batch tens of thousands of images without timeouts, switch models without changing code. Pay-as-you-go with no monthly fee — sign up here to get started. |
Why GPT-Load
Your application only needs one base URL and one AccessKey. Providers, accounts, credentials, models, and routing policy are all configured in the management UI.
- One gateway, native protocols — Manage official APIs, cloud platforms, model services, and compatible relays together while clients keep their OpenAI, Anthropic, or Gemini native interfaces.
- One mechanism for API keys and subscriptions — Codex, Claude, Antigravity, Grok, and API-key channels share credential management, scheduling, and health handling.
- Scheduling and failure isolation built in — Multi-credential scheduling, automatic weighting, retries, cooldown, blacklisting, and session affinity reduce the impact of overloaded or failing credentials.
- Observable, self-hosted, and simple to deploy — Inspect health, routes, logs, usage, and cost estimates in an embedded UI backed by SQLite, MySQL, or PostgreSQL with local credential encryption.
Quick start
Warning
If you are using 1.x, read Moving from 1.x first. 2.0 cannot open, import, or migrate 1.x data in place.
1. Start the service
Requires Docker and Docker Compose.
git clone --depth 1 https://github.com/tbphp/gpt-load.git
cd gpt-load
cp .env.example .env
docker compose up -d
Confirm the service is up:
curl --fail http://127.0.0.1:3001/health
The first start generates a management key. Read it and store it safely:
docker compose exec gpt-load sh -c 'cat /app/data/auth.key'
Open http://127.0.0.1:3001 and sign in to the console with that key.
You can also set
AUTH_KEYexplicitly in.envbefore starting. By default the service listens on the loopback address only and is not exposed to the internet.
2. Initial configuration
Initial setup takes three steps:
- Add a channel — Choose an upstream service and add one or more API keys. For subscription channels, complete the OAuth flow or import credentials as prompted.
- Create a group — Pick a channel, then configure available models and runtime policy.
- Create an AccessKey — Set the groups and client protocols it may use, then give the generated AccessKey to your application.
OAuth callback ports for subscription channels
The Codex, Claude, and Antigravity OAuth clients use fixed callback ports. Compose publishes them on the address configured by HOST, which defaults to 127.0.0.1; setting HOST=0.0.0.0 also publishes these callback ports on all host interfaces. Because the ports are fixed by the upstream clients, only one default Compose instance can run on a host at a time.
When working over SSH or from a remote browser, the browser's localhost may not reach GPT-Load — paste the full callback URL into the authorization dialog to finish the flow.
Screenshots
Groups — View channels, models, credential counts, and health in one place
Subscription accounts — Track account availability, quota windows, reset times, and runtime diagnostics
AccessKey read-only home — Sign in with an AccessKey to view only its own groups, models, requests, usage, and cost allowance
Usage and cost — Review request trends, cache hit rate, token categories, and cost estimates
Scope
Client protocols
| Protocol | Main entry |
|---|---|
| OpenAI Chat Completions | POST /v1/chat/completions |
| OpenAI Responses | /v1/responses and its resource paths |
| OpenAI Images | POST /v1/images/... |
| OpenAI Embeddings | POST /v1/embeddings |
| Anthropic Messages | POST /v1/messages |
| Gemini | /v1beta/models/... |
Each channel declares exactly which protocols and capabilities it can execute. GPT-Load converts between supported capabilities, but it is not a general-purpose any-protocol, any-JSON translator.
Embeddings initially uses the native OpenAI-compatible wire only on the OpenAI, OpenRouter, and OpenAI Compatible API-key channels; subscription channels and protocol conversion are not supported. An AccessKey without a protocol filter keeps its existing “all enabled protocols” behavior and therefore gains Embeddings access after upgrade. Least-privilege deployments should configure an explicit protocol filter.
Built-in channels
- Official and cloud — OpenAI, Anthropic, Gemini, xAI, Azure OpenAI, AWS Bedrock, Google Vertex AI
- Model services — DeepSeek, Moonshot AI, SiliconFlow, Zhipu AI, Alibaba, Volcengine, OpenRouter, Groq
- Subscription — Codex, Claude, Antigravity, Grok
- Custom — OpenAI Compatible (any compatible relay)
Deployment and data
Docker Compose uses application-managed SQLite by default. Data lives in the gpt-load-data named volume and includes the database, auth.key, and encryption.key.
Important
encryption.keydecrypts channel credentials. When backing up or migrating, the database and the key must be kept together. Once the key is lost or replaced, existing encrypted credentials cannot be recovered, and this version does not support master key rotation.
Using an external database
Use the unified DATABASE_DSN to connect SQLite, MySQL, or PostgreSQL:
mysql://user:password@db.example:3306/gpt_load?charset=utf8mb4&collation=utf8mb4_bin
postgres://user:password@db.example:5432/gpt_load?sslmode=require
Common operations:
docker compose logs -f # view logs
docker compose pull && docker compose up -d # update to the latest 2.x image
docker compose stop # stop the service
The official Compose file uses ghcr.io/tbphp/gpt-load:2. Before GA, 2 tracks verified 2.0 Beta and RC releases; after GA, it tracks stable 2.x releases only. Exact image tags omit the Git tag's v prefix (for example, 2.0.0-beta.25), while 2.0-beta remains the 2.0 Beta channel. latest remains on 1.x.
Using a native binary
Download the build for your platform from GitHub Releases, and verify it against the bundled SHA256SUMS first:
chmod +x ./gpt-load-linux-amd64
HOST=127.0.0.1 DATA_DIR=./data ./gpt-load-linux-amd64
Then open http://127.0.0.1:3001. Portable builds are provided for five targets across Linux, macOS (amd64 / arm64), and Windows; gpt-load-windows-amd64.exe keeps running in the foreground as before.
Windows desktop users can instead download gpt-load-windows-setup.exe. After one administrator approval, Setup installs and starts a low-privilege Windows service, enables automatic startup, and creates desktop and Start Menu shortcuts to the GPT-Load management page. Setup displays the generated management key before it finishes; save it before closing the page. The protected copy remains at %ProgramData%\GPT-Load\data\auth.key. Service configuration and its .env live in %ProgramData%\GPT-Load, with persistent data in %ProgramData%\GPT-Load\data.
Installing a newer Setup stops the service gracefully before updating it. Windows uninstall removes the program and service but preserves data. Advanced users can still manage an installed service with gpt-load-windows-amd64.exe service start|stop|restart|status.
Environment configuration
At startup, the application reads .env in the current directory; existing process environment variables take precedence. Unless noted otherwise, changes require restarting the process or container; see .env.example for the common configuration template.
Show all environment variables
| Variable | Default | Description |
|---|---|---|
HOST |
127.0.0.1 |
Native listening address, and the default host address for Compose's main port and OAuth callback ports; Compose always listens on 0.0.0.0 inside the container. |
PORT |
3001 |
HTTP service port, must be 1–65535; Compose also uses it for the container port, host publishing, and health check. |
BIND_ADDRESS |
Empty, inherits HOST |
Compose only; overrides the host publishing address for the main service port without changing OAuth callback ports. |
OAUTH_CALLBACK_BIND_ADDRESS |
Empty, inherits HOST |
Compose only; overrides the host publishing address for the fixed OAuth callback ports 1455, 54545, and 51121. |
GRACEFUL_SHUTDOWN_TIMEOUT |
10 |
Maximum time to wait for requests after a stop signal, positive integer in seconds. |
CONTAINER_STOP_GRACE_PERIOD |
15s |
Docker duration to wait before Compose force-stops the container; should be longer than GRACEFUL_SHUTDOWN_TIMEOUT. |
READ_TIMEOUT |
60 |
HTTP request read timeout, positive integer in seconds. |
IDLE_TIMEOUT |
120 |
HTTP keep-alive idle connection timeout, positive integer in seconds. |
DATA_DIR |
./data |
Directory for the managed database, auth.key, encryption.key, and runtime state; official Compose uses /app/data, while the Windows Setup service uses %ProgramData%\GPT-Load\data. |
DATABASE_DSN |
Empty, uses ${DATA_DIR}/gpt-load.db |
Empty uses application-managed SQLite; non-empty values support SQLite paths or URLs, MySQL URLs, and PostgreSQL URLs, and are treated as operator-managed external databases. Container file paths must be inside a mounted directory. |
DATABASE_MAX_OPEN_CONNECTIONS |
10 |
Maximum open connections for MySQL and PostgreSQL, positive integer. SQLite always uses one connection. |
DATABASE_MAX_IDLE_CONNECTIONS |
5 |
Maximum idle connections for MySQL and PostgreSQL, positive integer and no greater than DATABASE_MAX_OPEN_CONNECTIONS. SQLite always uses one connection. |
AUTH_KEY |
Empty, reads or generates ${DATA_DIR}/auth.key |
Bearer key for the management UI and /api management API, not a data-plane AccessKey. |
ENCRYPTION_KEY |
Empty, reads or generates ${DATA_DIR}/encryption.key |
Encrypts channel credentials; changing or losing it makes existing credentials undecryptable, so back it up with the database. |
HTTP_PROXY |
Empty | Environment proxy for HTTP upstream requests. |
HTTPS_PROXY |
Empty | Environment proxy for HTTPS upstream requests. |
NO_PROXY |
Empty | Comma-separated hosts, domains, or IPs that bypass the environment proxy. |
LOG_LEVEL |
info |
Supports panic, fatal, error, warn, warning, info, debug, and trace; invalid values warn and fall back to info. |
LOG_FORMAT |
text |
Supports text and json; any other value fails startup. |
MODELS_DEV_AUTO_SYNC_ENABLED |
Unset, initial default true |
When unset, uses the persisted management UI setting; when set, forces Models.dev auto-sync on or off and makes the same UI option read-only. |
Environment proxies apply only when no proxy is specified on the credential, group, or global settings.
Production considerations
- The service listens on
127.0.0.1only by default. For remote access, expose it through a controlled network or a TLS reverse proxy, and configure ACLs and firewall rules. - Manage
AUTH_KEYandENCRYPTION_KEYcarefully. Never commit real keys to a repository, log, screenshot, or public issue. - 2.0 is designed for a single application instance. Instances do not share state, so horizontal scaling is not supported.
- Usage and cost are estimates derived from upstream responses. They support operational analysis and capacity planning, and do not equal a provider invoice or a financial reconciliation.
- Subscription channels depend on upstream OAuth and compatibility protocols and may change as upstreams change. Only connect accounts you are entitled to use, and follow each provider's terms.
- In OpenAI Responses, stateful requests relying on
previous_response_id,conversation, or an existing resource ID are only reliable with a single credential, or with an upstream that shares resources across credentials.
Moving from 1.x
Warning
GPT-Load 2.0 is a complete rewrite. It cannot open, import, or migrate 1.x data in place.
Deploy 2.0 with its own database, DATA_DIR, port, and Docker volume. Cut traffic over only after verification, and keep the original 1.x deployment until the rollback window closes. Documentation for the 1.4.x maintenance line is at the official docs.
Open-source dependencies
Some of GPT-Load's capabilities build on these projects, with thanks:
| Project | Role | License |
|---|---|---|
| Bifrost Core | Provider authentication, request/response conversion, streaming, usage normalization | Apache-2.0 |
| CLIProxyAPI | OAuth and execution adapter for subscription channels | MIT |
| Lobe Icons | Channel brand icons in the management UI | MIT |
GPT-Load owns credential storage, account selection, scheduling, retry, health, affinity, logging, and usage policy. Third-party notices are in THIRD_PARTY_NOTICES.md, full license texts in LICENSES/, and each release ships a CycloneDX SBOM covering the Go dependency graph.
Channel icons identify their respective upstream providers. All trademarks belong to their owners; this project is not affiliated with or endorsed by them.
Project support
|
Platform support |
Community support |
Infrastructure support |


