An AI API gateway with a web console, for Codex, Claude Code and other OpenAI- or Anthropic-compatible clients. It runs on Cloudflare Workers, as a Node.js server, or on Vercel.
- Manage AI Gateway, Antigravity, Codex and Claude providers, credentials, client keys and model aliases in the console.
- Route traffic through SOCKS5 proxy groups.
- Track usage, costs and request details, with custom pricing by provider and model.
Keep your deployment’s encryption key safe and unchanged. Never commit it or files containing secrets, such as .env and .dev.vars.
All platforms run the same gateway and console. Every build requires Node.js 24 or newer.
| Cloudflare Workers | Node.js | Vercel | |
|---|---|---|---|
| Database | D1 | SQLite, PostgreSQL or libSQL | PostgreSQL or libSQL |
| Also needs | — | Redis | Redis |
| Console sign-in | Cloudflare Access | OIDC, Cloudflare Access, token | OIDC, Cloudflare Access, token |
| Responses WebSocket | Yes | Yes | No |
libSQL works with Turso or a self-hosted sqld.
| Operation | Application limit |
|---|---|
| HTTP inference on Node.js | 64 MiB |
| HTTP inference on Workers | 16 MiB |
| HTTP inference on Vercel | 4.5 MB (4,500,000 bytes) |
| Antigravity / xAI decoded and translated requests | 16 MiB |
| WebSocket message | 32 MiB |
| Each WebSocket processing buffer, including the active message | 32 MiB / 1024 messages |
| Management API request | 16 MiB |
| Configured search request | 1 MiB |
Inference upload limits apply separately before and after decompression. The effective upload limit is the smaller of the operation budget and the deployment ceiling; Workers use a 16 MiB buffering budget to leave memory for decoded text, parsed JSON and translated requests within their 128 MB isolate limit. Vercel also narrows management requests to 4.5 MB. Reverse proxies and upstream APIs may impose smaller limits. See the Vercel Function limits and Cloudflare WebSocket limits. Response inspection and usage observation have independent 16 MiB budgets; reaching an observation limit does not truncate a forwarded response.
HTTP inference and context-management requests run in a dedicated HttpExecution
Durable Object per request. The entry Worker forwards request and response streams
without parsing them; authentication, routing, provider adapters and usage
observation run inside the object. Existing account, health and session objects
still coordinate requests. WebSocket upgrades keep their existing path.
Each executor accepts one request. Failed dispatches cancel that executor without
resending inference.
Client disconnects cancel the executor through a separate RPC, including before
upstream headers arrive or while response writes are blocked. The executor waits
for pending usage journal writes before completing cancellation.
This moves inference CPU work out of the entry Worker's budget, but active HTTP
streams consume Durable Object duration quota. Deployment adds DO migration v10;
the executor does not write request bodies or tokens to its own storage.
npm install
npm run dev:cloudflareOpen http://127.0.0.1:5173/console/ for the console with hot reload. The gateway endpoint is http://127.0.0.1:8787/v1.
The first run creates a local database and .dev.vars with an encryption key. Keep this key: existing data depends on it.
-
Create the Cloudflare resources:
npx wrangler login npx wrangler kv namespace create CODY_CONFIG_KV npx wrangler d1 create cody npx wrangler queues create cody-usage npx wrangler queues create cody-usage-dlq
-
Put the returned KV namespace and D1 database IDs in wrangler.jsonc.
-
Bind your domain to the Worker and protect the console with Cloudflare Access: create a self-hosted application for the path
console/*and allow your administrator emails. Inwrangler.jsonc, setACCESS_TEAM_DOMAINtohttps://your-team.cloudflareaccess.com,ACCESS_AUDto the application's AUD tag, and keepADMIN_LOCAL_DEV=false. -
Store an encryption key and deploy:
openssl rand -base64 32 npx wrangler secret put CONFIG_ENCRYPTION_KEY npm run deploy:cloudflare
npm run deploy:cloudflare builds the console, applies database migrations and deploys the Worker.
For automatic deployments, connect the repository to Cloudflare Workers Builds and use npm run deploy:cloudflare as the deploy command. The API token needs D1 Edit permission in addition to the Worker permissions.
You need a Redis server. SQLite is the default database; use PostgreSQL or libSQL when running more than one instance.
npm ci
cp .env.example .env
openssl rand -base64 32Edit .env:
CONFIG_ENCRYPTION_KEY: the generated key.REDIS_URL: your Redis server.DATABASE_URL: keep the defaultsqlite:./data/cody.sqlite, or usepostgres://user:password@host:5432/codyorlibsql://your-database.turso.io?authToken=your-token.
npm run build:node
npm run start:nodeOpen http://127.0.0.1:8787/console/. The gateway endpoint is http://127.0.0.1:8787/v1. The default ADMIN_AUTH_MODE=local signs you in automatically and only works while the server listens on 127.0.0.1.
For development with hot reload, use npm run dev:node and open http://127.0.0.1:5173/console/. Keep HOST=127.0.0.1 and PORT=8787 in .env.
Before exposing the server, switch console sign-in to OIDC (see Console sign-in) and set HOST=0.0.0.0.
With Docker:
docker build -t cody .
docker run -d -p 8787:8787 -v cody-data:/data --env-file .env -e DATABASE_URL=sqlite:/data/cody.sqlite codyInside the container, 127.0.0.1 refers to the container itself, so point REDIS_URL at a Redis address the container can reach.
Without Docker, use npm run build:node followed by npm run start:node. To update, run npm run deploy:node, then restart the server.
Behind a reverse proxy that terminates TLS, preserve the public Host header and set X-Forwarded-Proto: https.
You need a PostgreSQL or libSQL database and a Redis server that Vercel can reach. Place them near your function's region.
- Import the repository into Vercel. Select Node.js 24 and leave Root Directory empty.
- Add the environment variables:
CONFIG_ENCRYPTION_KEY: generate withopenssl rand -base64 32.DATABASE_URL: your PostgreSQL or libSQL connection string.REDIS_URL: your Redis server.CRON_SECRET: a random string of at least 16 characters.- Console sign-in variables (see Console sign-in).
- Deploy. Vercel runs
npm run deploy:vercel(set invercel.json), which builds and applies database migrations before release; a failed migration stops the deployment.
Open /console/ on your deployment URL. Keep each preview environment on its own database and REDIS_PREFIX, separate from production.
Vercel supports HTTP only, with a default request timeout of 300 seconds.
For browser sign-in, use any OIDC provider:
ADMIN_AUTH_MODE=oidc
ADMIN_OIDC_ISSUER=https://identity.example.com
ADMIN_OIDC_CLIENT_ID=cody
ADMIN_OIDC_CLIENT_SECRET=your-client-secret
ADMIN_OIDC_ALLOWED_EMAILS=admin@example.com,another-admin@example.comRegister https://your-gateway/console/auth/callback as the redirect URL. The provider must return verified email addresses.
Other modes:
ADMIN_AUTH_MODE=access: behind Cloudflare Access, for example through a Cloudflare Tunnel. SetACCESS_TEAM_DOMAINandACCESS_AUD.ADMIN_AUTH_MODE=token: API access only, withADMIN_TOKENof at least 16 characters sent asAuthorization: Bearer ….
Use a client key created in the console and a model enabled in your published configuration.
Other clients can use the gateway's OpenAI or Anthropic endpoints with a client key, sent as Authorization: Bearer or x-api-key.
Add a provider to ~/.codex/config.toml, replacing base_url with your gateway URL and choosing a configured model:
model = "gpt-5.6-sol"
model_provider = "gateway"
[model_providers.gateway]
name = "Gateway"
base_url = "https://cody.example.com/v1"
wire_api = "responses"
http_headers = { "x-openai-actor-authorization" = "cody" }
[model_providers.gateway.auth]
command = "printenv"
args = ["OPENAI_API_KEY"]
timeout_ms = 5000
refresh_interval_ms = 300000export OPENAI_API_KEY="your-gateway-client-key"
codexexport ANTHROPIC_BASE_URL="https://cody.example.com"
export ANTHROPIC_API_KEY="your-gateway-client-key"
claude --model "your-configured-model"Use npm run data:transfer -- --help to copy business database data and encrypted OAuth accounts between Cloudflare D1, SQLite, PostgreSQL and libSQL. D1 uses Wrangler SQL-file export/import; standard databases use bulk reads and inserts. Runtime caches, health/cooldown state and unrecorded queue/outbox usage are excluded. Both deployments must use the same code, applied schema and CONFIG_ENCRYPTION_KEY; the target must be fresh.
Stop requests and background jobs on both sides before confirming the CLI prompt. Progress is kept locally for --resume or --abort; no database migration or runtime maintenance lock is added. D1 transfers also require the sqlite3 CLI. Start a new task for this workflow; older task files are not supported. See the transfer guide for setup and cutover.
npm test
npm run typecheck
npm run lint
npm run format:check