OpenAI-compatible reverse proxy that rotates across providers on failure, with Anthropic↔OpenAI format translation. Built with Rust + axum.
- Per-failure rotation through providers from CSV
- Always uses CSV model (ignores client's
modelfield) - Streaming (SSE) + non-streaming support for both OpenAI and Anthropic formats
- Anthropic↔OpenAI translation — full message, tool call, and tool result conversion
--cacheflag — injects Anthropiccache_controlhints into system prompt and last user message; falls back to uncached on 400--compressflag — injects a brevity system prompt into all requests to reduce token usage- Permanent provider skip on 413 (payload too large); skipped providers excluded from rotation
- Structured logging with
tracingincluding TTFB (time to first byte) metrics /healthand/statsendpoints- Static musl binaries for Android ARM64 (via NDK); Ubuntu x64 requires
musl-tools - Optimized streaming with proper line buffering to eliminate artificial latency
- Lock-free stats using atomic operations for minimal contention
- Connection pooling with configurable idle timeouts (10 connections per host, 90s idle timeout)
- Fast timeouts (5s connect, 120s total) to quickly fail over to next provider
- Optional custom DNS resolver (disabled by default, enable with
USE_CUSTOM_DNSenv var)
name,base_url,model,api_key
gemini,https://generativelanguage.googleapis.com/v1beta/openai/,gemini-2.0-flash,AIza...
groq,https://api.groq.com/openai/v1,llama-3.3-70b,gsk_...| Variable | Default | Description |
|---|---|---|
CSV_PATH |
$HOME/code/freellmkeys.csv |
Path to provider CSV |
BASE_URL |
http://0.0.0.0:3001/v1 |
Bind address openai-compatible |
ANTHROPIC_BASE_URL |
http://0.0.0.0:3001/anthropic |
Bind address anthropic-compatible |
API_KEY |
(none) | Require Bearer auth header |
RUST_LOG |
llmkeyrotator=info |
Log level |
USE_CUSTOM_DNS |
(unset) | Set to any value to use Google DNS (8.8.8.8, 8.8.4.4) + Cloudflare (1.1.1.1) instead of system DNS |
POST /v1/*— OpenAI-compatible proxy (e.g./v1/chat/completions). Strips/v1prefix, forwards to providerbase_url + rest_of_path. Always uses model from CSV.POST /anthropic/*— Anthropic-compatible proxy (e.g./anthropic/v1/messages). Converts Anthropic ↔ OpenAI format, strips/anthropicprefix, forwards to provider. Always uses model from CSV.GET /health— Status, provider count, current providerGET /stats— Request/error/rotation counts, per-provider failure stats/*— Catch-all proxy to current provider (strips/v1or/anthropicprefix if present, always uses model from CSV)
# Native debug build (x86_64 Linux)
cargo build
# Native release build (x86_64 Linux)
cargo build --release# Prerequisites: Have Android NDK installed (tested with r29)
# Configure .cargo/config.toml with NDK toolchain paths
# Add target and build
rustup target add aarch64-linux-android
cargo build --release --target aarch64-linux-androidOutput: target/aarch64-linux-android/release/llmkeyrotator
# Prerequisites: Install musl-tools
# sudo apt install musl-tools
# Add target and build
rustup target add x86_64-unknown-linux-musl
cargo build --release --target x86_64-unknown-linux-muslOutput: target/x86_64-unknown-linux-musl/release/llmkeyrotator (statically-linked ELF)
./build.sh # Attempts both targets, skips x86_64 if musl-gcc missing