This is a simple proxy for AI services.
This project is sponsored by ChatWise, the fastest AI chatbot that works for any LLM.
Replace your API domain with the domain of the proxy deployed on your server. For example:
- Gemini:
- from
https://generativelanguage.googleapis.com/v1beta - to
https://your-proxy/generativelanguage/v1beta
- from
- OpenAI:
- from
https://api.openai.com/v1 - to
https://your-proxy/openai/v1
- from
- Anthropic:
- from
https://api.anthropic.com/v1 - to
https://your-proxy/anthropic/v1
- from
- Groq:
- from
https://api.groq.com/openai/v1 - to
https://your-proxy/groq/openai/v1
- from
- Perplexity:
- from
https://api.perplexity.ai - to
https://your-proxy/pplx
- from
- Mistral:
- from
https://api.mistral.ai - to
https://your-proxy/mistral
- from
- OpenRouter:
- from
https://openrouter.ai/api - to
https://your-proxy/openrouter
- from
- xAI:
- from
https://api.x.ai - to
https://your-proxy/xai
- from
- Cerebras:
- from
https://api.cerebras.ai - to
https://your-proxy/cerebras
- from
- fal.ai:
- from
https://fal.run(sync inference) tohttps://your-proxy/fal - from
https://queue.fal.run(queue) tohttps://your-proxy/fal-queue - from
https://api.fal.ai(platform API) tohttps://your-proxy/fal-api - from
https://rest.fal.ai(realtime tokens, JWKS) tohttps://your-proxy/fal-rest - from
https://v3.fal.media(file CDN) tohttps://your-proxy/fal-media - from
wss://ws.fal.run(HTTP-over-WebSockets) towss://your-proxy/fal-ws
- from
- Kling AI:
- global: from
https://api-singapore.klingai.comtohttps://your-proxy/kling - China: from
https://api-beijing.klingai.comtohttps://your-proxy/kling-cn
- global: from
- Black Forest Labs (FLUX):
- from
https://api.bfl.aitohttps://your-proxy/bfl - EU region: from
https://api.eu.bfl.aitohttps://your-proxy/bfl-eu - US region: from
https://api.us.bfl.aitohttps://your-proxy/bfl-us
- from
- ElevenLabs:
- from
https://api.elevenlabs.iotohttps://your-proxy/elevenlabs - EU residency: from
https://api.eu.residency.elevenlabs.iotohttps://your-proxy/elevenlabs-eu - India residency: from
https://api.in.residency.elevenlabs.iotohttps://your-proxy/elevenlabs-in
- from
- Authentication headers are passed through as-is: fal.ai
Authorization: Key ..., KlingAuthorization: Bearer <JWT>(signed client-side from AccessKey/SecretKey), BFLx-key, ElevenLabsxi-api-key. - WebSocket endpoints are proxied transparently by the Node server (
server.ts) via raw upgrade passthrough: falwss://your-proxy/fal-ws/{model_id}andwss://your-proxy/fal/{app}/realtime, ElevenLabs realtime TTS/STT and Agents viawss://your-proxy/elevenlabs/.... Deployments that runmain.tson other runtimes (e.g. edge workers) do not get WS support. - Running behind an egress HTTP proxy (e.g. a local VPN): WebSocket passthrough honors
https_proxyautomatically (CONNECT tunnel, includinguser:pass@Basic auth andhttps://proxies); for regular HTTP routes setNODE_USE_ENV_PROXY=1(Node 24+) sofetchhonors it too. - Some responses contain absolute upstream URLs which bypass the proxy when followed: fal queue
status_url/response_url/cancel_url, BFLpolling_url(may point to a regional cluster), result file links (fal.media, BFL delivery URLs, Kling CDN). - Webhooks (fal
?fal_webhook=, Klingcallback_url, BFLwebhook_url) are delivered by the provider directly to your callback host, not through this proxy. - Long-running synchronous requests are supported: up to 10 minutes for
/fal(sync video generation) and 5 minutes for/elevenlabs(speech-to-text on long audio). Prefer the queue/async APIs in production.
Extra routes can be added without a code change via the EXTRA_PROXIES environment variable:
EXTRA_PROXIES='[{"pathSegment":"foo","target":"https://api.foo.example","timeout":120000}]'By default the proxy is open (anyone who can reach it can use it). Set PROXY_AUTH_TOKEN to require a shared secret on every request (HTTP and WebSocket) in the x-proxy-token header; the header is stripped before forwarding. The root path / stays open for health checks.
Set
PROXY_AUTH_TOKENwhenever the proxy is reachable by anyone but you. Without it,/custom-model-proxyis an open relay that anyone can use to send requests through your server, and the path-prefix routes will spend your upstream API quota for them.
| Env | Default | Purpose |
|---|---|---|
PROXY_AUTH_TOKEN |
(unset, open) | Shared secret required in the x-proxy-token header. |
MAX_BODY_BYTES |
104857600 (100 MB) |
Reject request bodies larger than this with 413 (caps memory/bandwidth abuse). |
WS_IDLE_TIMEOUT_MS |
600000 (10 min) |
Close WebSocket tunnels with no traffic for this long (frees abandoned sockets). |
CUSTOM_MODEL_PROXY_ALLOW_PRIVATE |
(unset) | When 1, lets /custom-model-proxy reach private/loopback addresses. Leave unset in production. |
/custom-model-proxy relays to an arbitrary ?url=. It only accepts http(s) and, unless CUSTOM_MODEL_PROXY_ALLOW_PRIVATE=1, refuses targets that resolve to loopback, link-local, cloud-metadata or RFC1918 addresses (SSRF protection). The path-prefix routes are restricted to their configured upstreams.
Use the hosted API, for example OpenAI https://ai-proxy.chatwise.app/openai/v1
Deploy this as a Docker container, check out Dockerfile:
docker build -t ai-proxy .
docker run -d --name ai-proxy --restart unless-stopped \
-p 3000:3000 \
-e PROXY_AUTH_TOKEN=change-me \
ai-proxyThe image has a built-in health check on /.
bun install
bun run dev # dev server with reload (tsx, node runtime)
bun test # test suite (incl. e2e of the production build)
bun run typecheck # tsc --noEmit
bun run format # prettierMIT.