This is a summary of a longer Chinese tutorial on building an OpenRouter proxy gateway on Cloudflare Workers. It shares only the method — no deployed endpoints or credentials.
Why build your own gateway#
The same OpenRouter model is served by several Providers, each with different pricing, implicit-cache support, and stability. OpenRouter’s default scheduling rotates between them, which hurts KV Cache hit rate on long sessions. A thin gateway lets you take control.
What it does#
- Auto-pick the best Provider — on a 3-hour Cron it fetches each model’s endpoints, scores them by
throughput / (effective_input_price × 0.4 + output_price × 0.6), and locks a single Provider for a lock period (measured cache hit rate up to ~98%). - Anti-abuse auth — clients send a custom
CUSTOM_ACCESS_KEY; the gateway swaps it for the realOPENROUTER_API_KEYupstream. - Auto-failover — 429s retry with exponential backoff (2s/4s/8s) without switching; lag/timeout/5xx trips a circuit breaker after N consecutive failures, cools the Provider for 10 min, and re-locks immediately.
It is multi-model: any model is scored and locked on first request, each model with its own lock and breaker.
Architecture#
Cloudflare Worker + KV + Cron, fully OpenAI-compatible (/v1/chat/completions). Cron writes candidates; active requests renew the live lock so long jobs never switch upstream mid-run.
Key design points:
- Locking: candidate + active renewal. Cron only writes candidates; the active lock is renewed in place and only promoted to a new candidate after idle expiry.
- Scoring: effective input price =
hit_rate × cache_read + (1 − hit_rate) × prompt; providers with implicit caching get aCACHE_BONUSmultiplier (default 2). - Time-of-day pricing: OpenRouter’s
overrides(e.g. official DeepSeek off-peak half price) are honored. - 429 vs lag: 429 retries in place (switching loses cache); real lag trips the breaker.
- KV layout (per model):
BEST_PROVIDER,PROVIDER_CANDIDATE,PROVIDER_FAILURE,PROVIDER_COOLDOWN,STATS; plus a globalMODELS_SEEN.
Deploy (outline)#
npm i -D wrangler;npx wrangler login.npx wrangler kv namespace create PROVIDER_KVand put the id inwrangler.toml.npx wrangler secret put OPENROUTER_API_KEYandnpx wrangler secret put CUSTOM_ACCESS_KEY.- Write
wrangler.toml(routecustom_domain = true, Cron0 */3 * * *,[vars]forTARGET_MODEL/HIT_RATE/CACHE_BONUS/MIN_UPTIME/SLOW_THRESHOLD/FAIL_LIMIT/COOLDOWN_SECONDS). npx wrangler deploy; verify withPOST /__cron,GET /stats, and a realPOST /v1/chat/completions.
The full, secret-free src/index.js (Worker logic) and the complete wrangler.toml are in the Chinese version.
Client setup#
Point any OpenAI-compatible client at it:
- Base URL:
https://<your-gateway-host> - API Key: your
CUSTOM_ACCESS_KEY(not the OpenRouter key) - Model: any OpenRouter model id, e.g.
deepseek/deepseek-v4-flash-0731— switching models needs no config change.
Gotchas#
wrangler 4.xuseskv namespace create(space, not colon).routesmust come before[triggers]inwrangler.toml.- OpenRouter’s
/models/{id}/endpointsrejects%2F-encoded slashes — use the raw/. This is the #1 cause of 404s and failed scoring. - Some official endpoints cost ~9× third-party output price; lower
CACHE_BONUS(e.g. 1.2) if output-heavy jobs find third parties cheaper.
Full Chinese version: 自建 OpenRouter 智能网关:自动选最优 Provider、防盗刷、自动容错







