freebuff-proxy is a local gateway that makes the AI coding models behind Codebuff/FreeBuff available to any tool that speaks the OpenAI API: OpenCode, pi, 9router, LiteLLM, or your own scripts.
Your coding tools expect an OpenAI-style endpoint (/v1/chat/completions). The upstream service is not OpenAI-shaped: it is a CLI coding agent with its own session protocol, and its free-tier access is tied to per-account tokens that carry individual daily quotas and can be rate-limited or banned. freebuff-proxy sits between the two and absorbs that friction:
- Translates: rewrites standard OpenAI requests into the upstream session protocol (CLI request envelope, model-bound agent runs, tool-schema normalization) and streams the SSE response back as OpenAI
chat.completion.chunkevents. - Pools: routes requests across multiple tokens (hot-session-first with round-robin start and failover), so a busy client or router rides out per-account quotas instead of failing.
- Stealths: makes egress look like a real browser (TLS fingerprints, header sanitization, request jitter) so upstream abuse detection is less likely to flag your account (see the ToS warning below).
⚠️ Terms-of-service risk. Using your FreeBuff token through this proxy conflicts with FreeBuff/Codebuff terms of service; upstream abuse detection can suspend or permanently ban accounts. UseSAFE_MODE=true, keep usage modest, and do not run unattended 24/7. See Getting Started.
⚠️ Honest expectations. FreeBuff's servers are strict, and this proxy reduces ban risk; it does not eliminate it. Nothing here can guarantee your account is never flagged or banned. Upstream detection is documented in the open-source FreeBuff client: per-request IP scoring (VPN/proxy/Tor/hosting egress → limited tier or terminalcountry_blocked), per-account trust levels with sticky caps (third-party-client flag, shared signup network, shared mailbox), daily spend ceilings ($0.50/day for restricted cohorts), and mass sweeps against known farm shapes (6,699 of 7,129 disposable-email accounts were already banned when the blocklist was compiled). This project is a local adapter that exposes FreeBuff's models as an OpenAI-compatible API for other coding agents (OpenCode, pi, hermes, openclaw, or any client that supports a custom endpoint). Your auth tokens are handled automatically by the gateway, which reimplements the official CLI's wire protocol (~99% parity); it is not the official client, and upstream changes can break it until adapted. Keep usage modest and follow the hygiene rules below; further improvements to session handling and ban avoidance are planned.
- New here? Start here
- Requirements
- Features
- How It Works
- Key Concepts
- Quick Start
- Command-Line Interface
- Configuration Reference
- Deployment
- Guides
- Contributing & Security
- Contact & Support
- License
Freebuff-proxy makes the free AI models behind the FreeBuff/Codebuff CLI available to any OpenAI-compatible tool (Cursor, VS Code Continue/Cline, OpenCode, pi, 9router, Chatbox, LibreChat).
If you are a beginner, you don't need to write code or compile anything:
- Download the pre-built Release: Go to Releases and download the ZIP for your OS (e.g.
freebuff-proxy_..._windows_amd64.zip). (Do not use the green "Code -> Download ZIP" button, which is raw source code). - Extract & Double-Click: Unzip the folder.
- Windows: Double-click
start-proxy.cmd. - Linux / macOS: Open terminal in the extracted folder and run
./start-proxy.sh.
- Windows: Double-click
- Log in: When prompted, press Enter to open your browser and sign in with your FreeBuff/GitHub account. Your token is saved automatically!
- Open Web Dashboard: Open http://localhost:3457/admin in your browser to view your live status, test chat, and manage tokens visually.
- Connect your tool: In Cursor, VS Code Continue/Cline, Chatbox, or OpenCode, set:
- Base URL:
http://localhost:3457/v1 - API Key:
not-needed - Model:
deepseek/deepseek-v4-flash(full-tier only; limited-tier accounts are coerced tomimo/mimo-v2.5) (See Client Integration Guide for 1-click config snippets).
- Base URL:
Before you start, the rules (what you should / shouldn't do):
| ✅ Do | ❌ Don't |
|---|---|
| Use one key until it is rate-limited; the pool drains it naturally | Don't rotate many healthy keys; it looks like account farming |
| Use a normal residential connection | Don't use a VPN / proxy / Tor (Cloudflare TCP-layer GeoIP + MaxMind/Spur ASN detection → restricted cohort or country_blocked) |
| Register with a real email (e.g. Gmail) | Don't use temp-mail (documented ban cohort: 6,699 of 7,129 accounts already banned) |
| Request only models your tier/region offers (default Flash) | Don't request out-of-region models: refused/downgraded and correlated with your IP's geo |
Read a 429 as quota, resets Pacific midnight | Don't confuse it with a ban; only 403banned/country_blocked is terminal |
| Expect reduced risk, not immunity | Don't run unattended 24/7 or expect zero ban risk |
| Keep the pool draining one key at a time | Don't hammer many tokens from one public IP (ip_capped) |
Access Tiers & Upstream Models. FreeBuff determines your access tier via Cloudflare TCP-layer GeoIP (not HTTP headers — spoofing is impossible). A residential IP in a Tier-1 country (US, UK, DE, JP, CA, etc.) gets accessTier: "full" with all premium models available (5 premium sessions/day base). Non-Tier-1 country IPs get accessTier: "limited" where mimo/mimo-v2.5 (MiMo 2.5) is the sole active model.
📢 Official Freebuff Upstream Notice (vendor snapshot 2026-08-23): "GPT-5.6 Luna is 3 sessions a day. V4 Pro and Flash use your daily sessions; MiMo is unmetered. —❤️ Freebuff Team" (DeepSeek models remain unavailable during weekday peak hours; Beijing-weekend Saturdays/Sundays are always off-peak.)
| Category | Model Name | Wire Model ID | Specs & Upstream Quota Policy |
|---|---|---|---|
| Premium | DeepSeek V4 Flash 07/31(Recommended) | deepseek/deepseek-v4-flash | Smart & Fast, Reasoning: high, NEW. 5 sessions/day premium pool. |
| Premium | GPT-5.6 Luna | openai/gpt-5.6-luna | Strong all-around, Reasoning: high, Images. 3 sessions/day limit (raised from 1 → 2 → 3 in the Aug 21–23 vendor snapshots). |
| Premium | DeepSeek V4 Pro | deepseek/deepseek-v4-pro | Deep reasoning, Reasoning: high. Per-model cap removed upstream (Aug 23 snapshot) — draws from the shared daily premium pool; weekday peak-hour pauses lifted. |
| Unlimited | MiMo 2.5 | mimo/mimo-v2.5 | Balanced, Images. Unlimited across all tiers. |
| Referral | GLM 5.2 | z-ai/glm-5.2 | Top open-source agentic model. Referral-gated (+1 session/referral). |
| Disabled | MiniMax M3 | minimax/minimax-m3 | Temporarily Unavailable upstream due to server-side cost spikes. |
Full detail in Key Hygiene & Ban Avoidance.
For a guided walkthrough, read Getting Started (5 minutes).
| Requirement | Details |
|---|---|
| A FreeBuff/Codebuff account | Free account at codebuff.com / freebuff.com. The proxy relays your account's token; each account has its own daily session quota. |
A token (cb_...) | From the official CLI login or scripts/gen-token.*. See Obtain an Auth Token. |
| OS | Linux, macOS, or Windows (amd64/arm64). Prebuilt release binaries; no Go toolchain needed. |
| Docker | Optional: only for the container deployment path (docker compose up -d --build). |
| Network | Outbound HTTPS to codebuff.com (configurable via UPSTREAM_BASE_URL); the proxy listens on loopback 127.0.0.1:3457 by default. |
| Go 1.26+ | Only if building from source. |
- OpenAI-Compatible API:
POST /v1/chat/completions(stream + non-stream),POST /v1/responses,POST /v1/messages(Anthropic shape) +/v1/messages/count_tokens,POST /v1/embeddings(unsupported →400 unsupported_endpoint),GET /v1/models,GET /healthz, PrometheusGET /metrics, and hot config reload viaPOST /admin/reload. - Admin Dashboard: embedded single-binary web UI at
http://<host>:3457/admin: a modern Svelte 5 + Tailwind CSS v4 single-page application built with self-hosted IBM Plex Sans & IBM Plex Mono typography and an "instrument panel" operational design. Features a live overview with 6 KPIs and token risk cards, runtime token pool & quota management with in-browser OAuth device login, served models catalog, hot-reloading.envConfiguration Studio, in-memory structured log viewer with level filtering, and universal 1-click client setup snippets. Zero external CDN or runtime Node.js dependency. - Dynamic Reasoning Effort: OpenAI
reasoning_effort(low/medium/high/max) and Codex/Anthropicreasoning.effortare normalized and mapped to upstream reasoning engines. - Session & Run Lifecycle: Upstream session handshakes, model-lock recovery (
DELETE→ re-POST), grace draining, and idle-run finishing, all automatic. - Token Pooling & Bridge Mode: Hot-session-first pooling with round-robin start and failover across
AUTH_TOKENS, or zero-storage relay when clients bring their own token. See Key Concepts. - Token Auto-Discovery: With empty
AUTH_TOKENS, credentials are read from the official CLI login files (~/.config/manicode/credentials.json,~/.config/codebuff/credentials.json). Disable withAUTO_DISCOVER_TOKEN=false. - TLS Stealth: browser TLS fingerprinting via uTLS (Chrome, Firefox, Safari, Edge) plus sanitized request headers so upstream traffic reads as a browser client.
- CLI Impersonation: egress presents as the official FreeBuff CLI —
Freebuff-CLI/1.0.0ads-API User-Agent with a Chrome/124 body UA,ai-sdk/openai-compatible/1.0.0/codebuffchat UA, Bun/1.3.14 on session/auth endpoints, and your real device timezone/locale. - Subagent-Ready Concurrency: Single-flight session refresh prevents race conditions during high-volume tool-calling loops.
- Safe Mode: On by default: anti-ban presets (TLS stealth, header sanitization, jitter, idle rotation).
- Operational Tooling:
-doctordiagnostics (config, port, DNS/TLS, registry; zero-cost per-token validity probes run by default),-test-token(zero-cost probe on the first token, prints live quota, exit 0/1 for installers and scripts),-setupinteractive client configuration, and a SHA-256-verified-updateself-updater. - Quota Transparency: Live per-model quota (from the upstream
rateLimitsByModeladmission payload) is surfaced inGET /healthz(per-tokenquotamap) andGET /metrics(freebuff_proxy_quota_recent/freebuff_proxy_quota_limitgauges).
One chat request, end to end:
- Your tool calls the proxy. It POSTs a standard OpenAI request to
http://127.0.0.1:3457/v1/chat/completions, same shape it would send to any OpenAI-compatible endpoint. - A token is chosen. The proxy prefers the token that already holds a live session (hot-session-first), starting from a round-robin index and skipping tokens in cooldown or locked by a rate limit; in bridge mode it uses the token your client sent in its
Authorizationheader. - The request is translated. The model id is resolved through the catalog to the upstream agent that runs it, the message list is sanitized and re-wrapped in the CLI request envelope, and OpenAI extras (
reasoning_effort, tool schemas, etc.) are mapped to what upstream expects. - It goes out stealthily. The upstream call uses a browser-like TLS handshake and sanitized headers.
- The stream comes back translated. The upstream SSE stream is converted into OpenAI
chat.completion.chunkevents and relayed to your client in real time. - State is cleaned up. When the request finishes, the run is drained; once a run or token ages out (rotation interval, idle timeout), it is rotated or finished so the next request starts clean. A token that hit a quota limit (
429) is locked locally until its reset time. The proxy answers429+Retry-Afteritself, with no traffic sent upstream.
The translation layer reimplements the official CLI's wire protocol and session lifecycle, sourced from the open-source Freebuff client (Apache-2.0). It changes when the upstream changes. The translation lives in internal/convert, internal/upstream, internal/stealth, and internal/registry.
graph TD
Client[AI Client / Router<br/>OpenCode · pi · 9router · LiteLLM] -->|POST /v1/chat/completions| Proxy[freebuff-proxy<br/>localhost:3457]
Proxy -->|1. Session & Run Lifecycle| Pool[Token Pool & Session Cache]
Proxy -->|2. Inject Envelope + Stealth| Upstream[Upstream Backend API]
Upstream -->|3. SSE Stream| Proxy
Proxy -->|4. OpenAI SSE Chunks| Client
Client -.->|GET /metrics · GET /healthz · POST /admin/reload| Proxy
| Concept | What it means |
|---|---|
| Token | One FreeBuff/Codebuff account credential (cb_...). Each token has its own daily quota and can be rate-limited or banned independently. |
| Session | Per-token upstream admission state (handshake, model locks). The proxy maintains and reuses it so every request does not pay the handshake cost. |
| Run | One upstream agent execution for a model, shared across many requests. Runs start on first use, live for ROTATION_INTERVAL (default 6h), then are rotated (fresh start, old one drained/finished) so no run accumulates suspiciously long-lived activity. Idle tokens get their runs finished too. |
| Model | A catalog entry addressed as provider/model (e.g. deepseek/deepseek-v4-flash). The registry serves /v1/models and maps each model to the upstream agent that runs it. |
| Pooled mode | You configure several tokens in AUTH_TOKENS. Requests stick to the token with a live session and fail over only when it is rate-limited or errors: a reactive drain, not aggressive rotation. Best for one user with several accounts who wants maximum uptime and quota headroom. |
| Bridge mode | You configure no tokens. Each client sends its own token as Authorization: Bearer <token>, and the proxy relays with it, caching per-client state (LRU, max 32). Best for a shared router (e.g. 9router) serving many users who each bring their own account. |
| Safe mode | Default-on anti-ban presets: TLS stealth, proxy-header sanitization, request jitter, and idle rotation. See Safe Mode. |
| Quota lock | When a token hits its daily limit, the proxy parses the upstream 429 reset timestamp and refuses local requests for that token until reset, fast (<1ms), silent, and spam-free. |
One-command installer (Linux/macOS):
curl -sSL https://raw.githubusercontent.com/trefeon/freebuff-proxy/main/scripts/install-freebuff-proxy.sh | bashWindows (PowerShell):
irm https://raw.githubusercontent.com/trefeon/freebuff-proxy/main/scripts/install-freebuff-proxy.ps1 | iexThe bash installer prompts for an install method (easy, manual binary, Docker Compose, bridge mode); both installers mint/read your token and write .env.
Alternatively, run with Docker Compose:
cp .env.example .env # then set AUTH_TOKENS
git fetch --tags 2>/dev/null ||true
VERSION=$(git describe --tags 2>/dev/null ||echo dev) docker compose up -d --buildOr download a release binary from Releases (Linux/macOS/Windows × amd64/arm64), unzip it, right-click the extracted folder → Open in Terminal, and run ./start-proxy.sh (Windows: .\start-proxy.cmd; the .cmd wrappers bypass the PowerShell execution policy). The bundled scripts also include a headless token generator (gen-token.sh / gen-token.cmd).
Generate one headlessly (opens a browser OAuth login). Run with no flags for an interactive menu; the recommended default (Enter) appends the token to .env, auto-creating it from .env.example if missing:
Windows (PowerShell / CMD):
.\scripts\gen-token.cmd# menu; Enter = append to .env (auto-create)Linux / macOS (bash):
./scripts/gen-token.sh # menu; Enter = append to .env (auto-create)gen-token.* also supports explicit modes that skip the menu: --clipboard / -ToClipboard, --save / -Save (store in the CLI credentials file), --append / -Append (add to .envAUTH_TOKENS), and --env <path> / -EnvFile <path>.
Alternatively, log in with the official CLI (npm i -g freebuff && freebuff): the proxy auto-discovers the token from its credentials file on startup.
Copy the example and set your token:
cp .env.example .env
# AUTH_TOKENS=cb_xxx ← paste your token (comma-separate for pooling)# SAFE_MODE=true ← default (set false to disable)Leave AUTH_TOKENS= empty for bridge mode (clients bring their own tokens). Not sure which to pick? One user with a few accounts → pooled mode; a shared router serving many users → bridge mode. See Key Concepts. config.example.json shows the common keys in JSON form, loaded with -config; the Configuration Reference below documents every key. Its cb_xxx/cb_yyy auth placeholders are deliberately rejected by validation — edit the file with real token values before passing -config.
./freebuff-proxy # or: docker compose up -dCheck health and run diagnostics:
curl http://127.0.0.1:3457/healthz
./freebuff-proxy -doctor # config, port, DNS/TLS, registry, plus zero-cost per-token validity probes
./freebuff-proxy -test-token # zero-cost probe on the first token (no session claimed); prints live quota, exit 0/1| Flag | Description |
|---|---|
| (none) | Run the proxy |
-config <path> | Load an optional JSON config file (keys mirror env names) |
-v | Verbose (debug) logging |
-version | Print version and exit |
-doctor | Run configuration and environment diagnostics: config, port, DNS/TLS reachability, model registry, plus a zero-cost validity probe per token |
-test-token | Probe the first configured token with a zero-cost upstream GET probe (no session claimed); prints token OK and live quota, exits 0, or exits 1 (for installers/scripts) |
-update | Self-update from the latest GitHub release (SHA-256 verified against checksums.txt) |
-setup | Interactive client setup (detects installed clients) |
-yes | Auto-confirm -setup prompts |
-refresh-token N | Re-authenticate token #N in .env via the headless GitHub login flow and exit. Interactive: prints a login URL and polls. With -yes and GITHUB_USER / GITHUB_PASSWORD / GITHUB_TOTP set: protocol login |
-install-service | Register the current binary as a background service and start it: Task Scheduler on Windows (per-user, no admin), systemd --user unit on Linux, launchd LaunchAgent on macOS. Runs from the executable's directory so .env resolves, and auto-starts on logon/boot |
-uninstall-service | Stop and unregister the background service (idempotent) |
-service-status | Check whether the service is registered and running; exits 0 when registered, 1 when not (scriptable) |
All keys can be set via environment variables or the JSON config file passed to -config (AUTO_DISCOVER_TOKEN is environment-only); a local .env file (if present) is also read, and for the keys it covers it behaves like the environment. Precedence, lowest to highest: built-in defaults < JSON -config < ./.env < environment. List values (AUTH_TOKENS, API_KEYS, MODELS_ALLOW) are comma-separated in env and arrays in JSON (MODELS_ALLOW also accepts a plain comma-separated JSON string).
| Environment Variable | Default | Description |
|---|---|---|
LISTEN_ADDR | 127.0.0.1:3457 | Host and port to bind (loopback; containers set :3457) |
UPSTREAM_BASE_URL | https://codebuff.com | Upstream API endpoint (normalized to www.codebuff.com) |
AUTH_TOKENS | "" | Comma-separated upstream tokens (empty = bridge mode) |
MODELS_HIDE_UNAVAILABLE | false | /v1/models prunes models marked unavailable (region/tier demotion, quota exhaustion) so picker clients cannot select them; off by default so a stale signal never hides a working model |
MODELS_ALLOW | "" | Comma-separated model allowlist (JSON array or string). When set, only these model ids are served — /v1/models lists only them, and chat/messages/responses requests whose resolved model (after alias resolution) is not listed are rejected with 404 model_not_found ("model not allowed by MODELS_ALLOW"). Empty = all models allowed |
AUTO_DISCOVER_TOKEN | true | When AUTH_TOKENS is empty, read credentials from the official CLI login files (false disables) |
API_KEYS | "" | Comma-separated client keys required for /v1/* (empty = open; ignored in bridge mode) |
ADMIN_TOKEN | 123456 | Login password for the admin dashboard and the bearer token POST /admin/reload requires. Defaults to the factory password 123456 (a startup warning is logged and the dashboard shows a change banner until you rotate it): change it before exposing the port — while the factory default is active, sensitive dashboard routes (config editor, logs, token management, reload) additionally require a loopback client |
ROTATION_INTERVAL | 6h | Agent-run rotation interval |
REQUEST_TIMEOUT | 15m | Upstream request timeout |
SESSION_CALL_TIMEOUT | 30s | Session call timeout |
REGISTRY_REFRESH | 6h | Model catalog refresh interval |
COST_MODE | free | free (free-tier) or paid billing mode |
ACTING_USER_ID | "" | Optional FreeBuff account id; sent on every chat call as x-freebuff-acting-user-id. BAN RISK: only the token's own account id is safe (the CLI derives it from GET /api/v1/me; the server honors the header only for the FreeBuff Web service account) — any other value impersonates another user. Pre-rename name USER_ID still works. Empty = header omitted |
TLS_FINGERPRINT | auto | auto, chrome120, chrome126, safari17, safari18, firefox120, firefox128, edge126, random |
DEBUG_DUMP | false | Persist redacted traffic dumps to ./dump/ (mode 0600) |
LOG_FILE | "" | Append log lines to a file (e.g. ./logs/proxy.log) |
LOG_LEVEL | info | debug, info, warn, error, trace (trace = wire-level bodies) |
LOG_FORMAT | text | text (key=value, colored) or json (one JSON object per line) |
LOG_ACCESS | true | Log one access line per HTTP request (false disables; /healthz, /metrics, OPTIONS are rate-limited to 1/min regardless) |
LOG_RING_SIZE | 500 | In-memory log ring for /admin/logs (50–5000) |
MAX_MESSAGES_PER_DAY | 0 | Per-token daily cap on successful chats (0 = unlimited, default; the upstream 429 lock is the real enforcement) |
IDLE_ROTATION_TIMEOUT | 0 | Finish runs after this idle period (0 = disabled; SAFE_MODE sets 30m when unset) |
SESSION_IDLE_END | 0 | End upstream sessions after this idle period, releasing the token's daily admission slot while the proxy sits unused; the next request re-admits and consumes a fresh slot (0 = disabled, opt-in) |
QUOTA_FALLBACK_MODELS | flash→mimo, glm→flash, luna→flash | Map model → fallback when its session quota is exhausted/unentitled. Defaults: deepseek/deepseek-v4-flash=mimo/mimo-v2.5, z-ai/glm-5.2=deepseek/deepseek-v4-flash, openai/gpt-5.6-luna=deepseek/deepseek-v4-flash (luna degrades the scarce premium session locally instead of hammering quota 429s; #203) |
SAFE_MODE | true | Apply anti-ban presets (see below; set false to disable) |
REQUEST_JITTER | 0s | Random delay range [0, REQUEST_JITTER) before upstream calls (SAFE_MODE sets 2s when unset) |
CLI_VERSION | 0.10.7 | Informational only: parsed and shown on the admin dashboard (Configuration Studio). No wire impact — the chat UA is pinned to ai-sdk/openai-compatible/1.0.0/codebuff, the ads UA to Freebuff-CLI/1.0.0, and session/auth endpoints default to Bun/1.3.14 |
MODEL_ALIASES | "" | Map aliases to real model IDs, e.g. gpt-4o:deepseek/deepseek-v4-pro. When unset (or empty / parsing to no pairs) the built-ins apply: deepseek-chat → deepseek/deepseek-v4-flash, gpt-4o → deepseek/deepseek-v4-pro, claude-3-5-sonnet → anthropic/claude-fable-5. A non-empty value with ≥1 valid pair REPLACES the defaults entirely; the built-ins cannot be disabled (there is no way to express an empty alias map) |
TRANSIENT_RETRIES | 1 | Max additional attempts after a transient transport failure; 0 disables |
SESSION_PERSIST | false | Persist session state AND active agent runs to disk so a restart resumes them instead of re-creating (new daily slot / re-START) |
SESSION_STATE_FILE | .freebuff-session-state.json | Path of the session state file (used when SESSION_PERSIST=true; token-keyed, 0600) |
SESSION_RE_ADMIT_LEAD | 60s | Re-admit a session pre-emptively when less than this remains: the request rides the old session while the refresh runs in the background |
SESSION_PROBE_CACHE_TTL | 15s | Reuse the last successful session state (skip redundant session poll GETs) within this window |
SESSION_CREATE_MAX_PARALLEL_GLOBAL | 128 | Cap on concurrent in-flight session admissions (wait-or-503) |
SESSION_CREATE_MAX_PARALLEL_PER_MODEL | 32 | Per-model cap on concurrent in-flight session admissions |
RUN_FINISH_QUEUE_SIZE | 64 | Bounded deferred-FINISH worker queue for rotated/drained runs |
RUN_FINISH_INLINE_TIMEOUT | 250ms | Synchronous inline FINISH fallback bound when the finish queue is full |
RUNS_DRAIN_QUEUE_CAP | 64 | Draining-runs list cap; older entries are force-dropped (FINISH is best-effort) |
RUNS_DRAIN_TTL | 10m | Draining-runs TTL eviction window |
HTTP2_UPSTREAM | true | Negotiate HTTP/2 with the upstream so the ALPN matches real browsers; false forces HTTP/1.1 |
FALLBACK_MODEL | "" | Map model1=fallback1,model2=fallback2 to re-route a request to the fallback model when its queue wait passes FALLBACK_AFTER_MS (queue-wait only — never on 429 quota exhaustion). When unset, built-in defaults apply: the premium rows → deepseek/deepseek-v4-flash, meta/muse-spark-1.2-contributor → deepseek/deepseek-v4-pro |
FALLBACK_AFTER_MS | 10000 | Queue-wait threshold (ms) before falling back to FALLBACK_MODEL |
CORS_ALLOWED_ORIGIN | * | Access-Control-Allow-Origin for /v1/* responses |
ADOPT_CLI_SESSION | false | Adopt the upstream CLI's active session instead of creating a new one |
WAITING_ROOM_CHAIN | false | After an upstream 428 waiting_room_required, fire the reference ad-chain (POST /api/v1/ads per provider) + GET /api/v1/freebuff/streak before the next session create (issue #94(b), gated stub — best-effort, never blocks the request; not a queue-across-tokens mechanism) |
WEBHOOK_URL | "" | Best-effort alert POSTs for exactly two events: pool_exhausted (all tokens rate-limited) and token_banned (issue #48; empty = disabled; at most one POST per event type per 5m, never blocks the request path) |
RATE_LIMIT_PER_IP | 0 | Requests/second allowed per client IP (0 = disabled; e.g. 20) |
RATE_LIMIT_BURST | 0 | Burst request capacity per client IP (0 = default 2 * RATE_LIMIT_PER_IP) |
When SESSION_PERSIST=true, the state file stores a SHA-256 hash of each
active token plus its session metadata (instance id, expiry, tier/country)
and its active agent runs (run id, agent, trace session id), including
bridge-mode client tokens, since every session manager shares the one store.
A restart adopts the persisted session and runs without re-creating them.
The raw token is never written, and the file is created with mode
0600. Leave SESSION_PERSIST unset (or false) to opt out entirely.
SAFE_MODE=true is the default for all setups (set SAFE_MODE=false to
opt out). It enables essential anti-ban protections and presets:
- JA3 TLS Stealth: Mimics real browser handshakes (Chrome 120/126, Safari 17/18, Firefox 120/128, Edge 126) via
uTLSto prevent WAF / CDN bot detection. - Proxy Header Sanitization: Strips 25 proxy-identifying headers (
X-Forwarded-For,Via,CF-Connecting-IP, etc.). - Request Jitter: Injects randomized 0-2s delay jitter to break robotic, machine-like cadence.
- Idle Rotation: Finishes runs after 30 minutes of inactivity.
- Daily Cap (optional):
MAX_MESSAGES_PER_DAYdefaults to0(unlimited). The upstream429lock is the real enforcement; see below.
- Use one key until it is rate-limited. The pool prefers the token that already holds a live session (hot-session-first) and only fails over when a token hits its quota or errors. It does not aggressively round-robin healthy keys. Letting one account run until its daily quota is natural usage; rotating many healthy keys in rapid succession looks like account farming and can trigger upstream ban detection.
- Do not route through a VPN. FreeBuff resolves access tier via Cloudflare TCP-layer GeoIP
(not HTTP headers —
X-Forwarded-For/CF-Connecting-IPspoofing is impossible at L4). VPN/datacenter IPs are detected via MaxMind/Spur Intelligence ASN databases (ipPrivacySignals: ["vpn"]) and placed in a restricted cohort with a $0.50/day spend ceiling. Commercial VPNs (NordVPN, ExpressVPN), datacenter VPS (AWS, DO, Hetzner), and Tor all trigger this detection. The proxy's stealth settings mask TLS fingerprints and proxy headers; they do not change your public IP. Use a normal residential connection. - Do not hammer many tokens at once from the same public IP. Upstream caps how many
distinct users can hold an active free session on one egress IP (
ip_capped, 429), and accounts created from the same signup network (≥8 per /24) or mailbox (≥3) are permanently capped at lower trust levels. Documented ban cohorts include single-IP rings and same-day account mints. The pool already drains keys one at a time; do not add aggressive rotation on top. - Only request models your account's tier and region actually offers. Out-of-tier picks
are refused or downgraded (
model_unavailable,session_model_mismatch). The requested model id is correlated with the egress IP's resolved geo, so a premium model request from a VPN/hosting IP is a suspicious, ToS-prohibited combination. On limited-tier accounts,mimo/mimo-v2.5is the supported active model (deepseek/deepseek-v4-flashis restricted on limited tier). - Know the difference between a quota and a ban.
429(quota, resets at Pacific midnight) is the normal end-of-day signal; the proxy locks the token locally and answers in<1ms, and routers fail over.503withwaiting_roomis the queued-waiting-room signal (also transient). Only403withbanned/country_blockedmeans the account itself is gone: stop using it and move to a fresh established account. - For ~24h of continuous coding, budget 4-5 keys. Each FreeBuff account has a daily session
quota (premium 4/day, limited 3/day, trust-level ladder up to 7) and the CLI holds one session
at a time (concurrent sessions are a Desktop multi-tab feature, not CLI).
One key ≈ one day of moderate use. Configure
AUTH_TOKENSwith multiple tokens to pool session headroom across tokens and let the proxy drain them one at a time. - Register accounts with real email addresses (e.g. Gmail). Disposable / temp-mail registrations are a documented ban cohort: 6,699 of 7,129 accounts on flagged domains were already banned when the blocklist was compiled. Accounts sharing one mailbox are capped at lower trust levels.
Why MAX_MESSAGES_PER_DAY Defaults to 0 (Unlimited):
- Unlimited is the default: no local cap throttles your free-tier allowance.
The proxy never spams upstream: when an account reaches its daily quota, the
upstream
429lock kicks in (below), so an unlimited local cap is safe. - Zero-Spam Guarantee: When an account reaches its daily quota or upstream capacity limit, the upstream returns a
429with a Pacific midnight reset timestamp (resetAt: 07:00:00Z). - The proxy parses this timestamp and locks the token locally in memory.
- Any subsequent request for that token returns
429locally in<1mswithout sending any network traffic upstream. - Upstream routers (e.g. 9router) receive standard
429+Retry-Afterheaders and automatically rotate to your next available account without failing user prompts.
| Endpoint | Auth | Description |
|---|---|---|
POST /v1/chat/completions | API_KEYS (when set) | OpenAI-compatible chat, streaming and non-streaming |
GET /v1/models | API_KEYS (when set) | Model catalog from the registry (fallback at boot + live refresh). Each row carries available/status/current_access_tier: models outside the limited-tier allowlist (mimo-v2.5) are marked available:false, status:"region_limited" when the token's egress region demotes it to the limited tier; MODELS_HIDE_UNAVAILABLE=true prunes them from the list; MODELS_ALLOW prunes every id not in the allowlist |
GET /healthz | none | JSON: status, uptime_seconds, models, per-token snapshot (incl. per-model quota map when the last admission carried it), bridge_tokens |
GET /metrics | none | Prometheus text format: uptime, model count, per-token 24h messages / requests / active runs / cooldown, per-model quota (freebuff_proxy_quota_recent / freebuff_proxy_quota_limit) |
POST /admin/reload | ADMIN_TOKEN (when set) | Hot-reload configuration from disk without restart |
GET /admin | session cookie (login via ADMIN_TOKEN) | Admin dashboard: overview, tokens, config, logs, metrics (see Admin Dashboard) |
GET/POST /admin/login | none | Dashboard login: constant-time ADMIN_TOKEN check, per-IP rate limit, HttpOnly + SameSite=Strict session cookie |
POST /admin/config | session cookie | Validate and persist the .env file, then hot-reload the config (rolls back on rejection) |
POST /admin/smoke | session cookie (loopback when ADMIN_TOKEN unset) | One real chat through the pool: reports model, token, latency, and a content preview (bridge mode needs a client token in the payload) |
POST /admin/diag | session cookie (loopback when ADMIN_TOKEN unset) | Dashboard diagnostics (same checks as -doctor): config state, DNS + TCP reachability, registry count; zero-cost per-token validity probes run on every request |
POST /admin/mode | session cookie (loopback when ADMIN_TOKEN unset) | Runtime pooled↔bridge switch; {"mode":"bridge"} empties the pool and clears AUTH_TOKENS in .env |
POST /admin/tokens/... | session cookie (loopback when ADMIN_TOKEN unset) | Runtime pool management: /add, /remove (last token), /test-all, and per-token /test, /unlock, /finish, persisted to .env |
The proxy ships with a built-in modern SPA web dashboard: single binary, no external dependencies, and zero runtime Node.js requirement (the Svelte 5 production build is compiled and embedded into the binary at build time). Open http://127.0.0.1:3457/admin (or your LISTEN_ADDR).
- Login: enter your
ADMIN_TOKENon the login page. It is the same value as the bearer token forPOST /admin/reload. It defaults to the factory password123456— until you change it, sensitive routes (config editor, logs, token management, reload) require a loopback client even when logged in (a startup warning and a persistent dashboard banner prompt the rotation;/admin/api/change-passwordworks from anywhere since it requires the current password). Failed logins are rate-limited per IP (5 fails → 1 minute lockout), and the session cookie isHttpOnly+SameSite=Strict(+Securewhen TLS orX-Forwarded-Proto: httpsis present). - Overview: live relay state (pooled/bridge mode, model count, uptime, safe mode) with per-token cards: session status, risk score, usage vs
MAX_MESSAGES_PER_DAY, transient-retry counters, plus a smoke test that sends one real chat through the pool (status, latency, preview). - Tokens & Quotas: per-token session detail + live per-model session quota table with usage bars and reset times; per-token Unlock (clears cooldown/ban), Finish runs, and Test (zero-cost validity probe). Features an always-visible 2-mode pool switcher (
Pooled,Bridge), runtime Add Token to Pool form, and Test all, with changes automatically persisted to.env. - Models: live catalog with upstream agent mappings, default model badges, and
MODEL_ALIASES. - Traces: recent chat requests and their routing outcome (token, model, status, duration, error class), the observability view for ban-avoidance debugging.
- Playground: interactive prompt console with real-time SSE chat streaming, model selector, and collapsible thinking/reasoning blocks.
- Configuration Studio: hot-reloading
.enveditor equipped with 3 One-Click Presets (Stealth Anti-Ban, Maximum Speed, Deep Debugging), interactive quick knobs (boolean switches, enum pills, duration sliders) with real-time bidirectional sync, and hover quick info cards explaining every setting and default. - Setup & Tool Integration: universal 1-click copy cards (Base URL, API Key, Default Model), copy-paste snippets for 5 major AI coding tools (OpenCode, Continue/Cline, aider, 9router, cURL), headless OAuth login wizard, and diagnostic suite.
- Logs: real-time in-memory log stream with level filtering (
INFO,DEBUG,WARN,ERROR), search filtering, and structured field tags. - Metrics: tabular stat cards with SVG sparklines and direct link to the raw
/metricsPrometheus feed.
See Dashboard Guide for access, Docker caveats, and hardening.
- Docker:
docker-compose.yml+Dockerfile, runs as an unprivileged user, healthchecked on/healthz,LISTEN_ADDR=:3457inside the container. - Systemd:
scripts/freebuff-proxy.service(Linux). - macOS launchd:
scripts/com.freebuff-proxy.plist(macOS). - Docker + 9router helper:
scripts/setup-proxy-docker.sh.
- Getting Started: 5-minute setup walkthrough
- Client Integration: OpenCode, pi, 9router, LiteLLM, OpenAI SDKs
- 9router Integration: router dashboard setup in bridge mode
- Dashboard Guide: the admin web UI: access, pages, Docker caveats, hardening
- Manual Testing: verify the proxy on Linux or Windows by hand, step by step
- Version Stability & Ban Findings: read before upgrading — why v0.11.2 bridge is the proven-stable deployment
- Contributing: filing issues, opening PRs, what to expect
- Security: supported versions and how to report a vulnerability
The offline model registry pins five upstream constant files in internal/registry/testdata/upstream/. scripts/check-upstream.sh compares those pins against CodebuffAI/freebuff@main (shallow-clones to ../freebuff-reference, or set FREEBUFF_REFERENCE_DIR; Windows: run from Git Bash):
bash scripts/check-upstream.shCI runs the same check weekly (upstream-drift workflow) and goes red on drift. A live registry refresh self-heals at runtime, but the offline fallback does not: on DRIFT, copy the changed files into testdata/upstream/ and update fallbackAgents/fallbackRootByModel in internal/registry/registry.go until TestFallbackParityWithPinnedUpstream passes.
- Questions, bugs, feature requests: GitHub Issues
- Security reports: SECURITY.md
- Contributing: CONTRIBUTING.md