# ccLoad - Claude Code & Codex & Gemini & OpenAI Compatible API Proxy Service **English | [็ฎ€ไฝ“ไธญๆ–‡](README.md)** [![Go](https://img.shields.io/badge/Go-1.25+-00ADD8.svg)](https://golang.org) [![Gin](https://img.shields.io/badge/Gin-v1.11+-blue.svg)](https://github.com/gin-gonic/gin) [![Docker](https://img.shields.io/badge/Docker-Supported-2496ED.svg)](https://hub.docker.com) [![Hugging Face](https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Spaces-yellow)](https://huggingface.co/spaces) [![GitHub Actions](https://img.shields.io/badge/CI%2FCD-GitHub%20Actions-2088FF.svg)](https://github.com/features/actions) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) > ๐Ÿš€ High-Performance AI API Proxy | Smart Multi-Channel Routing | Instant Failover | Real-time Monitoring | Production-Ready Managing multiple Claude API channels getting chaotic? Manual failover when rate limits hit? ccLoad has you covered! A high-performance Go-based proxy service supporting Claude Code, Codex, Gemini, and OpenAI. **Smart routing + automatic failover + real-time monitoring** - rock-solid API reliability ๐Ÿš€ ## ๐ŸŽฏ Pain Points Solved When using Claude API services, users typically face these challenges: - **Complex multi-channel management**: Managing multiple API channels simultaneously, some with short validity, others with daily limits - **Inconvenient manual switching**: Time-consuming manual channel switching affects work efficiency - **Difficult failure handling**: Manual switching to other available channels when one fails - **Opaque request status**: Traditional approaches leave you blindly waiting without knowing request progress - **Hidden upstream errors**: Some third-party channels return HTTP 200 status but with error content in the response body, making it difficult for clients to detect and handle ccLoad solves these pain points through: - **Smart routing**: Prioritizes high-priority channels, smooth weighted round-robin for same priority with more even distribution - **Automatic failover**: Automatically switches to available channels when failures occur - **Exponential cooldown**: Failed channels use exponential backoff to avoid hammering failed services - **Multi-URL smart routing**: Multiple URLs per channel with latency-weighted random selection, slower URLs automatically get less traffic - **Zero manual intervention**: Clients don't need to manually switch upstream channels - **Real-time request monitoring**: Log management interface shows ongoing requests - no more blind waiting, clear visibility into each request's status - **Soft error detection**: Automatically detects HTTP 200 responses that are actually errors ("masqueraded responses"), triggering channel cooldown and failover. Common scenarios include: - JSON responses containing `{"error": {...}}` structure - Responses with `type` field set to `"error"` - Plain text messages like `"ๅฝ“ๅ‰ๆจกๅž‹่ดŸ่ฝฝ่ฟ‡้ซ˜"` / `"Current model load too high"` (load warnings) ## โœจ Key Features - ๐Ÿš€ **High-Performance Architecture** - Gin framework, 1000+ concurrent connections, high-performance caching - ๐Ÿงฎ **Local Token Counting** - API-compliant local token estimation, <5ms response, 93%+ accuracy, supports large-scale tool scenarios - ๐ŸŽฏ **Smart Error Classification** - Distinguishes Key/Channel/Client errors, soft error detection (200 masquerading as error), 1308 quota handling (596/597 status codes) - ๐Ÿ”€ **Smart Routing** - Priority + smooth weighted round-robin channel selection, **pre-filters cooled channels**, multi-key load balancing, **health-based dynamic sorting** (confidence factor prevents small sample over-penalization) - ๐Ÿ›ก๏ธ **Failover** - Automatic failure detection with exponential backoff cooldown (1s โ†’ 2s โ†’ 4s โ†’ ... โ†’ 30min) - ๐Ÿ”’ **Race-Safe** - Key selector race condition protection, startup config validation, automatic resource cleanup - ๐Ÿ“Š **Real-time Monitoring** - Built-in trend analysis, logging, and stats dashboard, **Token usage stats** with time range selection and per-token classification - ๐ŸŽฏ **Transparent Proxy** - Supports Claude Code, Codex, Gemini, and OpenAI compatible APIs with smart auth detection - ๐Ÿ“ฆ **Single Binary Deployment** - No external dependencies, embedded SQLite included - ๐Ÿ”’ **Secure Authentication** - Token-based admin interface and API access control - ๐Ÿท๏ธ **Build Tags** - GOTAGS support, high-performance JSON library enabled by default - ๐Ÿณ **Docker Support** - Multi-arch images (amd64/arm64), automated CI/CD - โ˜๏ธ **Cloud Native** - Container deployment support, GitHub Actions auto-build - ๐Ÿค— **Hugging Face** - One-click deployment to Hugging Face Spaces, free hosting - ๐Ÿ’ฐ **Cost Limits** - Per-channel daily cost limits, per-token cost limits - ๐Ÿšฆ **Channel RPM Limits** - Per-channel rolling 60-second request caps, 0=unlimited - ๐Ÿ” **Token Restrictions** - API token cost limits + model restrictions for fine-grained access control - โฑ๏ธ **TTFB Monitoring** - Streaming request first byte time tracking for upstream latency diagnosis - ๐ŸŒ **Multi-URL Load Balancing** - Multiple URLs per channel with latency-weighted random selection - ๐Ÿ’ต **service_tier Pricing** - OpenAI priority/flex/default tier multipliers for accurate cost accounting - ๐Ÿ–ผ๏ธ **Image Tool Billing** - Responses image_generation/gpt-image-2 cost accounting - ๐Ÿ“‰ **Tiered Pricing** - GPT-5.4/Qwen-Plus/Gemini long-context step pricing, auto-applies lower rate at token thresholds - ๐Ÿ”„ **Protocol Transform** - Anthropic/OpenAI/Gemini/Codex cross-protocol conversion, one channel serves multiple client protocols - ๐Ÿ” **Debug Logs** - Upstream request/response raw data capture with sensitive header masking, essential for troubleshooting - ๐Ÿ• **Scheduled Checks** - Background periodic channel availability probing, auto-detect failed channels - ๐Ÿงฉ **Custom Request Rules** - Per-channel HTTP header & JSON body rewriting (remove/override/append), with auth header protection, CRLF guard, and capacity caps - ๐ŸŽ›๏ธ **Log Column Customization** - Show/hide table columns per preference, settings persist in browser localStorage ## ๐Ÿ—๏ธ Architecture Overview ```mermaid graph TB subgraph "Client" A[User App] --> B[ccLoad Proxy] end subgraph "ccLoad Service" B --> C[Auth Layer] C --> D[Route Dispatcher] D --> E[Channel Selector] E --> F[Load Balancer] subgraph "Core Components" F --> G[Channel A
Priority:10] F --> H[Channel B
Priority:5] F --> I[Channel C
Priority:5] G --> G1[URL Selector
Weighted Random] H --> H1[URL Selector
Weighted Random] I --> I1[URL Selector
Weighted Random] end subgraph "Storage Layer" J[(Storage Factory)] J3[Schema Definition] J4[Unified SQL Layer] J1[(SQLite)] J2[(MySQL)] J --> J3 J3 --> J4 J4 --> J1 J4 --> J2 end subgraph "Monitoring Layer" K[Log System] L[Stats Analysis] M[Trend Charts] end end subgraph "Upstream Services" G1 --> N[Claude API] H1 --> O[Claude API] I1 --> P[Claude API] end E <--> J F <--> J K <--> J L <--> J M <--> J style B fill:#4F46E5,stroke:#000,color:#fff style F fill:#059669,stroke:#000,color:#fff style E fill:#0EA5E9,stroke:#000,color:#fff ``` ## ๐Ÿš€ Quick Start Choose the deployment method that suits you best: | Method | Difficulty | Cost | Use Case | HTTPS | Persistence | |--------|------------|------|----------|-------|-------------| | ๐Ÿณ **Docker** | โญโญ | VPS required | Production, high performance | Config required | โœ… | | ๐Ÿค— **Hugging Face** | โญ | **Free** | Personal use, quick trial | โœ… Auto | โœ… | | ๐Ÿ”ง **Source Build** | โญโญโญ | Server required | Development, customization | Config required | โœ… | | ๐Ÿ“ฆ **Binary** | โญโญ | Server required | Lightweight, simple setup | Config required | โœ… | ### Method 1: Docker Deployment (Recommended) **Using pre-built images (Recommended)**: ```bash # Option 1: Using docker-compose (Simplest) curl -o docker-compose.yml https://raw.githubusercontent.com/caidaoli/ccLoad/master/docker-compose.yml curl -o .env https://raw.githubusercontent.com/caidaoli/ccLoad/master/.env.example # Edit .env file to set password docker-compose up -d # Option 2: Run image directly docker pull ghcr.io/caidaoli/ccload:latest docker run -d --name ccload \ -p 8080:8080 \ -e CCLOAD_PASS=your_secure_password \ -v ccload_data:/app/data \ ghcr.io/caidaoli/ccload:latest ``` **Building from source**: ```bash # Clone project git clone https://github.com/caidaoli/ccLoad.git cd ccLoad # Build and run with docker-compose docker-compose -f docker-compose.build.yml up -d # Or build manually docker build -t ccload:local . docker run -d --name ccload \ -p 8080:8080 \ -e CCLOAD_PASS=your_secure_password \ -v ccload_data:/app/data \ ccload:local ``` ### Method 2: Source Build ```bash # Clone project git clone https://github.com/caidaoli/ccLoad.git cd ccLoad # Build project (uses high-performance JSON library by default) go build -tags sonic -o ccload . # Or use Makefile make build # Run in development mode go run -tags sonic . # Or make dev ``` ### Method 3: Binary Download ```bash # Download binary for your platform from GitHub Releases wget https://github.com/caidaoli/ccLoad/releases/latest/download/ccload-linux-amd64 chmod +x ccload-linux-amd64 ./ccload-linux-amd64 ``` ### Method 4: Hugging Face Spaces Deployment Hugging Face Spaces provides free container hosting with Docker support, ideal for personal and small team use. #### Deployment Steps 1. **Login to Hugging Face** Visit [huggingface.co](https://huggingface.co) and log into your account 2. **Create New Space** - Click "New" โ†’ "Space" in the top right - **Space name**: `ccload` (or custom name) - **License**: `MIT` - **Select the SDK**: `Docker` - **Visibility**: `Public` or `Private` (private requires paid subscription) - Click "Create Space" 3. **Create Dockerfile** Create a `Dockerfile` in the Space repository: ```dockerfile FROM ghcr.io/caidaoli/ccload:latest ENV TZ=Asia/Shanghai ENV PORT=7860 ENV SQLITE_PATH=/tmp/ccload.db EXPOSE 7860 ``` Create via: **Method A - Web Interface** (Recommended): - Click "Files" tab on Space page - Click "Add file" โ†’ "Create a new file" - Enter `Dockerfile` as filename - Paste the content above - Click "Commit new file to main" **Method B - Git Command Line**: ```bash # Clone your Space repository git clone https://huggingface.co/spaces/YOUR_USERNAME/ccload cd ccload # Create Dockerfile cat > Dockerfile << 'EOF' FROM ghcr.io/caidaoli/ccload:latest ENV TZ=Asia/Shanghai ENV PORT=7860 ENV SQLITE_PATH=/tmp/ccload.db EXPOSE 7860 EOF # Commit and push git add Dockerfile git commit -m "Add Dockerfile for ccLoad deployment" git push ``` 4. **Configure Environment Variables (Secrets)** In Space settings (Settings โ†’ Variables and secrets โ†’ New secret): | Variable | Value | Required | Description | |----------|-------|----------|-------------| | `CCLOAD_PASS` | `your_admin_password` | โœ… **Required** | Admin interface password | | `CCLOAD_API_TOKENS` | `token1\|production,token2\|development` | Optional | Pre-seed API access tokens on startup | **Note**: API access tokens can be pre-seeded with `CCLOAD_API_TOKENS` or managed in the Web admin interface `/web/tokens.html`. 5. **Wait for Build and Startup** After pushing Dockerfile, Hugging Face will automatically: - Pull pre-built image (~30 seconds) - Start application container (~10 seconds) - Total time ~1-2 minutes (3-5x faster than source build) 6. **Access Application** After build completes, access via: - **App URL**: `https://YOUR_USERNAME-ccload.hf.space` - **Admin Interface**: `https://YOUR_USERNAME-ccload.hf.space/web/` - **API Endpoint**: `https://YOUR_USERNAME-ccload.hf.space/v1/messages` **First Access Note**: - If Space is sleeping, first access takes 20-30 seconds to wake - Subsequent accesses respond immediately #### Hugging Face Deployment Characteristics **Advantages**: - โœ… **Completely Free**: Public Spaces are permanently free with CPU and storage - โœ… **Fast Deployment**: Pre-built image, 1-2 minutes (3-5x faster than source build) - โœ… **Auto HTTPS**: No SSL certificate configuration needed - โœ… **Auto Restart**: Automatic restart after crashes - โœ… **Version Control**: Git-based, easy rollback and collaboration - โœ… **Simple Maintenance**: Only 5-line Dockerfile, no source code management **Limitations**: - โš ๏ธ **Resource Limits**: Free tier provides 2 CPU + 16GB RAM - โš ๏ธ **Sleep Policy**: 48 hours without access triggers sleep, first access takes ~20-30s to wake - โš ๏ธ **Fixed Port**: Must use port 7860 - โš ๏ธ **Public Access**: Spaces are public by default, must configure API tokens via Web admin to access /v1/* APIs (otherwise 401) #### Data Persistence **Important**: Hugging Face Spaces Storage Policy Due to Hugging Face Spaces limitations (`/tmp` directory clears on restart), **we strongly recommend using an external MySQL database** for complete data persistence: **Option 1: Hybrid Storage Mode (Recommended, Best Performance)** - โœ… **Ultra-fast queries**: All reads/writes go through local SQLite, latency <1ms (free MySQL has 800ms+ latency) - โœ… **Restart-safe**: Async sync to MySQL, auto-restore on startup - โœ… **Stats caching**: Smart TTL cache reduces repetitive aggregate queries - Configuration: Add `CCLOAD_MYSQL` + `CCLOAD_ENABLE_SQLITE_REPLICA=1` in Secrets **Dockerfile Example (Hybrid Mode)**: ```dockerfile FROM ghcr.io/caidaoli/ccload:latest ENV TZ=Asia/Shanghai ENV PORT=7860 # Configure in Secrets: CCLOAD_MYSQL + CCLOAD_ENABLE_SQLITE_REPLICA=1 EXPOSE 7860 ``` **Option 2: Pure MySQL Mode** - โœ… **Complete Persistence**: Channel configs, logs, and stats all preserved - โœ… **Restart-Safe**: Data stored externally, unaffected by Space restarts - โš ๏ธ **Slower Queries**: Free MySQL has higher latency, stats pages respond slowly - Configuration: Add `CCLOAD_MYSQL` environment variable in Secrets **Recommended Free MySQL Services**: - [TiDB Cloud Serverless](https://tidbcloud.com/) - Free 5GB storage, MySQL compatible, no connection limits, recommended first choice - [Aiven for MySQL](https://aiven.io/) - Free 1GB storage, multi-region support **MySQL Configuration Example (TiDB Cloud)**: 1. Register for [TiDB Cloud](https://tidbcloud.com/) account 2. Create Serverless Cluster (free) 3. Get connection info, format: `user:password@tcp(host:4000)/database?tls=true` 4. Add `CCLOAD_MYSQL` variable in Hugging Face Space Secrets 5. **(Optional) Enable Hybrid Mode**: Add `CCLOAD_ENABLE_SQLITE_REPLICA=1` for best performance 6. Restart Space, all data will auto-persist to MySQL **Dockerfile Example (Pure MySQL)**: ```dockerfile FROM ghcr.io/caidaoli/ccload:latest ENV TZ=Asia/Shanghai ENV PORT=7860 # No SQLITE_PATH needed, uses CCLOAD_MYSQL environment variable EXPOSE 7860 ``` **Option 3: Local Storage Only (Not Recommended)** - โš ๏ธ **Data Loss**: `/tmp` clears on Space restart, channel config lost - โš ๏ธ **Manual Recovery**: Must re-import via Web interface or CSV - Use case: Temporary testing only #### Update Deployment With pre-built images, updates are simple: **Auto Update**: - When new version image (`ghcr.io/caidaoli/ccload:latest`) is released - Click "Factory rebuild" in Space settings to pull latest image - Or wait for Hugging Face auto-restart (typically after 48 hours) **Manual Trigger Update**: ```bash # Add empty commit to trigger rebuild git commit --allow-empty -m "Trigger rebuild to pull latest image" git push ``` **Version Pinning** (Optional): To lock specific version, modify Dockerfile: ```dockerfile FROM ghcr.io/caidaoli/ccload:2.19.0 # Specify version ENV TZ=Asia/Shanghai ENV PORT=7860 ENV SQLITE_PATH=/tmp/ccload.db EXPOSE 7860 ``` ### Basic Configuration **SQLite Mode (Default)**: ```bash # Set environment variables export CCLOAD_PASS=your_admin_password export PORT=8080 export SQLITE_PATH=./data/ccload.db # Or use .env file echo "CCLOAD_PASS=your_admin_password" > .env echo "PORT=8080" >> .env echo "SQLITE_PATH=./data/ccload.db" >> .env # Start service ./ccload ``` **MySQL Mode**: ```bash # 1. Create MySQL database mysql -u root -p -e "CREATE DATABASE ccload CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" # 2. Set environment variables export CCLOAD_PASS=your_admin_password export CCLOAD_MYSQL="user:password@tcp(localhost:3306)/ccload?charset=utf8mb4" export PORT=8080 # Or use .env file echo "CCLOAD_PASS=your_admin_password" > .env echo "CCLOAD_MYSQL=user:password@tcp(localhost:3306)/ccload?charset=utf8mb4" >> .env echo "PORT=8080" >> .env # 3. Start service (auto-creates tables) ./ccload ``` **Docker + MySQL**: ```bash # Option 1: docker-compose (Recommended) cat > docker-compose.mysql.yml << 'EOF' version: '3.8' services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: rootpass MYSQL_DATABASE: ccload MYSQL_USER: ccload MYSQL_PASSWORD: ccloadpass volumes: - mysql_data:/var/lib/mysql ports: - "3306:3306" healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 5 ccload: image: ghcr.io/caidaoli/ccload:latest environment: CCLOAD_PASS: your_admin_password CCLOAD_MYSQL: "ccload:ccloadpass@tcp(mysql:3306)/ccload?charset=utf8mb4" PORT: 8080 ports: - "8080:8080" depends_on: mysql: condition: service_healthy volumes: mysql_data: EOF docker-compose -f docker-compose.mysql.yml up -d # Option 2: Direct run (requires existing MySQL service) docker run -d --name ccload \ -p 8080:8080 \ -e CCLOAD_PASS=your_admin_password \ -e CCLOAD_MYSQL="user:pass@tcp(mysql_host:3306)/ccload?charset=utf8mb4" \ ghcr.io/caidaoli/ccload:latest ``` After service starts, access: - Admin Interface: `http://localhost:8080/web/` - API Proxy: `POST http://localhost:8080/v1/messages` - **API Token Management**: `http://localhost:8080/web/tokens.html` - Configure API access tokens via Web interface ## ๐Ÿ“– Usage Guide ### API Proxy **Claude API Proxy (Requires Auth)**: First, configure API access token in Web admin interface `http://localhost:8080/web/tokens.html`, then use that token to access API: ```bash curl -X POST http://localhost:8080/v1/messages \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-api-token" \ -H "x-api-key: your-claude-api-key" \ -H "anthropic-version: 2023-06-01" \ -d '{ "model": "claude-sonnet-4-6", "max_tokens": 1024, "messages": [ { "role": "user", "content": "Hello, Claude!" } ] }' ``` **OpenAI Compatible API Proxy (Chat Completions)**: ```bash curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-api-token" \ -d '{ "model": "gpt-4o", "messages": [ { "role": "user", "content": "Hello!" } ] }' ``` ### Local Token Counting Quickly estimate request token consumption (no upstream API call needed): ```bash curl -X POST http://localhost:8080/v1/messages/count_tokens \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-6", "messages": [ {"role": "user", "content": "Hello, how are you?"} ], "system": "You are a helpful assistant." }' # Response example # { # "input_tokens": 28 # } ``` **Features**: - โœ… Compliant with Anthropic official API spec - โœ… Local computation, <5ms response, no API quota consumption - โœ… 93%+ accuracy (compared to official API) - โœ… Supports system prompts, tool definitions, large-scale tool scenarios - โœ… Requires auth token (configure at `/web/tokens.html`) ### Channel Management Manage channels via Web interface `/web/channels.html` or API: ```bash # Add channel (supports multiple URLs, comma-separated) curl -X POST http://localhost:8080/admin/channels \ -H "Content-Type: application/json" \ -d '{ "name": "Claude-API", "api_key": "sk-ant-api03-xxx", "url": "https://api.anthropic.com,https://api2.anthropic.com", "priority": 10, "rpm_limit": 0, "models": ["claude-sonnet-4-6", "claude-opus-4-6"], "enabled": true }' ``` > **Multi-URL Note**: The `url` field supports comma-separated multiple URLs. The system uses latency-weighted random selection for optimal URL choice, with automatic cooldown for failed URLs, enabling URL-level load balancing and failover within a single channel. > **RPM Limit Note**: `rpm_limit` is a per-channel request cap over a rolling 60-second window; `0` means unlimited. Proxy forwarding, manual tests, single-URL tests, and scheduled checks all count toward the cap. Multi-URL failover counts each actual upstream HTTP request. The counter is in-memory: restart clears it, and multiple instances count independently. ### Custom Request Rules (Advanced) The "Advanced" button in the channel editor opens a secondary modal that lets you rewrite the **HTTP headers** and **JSON request body** forwarded upstream at channel granularity. Typical use cases include `User-Agent` override, forcing API version headers, or tweaking fields like `thinking` / `max_tokens`. Rules apply in configured order and take effect for all subsequent requests on that channel as soon as they are saved. **Action matrix**: | Target | `remove` | `override` | `append` | |---|---|---|---| | HTTP Header | Delete the named header (supports token-level removal on multi-value headers such as `Anthropic-Beta`) | `Header.Set` replaces all values | `Header.Add` appends a value (multi-value semantics) | | JSON Body | Delete a field/array element by dotted path | Set the value at a path, creating intermediate nodes as needed | Not supported (ambiguous in JSON) | **JSON path syntax**: - Dotted path + numeric array index: `thinking.budget_tokens`, `messages.0.role`, `generation_config.temperature` - Values accept any JSON literal: number `0.7`, boolean `true`, string `"claude-opus-4-6"`, object `{"type":"adaptive"}`, array `["a","b"]` **Safety constraints** (hard-enforced server-side even if the frontend is bypassed): - **Auth header blacklist**: any rule targeting `Authorization`, `x-api-key`, or `x-goog-api-key` (case-insensitive) is silently ignored and logged via `slog.Warn` - **CRLF injection guard**: header names/values must not contain `\r\n` - **Non-JSON body passthrough**: requests without `application/json` content type, empty bodies, or bodies that fail to deserialize are forwarded untouched without blocking - **Capacity caps**: โ‰ค 32 header rules and โ‰ค 32 body rules per channel, each value โ‰ค 8 KB; violations return HTTP 400 **Typical example**: ```jsonc { "custom_request_rules": { "headers": [ { "action": "override", "name": "User-Agent", "value": "claude-cli/1.0 (custom)" }, { "action": "remove", "name": "Anthropic-Beta", "value": "context-1m-2025-08-07" }, { "action": "append", "name": "Accept", "value": "application/json" } ], "body": [ { "action": "override", "path": "thinking", "value": {"type":"adaptive"} }, { "action": "override", "path": "max_tokens", "value": 4096 }, { "action": "remove", "path": "stop_sequences" } ] } } ``` > **Interaction with built-in logic**: Custom rules run **after** the anyrouter `anthropic-beta` injection, so they can override or remove the beta flag. The anyrouter adaptive-thinking injection detects a user-provided `thinking` field and leaves it untouched. Authentication headers remain unmodifiable at all times. ### Batch Data Management Supports CSV format for channel config import/export: **Export Config**: ```bash # Web interface: Visit /web/channels.html, click "Export CSV" button # API call: curl -H "Authorization: Bearer your_token" \ http://localhost:8080/admin/channels/export > channels.csv ``` **Import Config**: ```bash # Web interface: Visit /web/channels.html, click "Import CSV" button # API call: curl -X POST -H "Authorization: Bearer your_token" \ -F "file=@channels.csv" \ http://localhost:8080/admin/channels/import ``` **CSV Format Example**: ```csv name,api_key,url,priority,models,enabled Claude-API-1,sk-ant-xxx,https://api.anthropic.com,10,"[\"claude-sonnet-4-6\"]",true Claude-API-2,sk-ant-yyy,https://api.anthropic.com,5,"[\"claude-opus-4-6\"]",true ``` **Features**: - Auto column name mapping (Chinese/English) - Smart data validation with error messages - Incremental import and overwrite update - UTF-8 encoding, Excel compatible ## ๐Ÿ“Š Monitoring Metrics Check out the awesome admin dashboard ๐Ÿ‘‡ ![ccLoad Dashboard](images/ccload-dashboard.jpeg) ![ccLoad Logs](images/ccload-logs.jpg) *Real-time Monitoring Dashboard: Claude Code, Codex, OpenAI, and Gemini platform metrics at a glance* **Core Features**: - ๐Ÿ“ˆ **24-hour Trend Charts** - Request volumes clearly visualized with peaks and valleys - ๐Ÿ”ด **Real-time Error Logs** - Instantly detect which channel has issues - ๐Ÿ“Š **Channel Call Statistics** - See which channels are performing well with data-backed insights - โšก **Performance Metrics** - Latency, success rates, and bottleneck detection - ๐Ÿ’ฐ **Token Usage Stats** - Know exactly where your budget goes: - Custom time range selector for flexible analysis - Per API token ID classification for multi-tenant billing - Supports Gemini/OpenAI cache token visualization - ๐ŸŽ›๏ธ **Log Column Customization** - Click the gear icon to show/hide columns, settings auto-saved to browser **UI Highlights**: - ๐ŸŽจ Modern gradient purple theme for comfortable viewing - ๐Ÿ“ฑ Responsive design works great on mobile and desktop - โšก Real-time data refresh without manual page reload - ๐Ÿ“Š Multi-dimensional stat cards show key metrics on one screen - Cached query optimization - Gemini/OpenAI Cache Token (Cache Read) display ## ๐Ÿ”ง Tech Stack ### Core Dependencies | Component | Version | Purpose | Performance Advantage | |-----------|---------|---------|----------------------| | **Go** | 1.25.0+ | Runtime | Native concurrency, built-in min function | | **Gin** | v1.11.0 | Web Framework | High-performance HTTP routing | | **modernc/sqlite** | v1.45.0 | Embedded Database | Pure Go, zero CGO dependency, single file (default) | | **MySQL** | v1.9.3 | RDBMS | Optional, for high-concurrency production | | **Sonic** | v1.15.0 | JSON Library | 2-3x faster than stdlib | | **godotenv** | v1.5.1 | Env Config | Simplified config management | ### Architecture Features **Modular Architecture**: - **Proxy Module Split** (SRP): - `proxy_handler.go`: HTTP entry, concurrency control, route selection - `proxy_forward.go`: Core forwarding logic, request building, response handling - `proxy_error.go`: Error handling, cooldown decisions, retry logic - `proxy_util.go`: Constants, type definitions, utility functions - `proxy_stream.go`: Streaming responses, first byte detection - `proxy_gemini.go`: Gemini API special handling - `proxy_sse_parser.go`: SSE parser (defensive handling, Gemini/OpenAI cache token parsing) - `proxy_debug.go`: Upstream request/response debug capture (with sensitive header masking) - **Admin Module Split** (SRP): - `admin_channels.go`: Channel CRUD - `admin_stats.go`: Stats analysis API - `admin_cooldown.go`: Cooldown management API - `admin_csv.go`: CSV import/export - `admin_types.go`: Admin API type definitions - `admin_auth_tokens.go`: API access token CRUD (with token stats, cost limits, model restrictions) - `admin_settings.go`: System settings management - `admin_models.go`: Model list management - `admin_testing.go`: Channel testing (with protocol transform testing) - `admin_debug_log.go`: Debug log API (sensitive header masking + base64 binary encoding) - `channel_check_scheduler.go`: Scheduled channel check scheduler - `detection_log.go`: Detection result to LogEntry builder - **Protocol Transform System** (2026-04 new): - `protocol/types.go`: Four protocol definitions (Anthropic/OpenAI/Gemini/Codex) - `protocol/registry.go`: Request/response transformer registry - `protocol/builtin/`: 18 built-in transform implementations (streaming and non-streaming) - Two modes: `upstream` (default, handled natively by upstream) / `local` (local translation) - Channel config: `ProtocolTransformMode` + `ProtocolTransforms` - **Cooldown Manager** (DRY): - `cooldown/manager.go`: Unified cooldown decision engine - Eliminates duplicate code, unified cooldown logic - Distinguishes network vs HTTP error classification - Built-in single-key channel auto-upgrade logic - **Multi-URL Selector** (URLSelector): - `url_selector.go`: Smart URL selection within a single channel - Explore-first: Unvisited URLs get priority to collect latency data - Weighted random: Weight = 1/EWMA latency, lower latency = higher selection probability - Independent cooldown: Failed URLs cool down independently without affecting other URLs - BaseURL tracking: Active requests, logs, and UI carry upstream URL throughout - **Storage Layer Refactor** (2025-12 optimization, eliminated 467 lines of duplicate code): - `storage/schema/`: Unified schema definition (supports SQLite/MySQL differences) - `storage/sql/`: Common SQL implementation layer (SQLite/MySQL shared) - `storage/factory.go`: Factory pattern auto-selects database - Composite index optimization, stats query performance improved - **OpenAI service_tier Pricing** (2026-03 new): - `util.OpenAIServiceTierMultiplier()`: Returns multiplier for priority/flex/default tiers - `LogEntry.ServiceTier`: Persisted to database, log cost column shows tier annotation - Supports GPT-5.4, GPT-5.4-pro, and other latest model pricing - **Responses image_generation Tool Billing** (2026-05 new): - Parses Responses API `tool_usage.image_gen` and the `image_generation` tool model - Bills `gpt-image-2` by text input, image input, and image output tokens - Streaming/non-streaming proxy paths and channel tests share the same usage parser to keep cost accounting consistent - **Tiered Pricing**: - GPT-5.4: Input price auto-steps down after token threshold - Qwen-Plus: Lower price tier kicks in after threshold - Gemini long-context: Price doubles above threshold - Cache discounts: Claude/Opus independent multipliers, OpenAI cache hit 50% discount **Multi-level Cache System**: - Channel config cache (60s TTL) - Round-robin pointer cache (in-memory) - Cooldown state inline (channels/api_keys tables store directly) - Error classification cache (1000 capacity) **Async Processing Architecture**: - Log system (1000 buffer + single worker, guarantees FIFO order) - Token/log cleanup (background goroutine, periodic maintenance) **Unified Response System**: - `StandardResponse[T]` generic struct (DRY) - `ResponseHelper` utility class with 9 shortcut methods - Auto-extracts app-level error codes, unified JSON format **Connection Pool Optimization**: - SQLite: 10 connections for memory mode / 5 for file mode, 5-minute lifetime - HTTP client: 100 max connections, 30s timeout, keepalive optimization - TLS: Session cache (1024 capacity), reduces handshake latency ## ๐Ÿ”ง Configuration ### Environment Variables | Variable | Default | Description | |----------|---------|-------------| | `CCLOAD_PASS` | None | Admin password (**Required**, exits if not set) | | `CCLOAD_API_TOKENS` | None | Pre-seed API access tokens on startup. Format: `token1,token2` or `token1\|production,token2\|development`; existing tokens are not overwritten | | `API_TOKENS` | None | Compatibility alias for `CCLOAD_API_TOKENS`; startup fails if both variables are set with different values | | `CCLOAD_MYSQL` | None | MySQL DSN (optional, format: `user:pass@tcp(host:port)/db?charset=utf8mb4`)
**If set uses MySQL, otherwise SQLite** | | `CCLOAD_ENABLE_SQLITE_REPLICA` | `0` | Hybrid storage mode switch (`1`=enable, see below) | | `CCLOAD_SQLITE_LOG_DAYS` | `7` | Days of logs to restore from MySQL on startup in hybrid mode (-1=all, 0=no logs) | | `CCLOAD_ALLOW_INSECURE_TLS` | `0` | Disable upstream TLS cert validation (`1`=enable; โš ๏ธfor troubleshooting/controlled intranet only) | | `PORT` | `8080` | Service port | | `GIN_MODE` | `release` | Run mode (`debug`/`release`) | | `GIN_LOG` | `true` | Gin access log switch (`false`/`0`/`no`/`off` to disable) | | `SQLITE_PATH` | `data/ccload.db` | SQLite database file path (SQLite mode only) | | `SQLITE_JOURNAL_MODE` | `WAL` | SQLite Journal mode (WAL/TRUNCATE/DELETE, recommend TRUNCATE for containers) | | `CCLOAD_MAX_CONCURRENCY` | `1000` | Max concurrent requests (limits simultaneous proxy requests) | | `CCLOAD_MAX_BODY_BYTES` | `10485760` | Max request body bytes (10MB, Images API auto-expands to 20MB) | | `CCLOAD_COOLDOWN_AUTH_SEC` | `300` | Auth error (401/402/403) initial cooldown (seconds) | | `CCLOAD_COOLDOWN_SERVER_SEC` | `120` | Server error (5xx) initial cooldown (seconds) | | `CCLOAD_COOLDOWN_TIMEOUT_SEC` | `60` | Timeout error (597/598) initial cooldown (seconds) | | `CCLOAD_COOLDOWN_RATE_LIMIT_SEC` | `60` | Rate limit error (429) initial cooldown (seconds) | | `CCLOAD_COOLDOWN_MAX_SEC` | `1800` | Exponential backoff cooldown max (seconds, 30 minutes) | | `CCLOAD_COOLDOWN_MIN_SEC` | `10` | Exponential backoff cooldown min (seconds) | #### Hybrid Storage Mode (MySQL Primary + SQLite Cache) HuggingFace Spaces and similar environments lose local data on restart, but free MySQL has high query latency (800ms+). Hybrid mode offers the best of both worlds: - **MySQL Primary Storage**: Write operations go to MySQL first, ensuring data persistence - **SQLite Local Cache**: Read operations go through local SQLite, latency <1ms - **Startup Recovery**: Restore data from MySQL to SQLite, supports restoring logs by days - **Log Special Handling**: Write to SQLite first (fast), then async sync to MySQL (backup) ```bash # Enable hybrid mode export CCLOAD_MYSQL="user:pass@tcp(host:3306)/db?charset=utf8mb4" export CCLOAD_ENABLE_SQLITE_REPLICA=1 export CCLOAD_SQLITE_LOG_DAYS=7 # Restore last 7 days of logs (optional) ``` **Three Storage Modes**: | Mode | Configuration | Use Case | |------|---------------|----------| | Pure SQLite | Don't set `CCLOAD_MYSQL` | Local dev, single instance | | Pure MySQL | Set `CCLOAD_MYSQL` | Standard production | | Hybrid Mode | Set `CCLOAD_MYSQL` + `CCLOAD_ENABLE_SQLITE_REPLICA=1` | HuggingFace Spaces | ### Web Admin Configuration (Hot Reload Supported) These settings have been migrated to database, managed via Web interface `/web/settings.html`, changes take effect immediately without restart: | Setting | Default | Description | |---------|---------|-------------| | `log_retention_days` | `7` | Log retention days (-1 for permanent, 1-365 days) | | `max_key_retries` | `3` | Max key retries within single channel | | `upstream_first_byte_timeout` | `0` | Upstream first valid stream content timeout (seconds, 0=disabled, stream only) | | `enable_health_score` | `false` | Enable health-based dynamic channel sorting | | `success_rate_penalty_weight` | `100` | Success rate penalty weight (see below) | | `health_score_window_minutes` | `30` | Success rate stats time window (minutes) | | `health_score_update_interval` | `30` | Success rate cache update interval (seconds) | | `health_min_confident_sample` | `20` | Confidence sample threshold (full penalty at this sample size) | | `channel_check_interval_hours` | `0` | Scheduled channel check interval (hours, 0=disabled) | #### Health Score Sorting When `enable_health_score` is enabled, the system dynamically adjusts priority based on channel success rate: ``` confidence = min(1.0, sample_count / health_min_confident_sample) effective_priority = base_priority - (failure_rate ร— success_rate_penalty_weight ร— confidence) ``` **Confidence Factor**: Solves over-penalization of new or low-traffic channels due to small sample sizes. Smaller samples = lower confidence = more penalty discount. **Example** (`success_rate_penalty_weight = 100`, `health_min_confident_sample = 20`): | Channel | Base Priority | Success Rate | Samples | Confidence | Penalty | Effective Priority | |---------|---------------|--------------|---------|------------|---------|-------------------| | A | 100 | 95% | 100 | 1.0 | 5 | **95** | | B | 90 | 70% | 80 | 1.0 | 30 | **60** | | C | 80 | 60% | 4 | 0.2 | 8 | **72** | | D | 70 | 100% | 50 | 1.0 | 0 | **70** | Base priority order: A > B > C > D **Effective priority order: A (95) > C (72) > D (70) > B (60)** #### API Access Token Configuration **Important**: API access tokens are normally managed in the Web admin interface; Docker and CI deployments can pre-seed them with an environment variable. - Visit `http://localhost:8080/web/tokens.html` for token management - Set `CCLOAD_API_TOKENS=token1|production,token2|development` to create missing tokens on startup - Provisioning is idempotent: existing tokens keep their description, limits, model/channel restrictions, and statistics - Only missing tokens are created; existing tokens are never modified - Supports add, delete, view tokens - All tokens stored in database with persistence - Without any tokens configured, all `/v1/*` and `/v1beta/*` APIs return `401 Unauthorized` โš ๏ธ **Security notes**: - In production, prefer Docker Secrets, Kubernetes Secrets, or platform encrypted Secrets over plain environment variables - In CI/CD, do not print full environment variables to logs - After provisioning, remove `CCLOAD_API_TOKENS` from deployment config if automatic recovery is no longer needed - Restrict access to container inspect output, orchestration dashboards, and deployment configuration **Advanced Token Features** (2026-01 New): - **Cost Limits**: Set cost limits per token (USD), requests rejected with 429 when exceeded - **Model Restrictions**: Restrict which models a token can access for fine-grained access control - **First Byte Time**: Records streaming request TTFB (milliseconds) for upstream latency diagnosis #### Behavior Summary - `CCLOAD_PASS` not set: Program fails to start and exits (secure default) - No API access tokens configured: All `/v1/*` and `/v1beta/*` APIs return `401 Unauthorized`. Configure tokens via Web interface `/web/tokens.html` - Public endpoints: `GET /health` (health check) and `GET /public/summary` (stats summary) require no auth, all others require auth token ### Docker Images Project supports multi-arch Docker images: - **Supported Architectures**: `linux/amd64`, `linux/arm64` - **Image Registry**: `ghcr.io/caidaoli/ccload` - **Available Tags**: - `latest` - Latest stable version - `2.19.0` - Specific version number - `2.19` - Major.minor version - `2` - Major version ### Image Tag Guide ```bash # Pull latest version docker pull ghcr.io/caidaoli/ccload:latest # Pull specific version docker pull ghcr.io/caidaoli/ccload:2.19.0 # Specify architecture (Docker usually auto-selects) docker pull --platform linux/amd64 ghcr.io/caidaoli/ccload:latest docker pull --platform linux/arm64 ghcr.io/caidaoli/ccload:latest ``` ### Database Structure **Storage Architecture (Factory Pattern)**: ``` storage/ โ”œโ”€โ”€ store.go # Store interface (unified contract) โ”œโ”€โ”€ factory.go # NewStore() auto-selects database โ”œโ”€โ”€ schema/ # Unified schema definition layer (2025-12 new) โ”‚ โ”œโ”€โ”€ tables.go # Table definitions (DefineXxxTable functions) โ”‚ โ””โ”€โ”€ builder.go # Schema builder (supports SQLite/MySQL differences) โ”œโ”€โ”€ sql/ # Common SQL implementation layer (2025-12 refactor, eliminated 467 lines) โ”‚ โ”œโ”€โ”€ store_impl.go # SQLStore core implementation โ”‚ โ”œโ”€โ”€ config.go # Channel config CRUD โ”‚ โ”œโ”€โ”€ apikey.go # API key CRUD โ”‚ โ”œโ”€โ”€ cooldown.go # Cooldown management โ”‚ โ”œโ”€โ”€ log.go # Log storage โ”‚ โ”œโ”€โ”€ metrics.go # Metrics stats โ”‚ โ”œโ”€โ”€ metrics_filter.go # Filter intersection support โ”‚ โ”œโ”€โ”€ metrics_aggregate_rows.go # Aggregate row processing โ”‚ โ”œโ”€โ”€ metrics_finalize.go # Finalization processing โ”‚ โ”œโ”€โ”€ auth_tokens.go # API access tokens โ”‚ โ”œโ”€โ”€ auth_token_stats.go # Token statistics โ”‚ โ”œโ”€โ”€ admin_sessions.go # Admin sessions โ”‚ โ”œโ”€โ”€ system_settings.go # System settings โ”‚ โ””โ”€โ”€ helpers.go # Helper functions โ””โ”€โ”€ sqlite/ # SQLite specific (test files only) ``` **Database Selection Logic**: - `CCLOAD_MYSQL` environment variable set โ†’ Uses MySQL - Not set โ†’ Uses SQLite (default) **Core Table Structure** (SQLite and MySQL shared): - `channels` - Channel config (cooldown data inline, UNIQUE constraint on name, with protocol transform config, scheduled check config, RPM limit config) - `api_keys` - API keys (key-level cooldown inline, multi-key strategies) - `logs` - Request logs (with base_url upstream URL tracking) - `debug_logs` - Debug logs (upstream request/response raw data, independent cleanup policy) - `key_rr` - Round-robin pointers (channel_id โ†’ idx) - `auth_tokens` - Auth tokens (with cost limits, model restrictions, first byte time tracking) - `admin_sessions` - Admin sessions - `system_settings` - System config (hot reload support) **Architecture Features** (โœ… 2025-12 through 2026-04 continuous improvements): - โœ… **Unified SQL Layer** (refactor): SQLite/MySQL share `storage/sql/` implementation, eliminated 467 lines of duplicate code - โœ… **Unified Schema Definition** (new): `storage/schema/` defines table structures, supports database differences - โœ… Factory pattern unified interface (OCP, easy to extend new storage) - โœ… Cooldown data inline (deprecated separate cooldowns table, reduces JOIN overhead) - โœ… Performance index optimization (channel selection latency โ†“30-50%, key lookup latency โ†“40-60%) - โœ… Composite index optimization (stats query performance improved) - โœ… Foreign key constraints (cascade delete, ensures data consistency) - โœ… Multi-key support (sequential/round_robin strategies) - โœ… Auto migration (auto creates/updates table structure on startup) - โœ… Token stats enhancement (time range selection, per-token ID classification, cache optimization) - โœ… **service_tier cost tracking**: Logs persist service_tier field, cost column shows tier label - โœ… **Responses image tool cost tracking**: `image_generation` tool costs are included in logs, stats, and cost limit accounting - โœ… **Tiered pricing engine**: GPT-5.4/Qwen-Plus/Gemini long-context step billing - โœ… **Log UX improvements**: Cost column formats to 3 decimal places (empty for zero), IP column shows full address on hover - โœ… **Protocol transform system**: Anthropic/OpenAI/Gemini/Codex four-protocol cross-conversion, upstream/local modes - โœ… **Debug logs**: Upstream request/response raw data capture, sensitive header masking, independent cleanup policy - โœ… **Scheduled channel checks**: Background periodic channel availability probing, configurable check model per channel - โœ… **Channel RPM limits**: Per-channel rolling 60-second request caps, `0` means unlimited, over-limit channels are skipped **Backward Compatible Migration**: - Auto-detects and fixes duplicate channel names - Intelligently adds UNIQUE constraints, ensures data integrity - Runs automatically on startup, no manual intervention needed - Log database merged into main database (single data source) ## ๐Ÿ›ก๏ธ Security Considerations - Production must set strong password `CCLOAD_PASS` - Configure API access tokens via Web admin `/web/tokens.html` to protect API endpoint access - API keys used only in memory, not logged - Tokens stored in client localStorage, 24-hour expiry - Recommend using HTTPS reverse proxy - Docker images run as non-root user for enhanced security ### Token Authentication System ccLoad uses token-based authentication for simple and efficient secure access control. **Auth Methods**: - **Admin Interface**: Login gets 24-hour token, stored in `localStorage` - **API Endpoints**: Support `Authorization: Bearer ` header auth **Core Features**: - โœ… **Stateless Auth**: Tokens don't depend on server sessions, naturally supports horizontal scaling - โœ… **Unified Auth System**: API and admin interface use same token mechanism - โœ… **Simple Architecture**: Pure token auth, simple reliable code (KISS principle) - โœ… **CORS Support**: Token stored in localStorage, fully supports cross-origin access **Usage Example**: ```bash # 1. Login to get token curl -X POST http://localhost:8080/login \ -H "Content-Type: application/json" \ -d '{"password":"your_admin_password"}' | jq # Response example: # { # "status": "success", # "token": "abc123...", # 64-char hex token # "expiresIn": 86400 # 24 hours (seconds) # } # 2. Use token to access admin API curl http://localhost:8080/admin/channels \ -H "Authorization: Bearer " # 3. Logout (optional, token auto-expires after 24 hours) curl -X POST http://localhost:8080/logout \ -H "Authorization: Bearer " ``` ## ๐Ÿ”„ CI/CD Project uses GitHub Actions for automated CI/CD: - **Trigger Conditions**: Push version tags (`v*`) or manual trigger - **Build Output**: Multi-arch Docker images pushed to GitHub Container Registry - **Version Management**: Auto-generates semantic version tags - **Cache Optimization**: Uses GitHub Actions cache to accelerate builds ## ๐Ÿค Contributing Issues and Pull Requests welcome! ### Troubleshooting **Port In Use**: ```bash # Find and kill process using port 8080 lsof -i :8080 && kill -9 ``` **Container Issues**: ```bash # View container logs docker logs ccload -f # Check container health status docker inspect ccload --format='{{.State.Health.Status}}' ``` **Config Validation**: ```bash # Test service health (lightweight health check, <5ms) curl -s http://localhost:8080/health # Or view stats summary (returns business data, 50-200ms) curl -s http://localhost:8080/public/summary # Check environment variable config env | grep CCLOAD ``` ## ๐Ÿ“„ License MIT License