cc-gateway-ai-proxy

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

CC Gateway — AI API Identity Gateway

CC Gateway — AI API身份网关

Skill by ara.so — Daily 2026 Skills collection.
CC Gateway is a TypeScript reverse proxy that sits between Claude Code clients and the Anthropic API. It normalizes 40+ device fingerprint dimensions (device ID, email, environment, RAM, headers, and system prompt content) to a single canonical identity, manages OAuth token refresh centrally, and prevents telemetry leakage from multi-machine setups.
技能由 ara.so 提供 — 2026年度技能合集。
CC Gateway是一款TypeScript编写的反向代理,部署在Claude Code客户端与Anthropic API之间。它可将40+项设备指纹维度(设备ID、邮箱、运行环境、RAM、请求头、系统提示词内容)标准化为单一规范身份,集中管理OAuth令牌刷新,防止多设备部署场景下的遥测数据泄露。

Architecture Overview

架构概述

Client (Claude Code + env vars + Clash)
  └─► CC Gateway (rewrite + auth inject + SSE passthrough)
        └─► api.anthropic.com (single canonical identity)
              
Gateway also contacts:
  platform.claude.com (OAuth token refresh only)
Three-layer defense:
LayerMechanism
Env varsRoute CC traffic to gateway, disable side channels
Clash rulesBlock any direct Anthropic connections at network level
GatewayRewrite all 40+ fingerprint dimensions in-flight
Client (Claude Code + env vars + Clash)
  └─► CC Gateway (rewrite + auth inject + SSE passthrough)
        └─► api.anthropic.com (single canonical identity)
              
Gateway also contacts:
  platform.claude.com (OAuth token refresh only)
三层防护机制:
层级防护机制
环境变量将Claude Code流量路由到网关,禁用侧边通道
Clash规则在网络层面拦截所有直接访问Anthropic的请求
网关动态重写全部40+项指纹维度

Installation

安装

Prerequisites

前置要求

  • Node.js 18+ or Docker
  • A machine that has previously logged into Claude Code (for OAuth token extraction)
  • Node.js 18+ 或 Docker
  • 曾登录过Claude Code的机器(用于提取OAuth令牌)

Clone and Install

克隆与安装

bash
git clone https://github.com/motiful/cc-gateway.git
cd cc-gateway
npm install
bash
git clone https://github.com/motiful/cc-gateway.git
cd cc-gateway
npm install

Generate Identity and Tokens

生成身份与令牌

bash
undefined
bash
undefined

Create a stable canonical identity (device_id, email, env profile)

创建稳定的规范身份(device_id、邮箱、环境配置)

npm run generate-identity
npm run generate-identity

Create a bearer token for a specific client machine

为指定客户端机器生成Bearer令牌

npm run generate-token my-laptop npm run generate-token work-desktop
undefined
npm run generate-token my-laptop npm run generate-token work-desktop
undefined

Extract OAuth Token (from a logged-in machine)

提取OAuth令牌(从已登录的机器)

bash
undefined
bash
undefined

macOS — copies refresh_token from Keychain

macOS — 从钥匙串复制refresh_token

bash scripts/extract-token.sh
undefined
bash scripts/extract-token.sh
undefined

Configure

配置

bash
cp config.example.yaml config.yaml
Edit
config.yaml
:
yaml
undefined
bash
cp config.example.yaml config.yaml
编辑
config.yaml
yaml
undefined

config.yaml

config.yaml

identity: device_id: "GENERATED_DEVICE_ID" # from generate-identity email: "canonical@example.com" platform: "darwin" arch: "arm64" node_version: "20.11.0" shell: "/bin/zsh" home: "/Users/canonical" working_directory: "/Users/canonical/projects" memory_gb: 16 # canonical RAM value
oauth: refresh_token: "EXTRACTED_REFRESH_TOKEN" # from extract-token.sh
clients:
  • name: my-laptop token: "GENERATED_CLIENT_TOKEN"
  • name: work-desktop token: "ANOTHER_CLIENT_TOKEN"
server: port: 8443 tls: false # true for production with certs
undefined
identity: device_id: "GENERATED_DEVICE_ID" # 来自generate-identity命令输出 email: "canonical@example.com" platform: "darwin" arch: "arm64" node_version: "20.11.0" shell: "/bin/zsh" home: "/Users/canonical" working_directory: "/Users/canonical/projects" memory_gb: 16 # 规范RAM值
oauth: refresh_token: "EXTRACTED_REFRESH_TOKEN" # 来自extract-token.sh命令输出
clients:
  • name: my-laptop token: "GENERATED_CLIENT_TOKEN"
  • name: work-desktop token: "ANOTHER_CLIENT_TOKEN"
server: port: 8443 tls: false # 生产环境带证书时设置为true
undefined

Starting the Gateway

启动网关

bash
undefined
bash
undefined

Development (no TLS, hot reload)

开发模式(无TLS、热重载)

npm run dev
npm run dev

Production build

生产构建

npm run build && npm start
npm run build && npm start

Docker Compose (recommended for production)

Docker Compose(生产环境推荐)

docker-compose up -d
undefined
docker-compose up -d
undefined

Docker Compose Example

Docker Compose示例

yaml
undefined
yaml
undefined

docker-compose.yml

docker-compose.yml

version: "3.8" services: cc-gateway: build: . ports: - "8443:8443" volumes: - ./config.yaml:/app/config.yaml:ro restart: unless-stopped environment: - NODE_ENV=production
undefined
version: "3.8" services: cc-gateway: build: . ports: - "8443:8443" volumes: - ./config.yaml:/app/config.yaml:ro restart: unless-stopped environment: - NODE_ENV=production
undefined

Verification

验证

bash
undefined
bash
undefined

Health check

健康检查

Show before/after rewrite diff (requires client token)

查看重写前后的差异(需要客户端令牌)

curl -H "Authorization: Bearer YOUR_CLIENT_TOKEN"
http://localhost:8443/_verify
undefined
curl -H "Authorization: Bearer YOUR_CLIENT_TOKEN"
http://localhost:8443/_verify
undefined

Client Machine Setup

客户端机器配置

On each machine running Claude Code, set these environment variables:
bash
undefined
在每台运行Claude Code的机器上,设置以下环境变量:
bash
undefined

~/.bashrc or ~/.zshrc

~/.bashrc 或 ~/.zshrc

Route all Claude Code API traffic through the gateway

将所有Claude Code API流量路由到网关

export ANTHROPIC_BASE_URL="https://gateway.your-domain.com:8443"
export ANTHROPIC_BASE_URL="https://gateway.your-domain.com:8443"

Disable side-channel telemetry (Datadog, GrowthBook, version checks)

禁用侧边通道遥测(Datadog、GrowthBook、版本检查)

export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1

Skip browser OAuth — gateway handles authentication

跳过浏览器OAuth — 网关负责身份认证

export CLAUDE_CODE_OAUTH_TOKEN="gateway-managed"
export CLAUDE_CODE_OAUTH_TOKEN="gateway-managed"

Authenticate to the gateway with the per-machine token

使用单设备专属令牌向网关认证

export ANTHROPIC_CUSTOM_HEADERS="Proxy-Authorization: Bearer YOUR_CLIENT_TOKEN"

Or use the interactive setup script:

```bash
bash scripts/client-setup.sh
Then just run
claude
— no login prompt required.
export ANTHROPIC_CUSTOM_HEADERS="Proxy-Authorization: Bearer YOUR_CLIENT_TOKEN"

或者使用交互式配置脚本:

```bash
bash scripts/client-setup.sh
之后直接运行
claude
即可,无需登录弹窗。

Clash Rules (Network-Level Blocking)

Clash规则(网络层级拦截)

Add to your Clash configuration to block any direct Anthropic connections:
yaml
undefined
在你的Clash配置中添加以下规则,拦截所有直接访问Anthropic的请求:
yaml
undefined

clash-rules.yaml excerpt

clash-rules.yaml 片段

rules:
  • DOMAIN,gateway.your-domain.com,DIRECT # Allow your gateway
  • DOMAIN-SUFFIX,anthropic.com,REJECT # Block direct API calls
  • DOMAIN-SUFFIX,claude.com,REJECT # Block direct OAuth
  • DOMAIN-SUFFIX,claude.ai,REJECT # Block Claude web
  • DOMAIN-SUFFIX,datadoghq.com,REJECT # Block Datadog telemetry
  • DOMAIN-SUFFIX,statsig.com,REJECT # Block feature flags

See `clash-rules.yaml` in the repo for the full template.
rules:
  • DOMAIN,gateway.your-domain.com,DIRECT # 放行你的网关地址
  • DOMAIN-SUFFIX,anthropic.com,REJECT # 拦截直接API调用
  • DOMAIN-SUFFIX,claude.com,REJECT # 拦截直接OAuth请求
  • DOMAIN-SUFFIX,claude.ai,REJECT # 拦截Claude网页端
  • DOMAIN-SUFFIX,datadoghq.com,REJECT # 拦截Datadog遥测
  • DOMAIN-SUFFIX,statsig.com,REJECT # 拦截特征旗标请求

完整模板可查看仓库中的`clash-rules.yaml`文件。

What Gets Rewritten

重写内容说明

LayerFieldTransformation
Identity
device_id
→ canonical ID from config
Identity
email
→ canonical email
Environment
env
object (40+ fields)
→ entire object replaced
Process
constrainedMemory
(physical RAM)
→ canonical value
Process
rss
,
heapTotal
,
heapUsed
→ randomized in realistic range
Headers
User-Agent
→ canonical CC version string
Headers
Authorization
→ real OAuth token (injected)
Headers
x-anthropic-billing-header
→ canonical fingerprint
Prompt text
Platform
,
Shell
,
OS Version
→ canonical values
Prompt text
/Users/xxx/
,
/home/xxx/
→ canonical home prefix
Leak fields
baseUrl
→ stripped
Leak fields
gateway
provider field
→ stripped
层级字段转换规则
身份
device_id
→ 配置中的规范ID
身份
email
→ 规范邮箱
环境
env
对象(40+字段)
→ 替换为完整的规范对象
进程
constrainedMemory
(物理RAM)
→ 规范值
进程
rss
heapTotal
heapUsed
→ 在合理范围内随机化
请求头
User-Agent
→ 规范的CC版本字符串
请求头
Authorization
→ 注入真实OAuth令牌
请求头
x-anthropic-billing-header
→ 规范指纹
提示词文本
Platform
Shell
OS Version
→ 规范值
提示词文本
/Users/xxx/
/home/xxx/
→ 规范的home路径前缀
泄露字段
baseUrl
→ 移除
泄露字段
gateway
提供者字段
→ 移除

TypeScript Usage Examples

TypeScript使用示例

Custom Rewriter Extension

自定义重写器扩展

typescript
// src/rewriters/custom-field-rewriter.ts
import { RequestRewriter } from '../types';

export const customFieldRewriter: RequestRewriter = {
  name: 'custom-field-rewriter',
  
  rewriteBody(body: Record<string, unknown>, config: CanonicalConfig): Record<string, unknown> {
    // Strip any custom analytics fields your org adds
    const { __analytics, __session_debug, ...cleaned } = body as any;
    
    // Normalize any additional identity fields
    if (cleaned.metadata?.user_id) {
      cleaned.metadata.user_id = config.identity.device_id;
    }
    
    return cleaned;
  },
  
  rewriteHeaders(headers: Record<string, string>, config: CanonicalConfig): Record<string, string> {
    return {
      ...headers,
      'x-custom-client': 'canonical',
    };
  }
};
typescript
// src/rewriters/custom-field-rewriter.ts
import { RequestRewriter } from '../types';

export const customFieldRewriter: RequestRewriter = {
  name: 'custom-field-rewriter',
  
  rewriteBody(body: Record<string, unknown>, config: CanonicalConfig): Record<string, unknown> {
    // 移除你的组织添加的自定义分析字段
    const { __analytics, __session_debug, ...cleaned } = body as any;
    
    // 标准化其他额外身份字段
    if (cleaned.metadata?.user_id) {
      cleaned.metadata.user_id = config.identity.device_id;
    }
    
    return cleaned;
  },
  
  rewriteHeaders(headers: Record<string, string>, config: CanonicalConfig): Record<string, string> {
    return {
      ...headers,
      'x-custom-client': 'canonical',
    };
  }
};

Programmatic Gateway Start

编程式启动网关

typescript
// scripts/start-with-monitoring.ts
import { createGateway } from '../src/gateway';
import { loadConfig } from '../src/config';

async function main() {
  const config = await loadConfig('./config.yaml');
  
  const gateway = await createGateway(config);
  
  gateway.on('request', ({ clientId, path }) => {
    console.log(`[${new Date().toISOString()}] ${clientId}${path}`);
  });
  
  gateway.on('rewrite', ({ field, before, after }) => {
    console.log(`Rewrote ${field}: ${before}${after}`);
  });
  
  gateway.on('tokenRefresh', ({ expiresAt }) => {
    console.log(`OAuth token refreshed, expires: ${expiresAt}`);
  });
  
  await gateway.listen(config.server.port);
  console.log(`Gateway running on port ${config.server.port}`);
}

main().catch(console.error);
typescript
// scripts/start-with-monitoring.ts
import { createGateway } from '../src/gateway';
import { loadConfig } from '../src/config';

async function main() {
  const config = await loadConfig('./config.yaml');
  
  const gateway = await createGateway(config);
  
  gateway.on('request', ({ clientId, path }) => {
    console.log(`[${new Date().toISOString()}] ${clientId}${path}`);
  });
  
  gateway.on('rewrite', ({ field, before, after }) => {
    console.log(`Rewrote ${field}: ${before}${after}`);
  });
  
  gateway.on('tokenRefresh', ({ expiresAt }) => {
    console.log(`OAuth token refreshed, expires: ${expiresAt}`);
  });
  
  await gateway.listen(config.server.port);
  console.log(`Gateway running on port ${config.server.port}`);
}

main().catch(console.error);

Token Generation (Programmatic)

编程式生成令牌

typescript
// scripts/provision-client.ts
import { generateClientToken, addClientToConfig } from '../src/auth';

async function provisionNewMachine(machineName: string) {
  const token = await generateClientToken(machineName);
  
  await addClientToConfig('./config.yaml', {
    name: machineName,
    token,
    created_at: new Date().toISOString(),
  });
  
  console.log(`Client token for ${machineName}:`);
  console.log(token);
  console.log('\nAdd to client machine:');
  console.log(`export ANTHROPIC_CUSTOM_HEADERS="Proxy-Authorization: Bearer ${token}"`);
}

provisionNewMachine(process.argv[2] ?? 'new-machine');
typescript
// scripts/provision-client.ts
import { generateClientToken, addClientToConfig } from '../src/auth';

async function provisionNewMachine(machineName: string) {
  const token = await generateClientToken(machineName);
  
  await addClientToConfig('./config.yaml', {
    name: machineName,
    token,
    created_at: new Date().toISOString(),
  });
  
  console.log(`Client token for ${machineName}:`);
  console.log(token);
  console.log('\nAdd to client machine:');
  console.log(`export ANTHROPIC_CUSTOM_HEADERS="Proxy-Authorization: Bearer ${token}"`);
}

provisionNewMachine(process.argv[2] ?? 'new-machine');

Key npm Scripts

核心npm脚本

CommandPurpose
npm run dev
Start with hot reload (development)
npm run build
Compile TypeScript to
dist/
npm start
Run compiled production build
npm test
Run rewriter test suite (13 tests)
npm run generate-identity
Create canonical device profile
npm run generate-token <name>
Create per-client bearer token
命令用途
npm run dev
热重载启动(开发环境)
npm run build
将TypeScript编译到
dist/
目录
npm start
运行编译后的生产构建版本
npm test
运行重写器测试套件(13项测试)
npm run generate-identity
创建规范设备配置文件
npm run generate-token <name>
生成单客户端Bearer令牌

Common Patterns

常见使用场景

Multiple Machines, One Identity

多设备共享同一身份

bash
undefined
bash
undefined

On gateway server — generate once

在网关服务器上 — 仅需执行一次

npm run generate-identity
npm run generate-identity

→ device_id: abc-123, email: canonical@proxy.local

→ device_id: abc-123, email: canonical@proxy.local

Provision each machine

为每台机器分配令牌

npm run generate-token laptop-home # → token-aaa npm run generate-token laptop-work # → token-bbb
npm run generate-token desktop # → token-ccc
npm run generate-token laptop-home # → token-aaa npm run generate-token laptop-work # → token-bbb
npm run generate-token desktop # → token-ccc

All three machines present as the same device to Anthropic

三台机器对Anthropic都表现为同一设备

undefined
undefined

Rotating the Canonical Identity

轮换规范身份

bash
undefined
bash
undefined

Generate a new identity (e.g., after a suspected flag)

生成新身份(例如怀疑账号被标记时)

npm run generate-identity --force
npm run generate-identity --force

Update config.yaml with new device_id

用新的device_id更新config.yaml

Restart gateway — all clients immediately use new identity

重启网关 — 所有客户端立即使用新身份

docker-compose restart cc-gateway
undefined
docker-compose restart cc-gateway
undefined

Checking for New Telemetry Fields After CC Updates

CC更新后检查新遥测字段

bash
undefined
bash
undefined

After a Claude Code update, use _verify to diff

Claude Code更新后,使用_verify接口查看差异

curl -H "Authorization: Bearer $TOKEN"
http://localhost:8443/_verify | jq '.unrewritten_fields'
curl -H "Authorization: Bearer $TOKEN"
http://localhost:8443/_verify | jq '.unrewritten_fields'

Monitor Clash logs for new endpoints

监控Clash日志排查新端点

Any REJECT hits on new domains = new hardcoded endpoints

任何新域名的REJECT命中 = 新的硬编码端点

undefined
undefined

Troubleshooting

故障排查

claude
still prompts for browser login

claude
仍弹出浏览器登录提示

  • Ensure
    CLAUDE_CODE_OAUTH_TOKEN=gateway-managed
    is exported
  • Verify
    ANTHROPIC_BASE_URL
    points to your running gateway
  • Check gateway logs:
    docker-compose logs -f cc-gateway
  • 确保已导出
    CLAUDE_CODE_OAUTH_TOKEN=gateway-managed
  • 验证
    ANTHROPIC_BASE_URL
    指向你运行的网关地址
  • 检查网关日志:
    docker-compose logs -f cc-gateway

401 Unauthorized from gateway

网关返回401未授权

  • Confirm
    ANTHROPIC_CUSTOM_HEADERS
    contains
    Proxy-Authorization: Bearer <token>
  • Verify the token in config.yaml matches the one set in env var
  • Run
    curl -H "Authorization: Bearer $TOKEN" http://localhost:8443/_health
  • 确认
    ANTHROPIC_CUSTOM_HEADERS
    包含
    Proxy-Authorization: Bearer <token>
  • 验证config.yaml中的令牌与环境变量中设置的一致
  • 运行
    curl -H "Authorization: Bearer $TOKEN" http://localhost:8443/_health
    排查

OAuth token expired

OAuth令牌过期

bash
undefined
bash
undefined

Re-extract from a logged-in machine

从已登录的机器重新提取

bash scripts/extract-token.sh
bash scripts/extract-token.sh

Paste new refresh_token into config.yaml

将新的refresh_token粘贴到config.yaml

docker-compose restart cc-gateway
undefined
docker-compose restart cc-gateway
undefined

MCP servers bypassing gateway

MCP服务器绕过网关

MCP uses
mcp-proxy.anthropic.com
which ignores
ANTHROPIC_BASE_URL
. Add to Clash:
yaml
- DOMAIN,mcp-proxy.anthropic.com,REJECT
MCP使用
mcp-proxy.anthropic.com
,该地址会忽略
ANTHROPIC_BASE_URL
。在Clash中添加规则:
yaml
- DOMAIN,mcp-proxy.anthropic.com,REJECT

Requests reaching Anthropic directly (Clash not blocking)

请求直接到达Anthropic(Clash未拦截)

  • Check Clash is running:
    clash -v
  • Verify rules are loaded: look for REJECT entries in Clash dashboard
  • Test:
    curl https://api.anthropic.com
    — should fail if Clash is active
  • 检查Clash是否运行:
    clash -v
  • 验证规则已加载:在Clash控制台中查看REJECT条目
  • 测试:
    curl https://api.anthropic.com
    — 如果Clash正常运行应该请求失败

Gateway rewrite not applying to a new field

新字段未应用网关重写

After a Claude Code update, new telemetry fields may not be covered. Check
/_verify
for
unrewritten_fields
, then open an issue or add a custom rewriter (see Custom Rewriter Extension above).
Claude Code更新后,可能出现未覆盖的新遥测字段。检查
/_verify
接口的
unrewritten_fields
,然后提交Issue或者添加自定义重写器(参考上方自定义重写器扩展部分)。

Caveats

注意事项

  • MCP servers — hardcoded endpoint, use Clash to block if not needed
  • CC updates — monitor Clash REJECT logs after every Claude Code update for new endpoints
  • Refresh token lifetime — if the OAuth refresh token expires, re-run
    extract-token.sh
  • ToS — do not use for account sharing; intended for managing your own devices under one subscription
  • Alpha — test with a non-primary account before production use
  • MCP服务器 — 端点为硬编码,不需要的话可以用Clash拦截
  • CC更新 — 每次Claude Code更新后都要监控Clash的REJECT日志,排查新端点
  • 刷新令牌生命周期 — 如果OAuth刷新令牌过期,重新运行
    extract-token.sh
    即可
  • 服务条款 — 请勿用于账号共享,仅适用于同一订阅下管理你自己的多台设备
  • Alpha版本 — 生产使用前请先在非主账号上测试