| # ccLoad - Claude Code & Codex & Gemini & OpenAI Compatible API Proxy Service |
|
|
| **English | [简体中文](README.md)** |
|
|
| [](https://golang.org) |
| [](https://github.com/gin-gonic/gin) |
| [](https://hub.docker.com) |
| [](https://huggingface.co/spaces) |
| [](https://github.com/features/actions) |
| [](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<br/>Priority:10] |
| F --> H[Channel B<br/>Priority:5] |
| F --> I[Channel C<br/>Priority:5] |
| G --> G1[URL Selector<br/>Weighted Random] |
| H --> H1[URL Selector<br/>Weighted Random] |
| I --> I1[URL Selector<br/>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 👇 |
|
|
|  |
|  |
| *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`)<br/>**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 <token>` 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 <your_token>" |
| |
| # 3. Logout (optional, token auto-expires after 24 hours) |
| curl -X POST http://localhost:8080/logout \ |
| -H "Authorization: Bearer <your_token>" |
| ``` |
|
|
| ## 🔄 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 <PID> |
| ``` |
|
|
| **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 |
|
|