週末的狂歡party,奧特曼給了我們的大禮物,這一次我沒跟上,因為一直在折騰CPA,加上又是深夜,忍不住說著了,起床的時候已經人去樓空…
站內有許多大佬給出CPA的詳細部屬的教程,我這邊分享一個奴役AI寫的腳本,把需要的東西放好,一鍵執行,就可以把你的CPA弄好,希望對大家有幫助,如果奧特曼在發免費禮物,party狂歡的時候大家也能一同參與
(sh 腳本 改成txt 因為不然不能上船,直接貼出來,上船死活不給)
#!/bin/bash
# ============================================================================
# CLIProxyAPI One-Click Deploy Script
# ============================================================================
# Usage: bash deploy-cpa.sh config.txt
#
# Config file format (one per line):
# CF_EMAIL=your@email.com
# CF_API_KEY=your_global_api_key
# CF_ACCOUNT_ID=your_account_id
# CF_ZONE_ID=your_zone_id
# DOMAIN=cpa.yourdomain.com
# TOKENS_PATH=/path/to/tokens.zip
# API_KEY=sk-cpa-custom-key (optional, auto-generated if missing)
# MGMT_KEY=mgt-cpa-custom-key (optional, auto-generated if missing)
# TUNNEL_NAME=cpa-proxy (optional, defaults to cpa-proxy)
# ============================================================================
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
log() { echo -e "${GREEN}[✓]${NC} $1"; }
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
err() { echo -e "${RED}[✗]${NC} $1"; exit 1; }
info() { echo -e "${BLUE}[i]${NC} $1"; }
# ============================================================================
# Check arguments
# ============================================================================
if [ -z "$1" ]; then
echo ""
echo -e "${CYAN}CLIProxyAPI One-Click Deploy${NC}"
echo ""
echo "Usage: bash deploy-cpa.sh <config-file>"
echo ""
echo "Create a config file with the following format:"
echo ""
echo " CF_EMAIL=your@email.com"
echo " CF_API_KEY=your_global_api_key"
echo " CF_ACCOUNT_ID=your_account_id"
echo " CF_ZONE_ID=your_zone_id"
echo " DOMAIN=cpa.yourdomain.com"
echo " TOKENS_PATH=/path/to/tokens.zip"
echo ""
echo "Optional:"
echo " API_KEY=sk-cpa-custom-key"
echo " MGMT_KEY=mgt-cpa-custom-key"
echo " TUNNEL_NAME=cpa-proxy"
echo ""
exit 1
fi
CONFIG_FILE="$1"
[ ! -f "$CONFIG_FILE" ] && err "Config file not found: $CONFIG_FILE"
# ============================================================================
# Load config
# ============================================================================
info "Loading config from $CONFIG_FILE..."
# Source the config file
set -a
source "$CONFIG_FILE"
set +a
# Validate required fields
[ -z "$CF_EMAIL" ] && err "CF_EMAIL is required"
[ -z "$CF_API_KEY" ] && err "CF_API_KEY is required"
[ -z "$CF_ACCOUNT_ID" ] && err "CF_ACCOUNT_ID is required"
[ -z "$CF_ZONE_ID" ] && err "CF_ZONE_ID is required"
[ -z "$DOMAIN" ] && err "DOMAIN is required (e.g., cpa.yourdomain.com)"
[ -z "$TOKENS_PATH" ] && err "TOKENS_PATH is required (path to token zip files)"
# Set defaults
TUNNEL_NAME="${TUNNEL_NAME:-cpa-proxy}"
API_KEY="${API_KEY:-sk-cpa-$(tr -dc 'a-z0-9' </dev/urandom | head -c 32)}"
MGMT_KEY="${MGMT_KEY:-mgt-cpa-$(tr -dc 'a-z0-9' </dev/urandom | head -c 32)}"
INSTALL_DIR="/root/cpa"
AUTH_DIR="/root/.cli-proxy-api"
# Extract subdomain and root domain for DNS
SUBDOMAIN=$(echo "$DOMAIN" | cut -d. -f1)
ROOT_DOMAIN=$(echo "$DOMAIN" | cut -d. -f2-)
log "Config loaded successfully"
info "Domain: $DOMAIN"
info "Tunnel: $TUNNEL_NAME"
info "Tokens: $TOKENS_PATH"
# ============================================================================
# Step 1: System setup
# ============================================================================
echo ""
echo -e "${CYAN}=== Step 1: System Setup ===${NC}"
# Update and install dependencies
apt-get update -qq
apt-get install -y -qq curl unzip python3 jq p7zip-full > /dev/null 2>&1
log "System dependencies installed"
# ============================================================================
# Step 2: Install Docker
# ============================================================================
echo ""
echo -e "${CYAN}=== Step 2: Docker Setup ===${NC}"
if command -v docker &> /dev/null; then
log "Docker already installed: $(docker --version)"
else
info "Installing Docker..."
curl -fsSL https://get.docker.com | sh > /dev/null 2>&1
log "Docker installed: $(docker --version)"
fi
# ============================================================================
# Step 3: Install cloudflared
# ============================================================================
echo ""
echo -e "${CYAN}=== Step 3: Cloudflared Setup ===${NC}"
if command -v cloudflared &> /dev/null; then
log "cloudflared already installed: $(cloudflared --version | head -1)"
else
info "Installing cloudflared..."
curl -fsSL https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o /usr/local/bin/cloudflared
chmod +x /usr/local/bin/cloudflared
log "cloudflared installed: $(cloudflared --version | head -1)"
fi
# ============================================================================
# Step 4: Prepare tokens
# ============================================================================
echo ""
echo -e "${CYAN}=== Step 4: Token Import ===${NC}"
mkdir -p "$AUTH_DIR"
mkdir -p "$INSTALL_DIR/auths"
# Handle token files - support zip, json, or directory of zips
if [ -d "$TOKENS_PATH" ]; then
# Directory - check for JSON files first, then zip files
JSON_COUNT=$(find "$TOKENS_PATH" -maxdepth 1 -name "*.json" 2>/dev/null | wc -l)
ZIP_COUNT=$(find "$TOKENS_PATH" -maxdepth 1 -name "*.zip" 2>/dev/null | wc -l)
if [ "$JSON_COUNT" -gt 0 ]; then
info "Found $JSON_COUNT JSON files in directory"
cp "$TOKENS_PATH"/*.json "$INSTALL_DIR/auths/" 2>/dev/null || true
fi
if [ "$ZIP_COUNT" -gt 0 ]; then
info "Found $ZIP_COUNT zip files in directory"
for zipfile in "$TOKENS_PATH"/*.zip; do
[ -f "$zipfile" ] && unzip -o "$zipfile" -d "$INSTALL_DIR/auths/" > /dev/null 2>&1
done
fi
# Also check for 7z files
SEVEN_COUNT=$(find "$TOKENS_PATH" -maxdepth 1 -name "*.7z" 2>/dev/null | wc -l)
if [ "$SEVEN_COUNT" -gt 0 ]; then
info "Found $SEVEN_COUNT 7z files in directory"
for sevenfile in "$TOKENS_PATH"/*.7z; do
[ -f "$sevenfile" ] && 7z x -y -o"$INSTALL_DIR/auths/" "$sevenfile" > /dev/null 2>&1
done
fi
if [ "$JSON_COUNT" -eq 0 ] && [ "$ZIP_COUNT" -eq 0 ] && [ "$SEVEN_COUNT" -eq 0 ]; then
err "No .json, .zip, or .7z files found in $TOKENS_PATH"
fi
elif [ -f "$TOKENS_PATH" ] && [[ "$TOKENS_PATH" == *.zip ]]; then
# Single zip file
info "Extracting tokens from zip..."
unzip -o "$TOKENS_PATH" -d "$INSTALL_DIR/auths/" > /dev/null 2>&1
elif [ -f "$TOKENS_PATH" ] && [[ "$TOKENS_PATH" == *.7z ]]; then
# Single 7z file
info "Extracting tokens from 7z..."
7z x -y -o"$INSTALL_DIR/auths/" "$TOKENS_PATH" > /dev/null 2>&1
elif [ -f "$TOKENS_PATH" ] && [[ "$TOKENS_PATH" == *.json ]]; then
# Single JSON file
cp "$TOKENS_PATH" "$INSTALL_DIR/auths/"
else
err "TOKENS_PATH must be a directory, .zip, .7z, or .json file"
fi
TOKEN_COUNT=$(find "$INSTALL_DIR/auths" -name "*.json" | wc -l)
[ "$TOKEN_COUNT" -eq 0 ] && err "No token files found in $TOKENS_PATH"
# Convert tokens to CLIProxyAPI format
info "Converting $TOKEN_COUNT tokens to CLIProxyAPI format..."
python3 << PYEOF
import json, os, glob, base64, datetime
auth_dir = "$INSTALL_DIR/auths"
files = glob.glob(os.path.join(auth_dir, "*.json"))
converted = 0
errors = 0
for f in files:
try:
with open(f) as fh:
data = json.load(fh)
# Skip if already in correct format
if "expired" in data and "last_refresh" in data:
continue
# Extract expiry from access_token JWT
access_token = data.get("access_token", "")
expire = ""
account_id = ""
if access_token and "." in access_token:
parts = access_token.split(".")
if len(parts) >= 2:
payload = parts[1] + "=" * (4 - len(parts[1]) % 4)
try:
claims = json.loads(base64.b64decode(payload))
exp_ts = claims.get("exp", 0)
if exp_ts:
expire = datetime.datetime.fromtimestamp(exp_ts, tz=datetime.timezone.utc).isoformat()
auth = claims.get("https://api.openai.com/auth", {})
account_id = auth.get("chatgpt_account_id", "")
except:
pass
# Convert to CLIProxyAPI format
new_data = {
"id_token": data.get("id_token", ""),
"access_token": data.get("access_token", ""),
"refresh_token": data.get("refresh_token", ""),
"account_id": account_id,
"last_refresh": data.get("saved_at", datetime.datetime.now(tz=datetime.timezone.utc).isoformat()),
"email": data.get("email", ""),
"type": "codex",
"expired": expire
}
with open(f, 'w') as fh:
json.dump(new_data, fh)
converted += 1
except Exception as e:
errors += 1
print(f"Converted: {converted}, Errors: {errors}")
PYEOF
log "Token conversion complete: $TOKEN_COUNT tokens ready"
# ============================================================================
# Step 5: Create CLIProxyAPI config
# ============================================================================
echo ""
echo -e "${CYAN}=== Step 5: CLIProxyAPI Configuration ===${NC}"
cat > "$INSTALL_DIR/config.yaml" << EOF
# CLIProxyAPI Configuration - Auto-generated by deploy-cpa.sh
host: "127.0.0.1"
port: 8317
auth-dir: "/root/.cli-proxy-api"
request-retry: 3
max-retry-credentials: 5
quota-exceeded:
switch-project: true
switch-preview-model: true
api-keys:
- "$API_KEY"
remote-management:
allow-remote: true
secret-key: "$MGMT_KEY"
disable-control-panel: false
logging-to-file: true
usage-statistics-enabled: true
logs-max-total-size-mb: 100
# Prevent Cloudflare blocking -> payment_required false positive
disable-cooling: true
# Set Codex CLI User-Agent to bypass Cloudflare
codex-header-defaults:
user-agent: "codex_cli_rs/0.114.0 (Mac OS 14.2.0; x86_64) vscode/1.111.0"
beta-features: "multi_agent"
routing:
strategy: "round-robin"
session-affinity: true
session-affinity-ttl: "30m"
ws-auth: false
debug: false
EOF
log "Config created at $INSTALL_DIR/config.yaml"
# ============================================================================
# Step 6: Create docker-compose.yml
# ============================================================================
echo ""
echo -e "${CYAN}=== Step 6: Docker Compose Setup ===${NC}"
cat > "$INSTALL_DIR/docker-compose.yml" << 'EOF'
services:
cli-proxy-api:
image: eceasy/cli-proxy-api:latest
pull_policy: always
container_name: cli-proxy-api
network_mode: host
volumes:
- ./config.yaml:/CLIProxyAPI/config.yaml
- ./auths:/root/.cli-proxy-api
- ./logs:/CLIProxyAPI/logs
restart: unless-stopped
EOF
log "docker-compose.yml created"
# ============================================================================
# Step 7: Start CLIProxyAPI
# ============================================================================
echo ""
echo -e "${CYAN}=== Step 7: Starting CLIProxyAPI ===${NC}"
cd "$INSTALL_DIR"
# Stop and remove existing container if it exists
docker stop cli-proxy-api 2>/dev/null || true
docker rm cli-proxy-api 2>/dev/null || true
docker compose up -d 2>&1
# Wait for startup
sleep 5
# Verify it's running
if docker ps | grep -q cli-proxy-api; then
log "CLIProxyAPI is running"
docker logs cli-proxy-api 2>&1 | tail -3
else
err "CLIProxyAPI failed to start. Check: docker logs cli-proxy-api"
fi
# ============================================================================
# Step 8: Create Cloudflare Tunnel
# ============================================================================
echo ""
echo -e "${CYAN}=== Step 8: Cloudflare Tunnel Setup ===${NC}"
# Check if tunnel already exists
EXISTING_TUNNEL=$(curl -s "https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/cfd_tunnel?name=${TUNNEL_NAME}" \
-H "X-Auth-Email: ${CF_EMAIL}" \
-H "X-Auth-Key: ${CF_API_KEY}" | python3 -c "import sys, json; d=json.load(sys.stdin); t=[x for x in d.get('result',[]) if x['name']=='${TUNNEL_NAME}']; print(t[0]['id'] if t else '')" 2>/dev/null)
if [ -n "$EXISTING_TUNNEL" ]; then
warn "Tunnel '$TUNNEL_NAME' already exists (ID: $EXISTING_TUNNEL)"
TUNNEL_ID="$EXISTING_TUNNEL"
# Get existing token
TUNNEL_TOKEN=$(curl -s "https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/cfd_tunnel/${TUNNEL_ID}/token" \
-H "X-Auth-Email: ${CF_EMAIL}" \
-H "X-Auth-Key: ${CF_API_KEY}" | python3 -c "import sys, json; print(json.load(sys.stdin)['result'])" 2>/dev/null)
else
# Create new tunnel
info "Creating tunnel '$TUNNEL_NAME'..."
TUNNEL_RESULT=$(curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/cfd_tunnel" \
-H "X-Auth-Email: ${CF_EMAIL}" \
-H "X-Auth-Key: ${CF_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"name\":\"${TUNNEL_NAME}\"}")
TUNNEL_ID=$(echo "$TUNNEL_RESULT" | python3 -c "import sys, json; print(json.load(sys.stdin)['result']['id'])" 2>/dev/null)
TUNNEL_TOKEN=$(echo "$TUNNEL_RESULT" | python3 -c "import sys, json; print(json.load(sys.stdin)['result']['token'])" 2>/dev/null)
[ -z "$TUNNEL_ID" ] && err "Failed to create tunnel: $TUNNEL_RESULT"
log "Tunnel created: $TUNNEL_ID"
fi
# Configure tunnel ingress
info "Configuring tunnel routing..."
curl -s -X PUT "https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/cfd_tunnel/${TUNNEL_ID}/configurations" \
-H "X-Auth-Email: ${CF_EMAIL}" \
-H "X-Auth-Key: ${CF_API_KEY}" \
-H "Content-Type: application/json" \
-d "{
\"config\": {
\"ingress\": [
{
\"hostname\": \"${DOMAIN}\",
\"service\": \"http://localhost:8317\",
\"originRequest\": { \"noTLSVerify\": true }
},
{ \"service\": \"http_status:404\" }
]
}
}" > /dev/null 2>&1
log "Tunnel routing configured"
# ============================================================================
# Step 9: DNS Record
# ============================================================================
echo ""
echo -e "${CYAN}=== Step 9: DNS Record Setup ===${NC}"
# Check if DNS record already exists
EXISTING_DNS=$(curl -s "https://api.cloudflare.com/client/v4/zones/${CF_ZONE_ID}/dns_records?name=${DOMAIN}" \
-H "X-Auth-Email: ${CF_EMAIL}" \
-H "X-Auth-Key: ${CF_API_KEY}" | python3 -c "import sys, json; d=json.load(sys.stdin); print(d['result'][0]['id'] if d['result'] else '')" 2>/dev/null)
if [ -n "$EXISTING_DNS" ]; then
# Update existing record to point to new tunnel
info "Updating existing DNS record to point to new tunnel..."
curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/${CF_ZONE_ID}/dns_records/${EXISTING_DNS}" \
-H "X-Auth-Email: ${CF_EMAIL}" \
-H "X-Auth-Key: ${CF_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"content\":\"${TUNNEL_ID}.cfargotunnel.com\"}" > /dev/null 2>&1
log "DNS record updated: $DOMAIN -> tunnel"
else
info "Creating CNAME record for $DOMAIN..."
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/${CF_ZONE_ID}/dns_records" \
-H "X-Auth-Email: ${CF_EMAIL}" \
-H "X-Auth-Key: ${CF_API_KEY}" \
-H "Content-Type: application/json" \
-d "{
\"type\": \"CNAME\",
\"name\": \"${SUBDOMAIN}\",
\"content\": \"${TUNNEL_ID}.cfargotunnel.com\",
\"proxied\": true,
\"ttl\": 1
}" > /dev/null 2>&1
log "DNS record created: $DOMAIN -> tunnel"
fi
# ============================================================================
# Step 10: WAF Skip Rule
# ============================================================================
echo ""
echo -e "${CYAN}=== Step 10: WAF Configuration ===${NC}"
# Get the firewall custom ruleset
RULESET_ID=$(curl -s "https://api.cloudflare.com/client/v4/zones/${CF_ZONE_ID}/rulesets" \
-H "X-Auth-Email: ${CF_EMAIL}" \
-H "X-Auth-Key: ${CF_API_KEY}" | python3 -c "
import sys, json
d = json.load(sys.stdin)
for r in d.get('result', []):
if r['phase'] == 'http_request_firewall_custom' and r['name'] == 'default':
print(r['id'])
break
" 2>/dev/null)
if [ -n "$RULESET_ID" ]; then
# Get existing rules
curl -s "https://api.cloudflare.com/client/v4/zones/${CF_ZONE_ID}/rulesets/${RULESET_ID}" \
-H "X-Auth-Email: ${CF_EMAIL}" \
-H "X-Auth-Key: ${CF_API_KEY}" > /tmp/cf_ruleset.json
# Check if rule already exists
if grep -q "CPA API" /tmp/cf_ruleset.json 2>/dev/null; then
warn "WAF skip rule already exists"
else
# Add skip rule
python3 << PYEOF
import json
with open('/tmp/cf_ruleset.json') as f:
data = json.load(f)
rules = data.get('result', {}).get('rules', [])
rules.append({
'expression': 'starts_with(http.request.uri.path, "/v1/")',
'description': 'CPA API - Skip WAF',
'action': 'skip',
'action_parameters': {'ruleset': 'current'},
'enabled': True
})
with open('/tmp/cf_update.json', 'w') as f:
json.dump({'rules': rules}, f)
PYEOF
curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/${CF_ZONE_ID}/rulesets/${RULESET_ID}" \
-H "X-Auth-Email: ${CF_EMAIL}" \
-H "X-Auth-Key: ${CF_API_KEY}" \
-H "Content-Type: application/json" \
-d @/tmp/cf_update.json > /dev/null 2>&1
log "WAF skip rule added for /v1/* paths"
fi
else
warn "Could not find WAF ruleset, skipping (you may need to add manually)"
fi
# ============================================================================
# Step 11: Install cloudflared service
# ============================================================================
echo ""
echo -e "${CYAN}=== Step 11: Cloudflared Service ===${NC}"
# Stop existing service if running
systemctl stop cloudflared 2>/dev/null || true
# Uninstall existing service if needed
cloudflared service uninstall 2>/dev/null || true
# Install with token
cloudflared service install "$TUNNEL_TOKEN" 2>&1
systemctl daemon-reload
systemctl start cloudflared
sleep 3
if systemctl is-active --quiet cloudflared; then
log "cloudflared service is running"
else
err "cloudflared failed to start. Check: journalctl -u cloudflared"
fi
# ============================================================================
# Step 12: Verify deployment
# ============================================================================
echo ""
echo -e "${CYAN}=== Step 12: Verification ===${NC}"
# Wait for tunnel to connect
sleep 5
# Test local endpoint
LOCAL_TEST=$(curl -s --max-time 10 http://127.0.0.1:8317/v1/models \
-H "Authorization: Bearer $API_KEY" 2>/dev/null | python3 -c "import sys, json; d=json.load(sys.stdin); print(len(d.get('data',[])))" 2>/dev/null)
if [ "$LOCAL_TEST" -gt 0 ] 2>/dev/null; then
log "Local API working: $LOCAL_TEST models available"
else
warn "Local API test failed - tokens may need time to load"
fi
# Test tunnel endpoint
sleep 3
TUNNEL_TEST=$(curl -s --max-time 15 "https://${DOMAIN}/v1/models" \
-H "Authorization: Bearer $API_KEY" 2>/dev/null | python3 -c "import sys, json; d=json.load(sys.stdin); print(len(d.get('data',[])))" 2>/dev/null)
if [ "$TUNNEL_TEST" -gt 0 ] 2>/dev/null; then
log "Tunnel API working: $TUNNEL_TEST models available"
else
warn "Tunnel test failed - DNS may need time to propagate"
fi
# ============================================================================
# Print Summary
# ============================================================================
echo ""
echo ""
echo -e "${GREEN}============================================================================${NC}"
echo -e "${GREEN} CLIProxyAPI Deploy Complete!${NC}"
echo -e "${GREEN}============================================================================${NC}"
echo ""
echo -e "${CYAN}API Endpoint:${NC} https://${DOMAIN}"
echo -e "${CYAN}API Key:${NC} ${API_KEY}"
echo -e "${CYAN}Management:${NC} https://${DOMAIN}/management.html"
echo -e "${CYAN}Mgmt Key:${NC} ${MGMT_KEY}"
echo ""
echo -e "${CYAN}Token Count:${NC} ${TOKEN_COUNT}"
echo -e "${CYAN}Models:${NC} gpt-5.4, gpt-5.4-mini, gpt-5.5, codex-auto-review, gpt-image-2"
echo ""
echo -e "${CYAN}Install Dir:${NC} ${INSTALL_DIR}"
echo -e "${CYAN}Auth Dir:${NC} ${INSTALL_DIR}/auths"
echo -e "${CYAN}Logs:${NC} ${INSTALL_DIR}/logs"
echo ""
echo -e "${YELLOW}Test Commands:${NC}"
echo " curl https://${DOMAIN}/v1/models -H 'Authorization: Bearer ${API_KEY}'"
echo " curl https://${DOMAIN}/v1/chat/completions -H 'Authorization: Bearer ${API_KEY}' -H 'Content-Type: application/json' -d '{\"model\":\"gpt-5.5\",\"messages\":[{\"role\":\"user\",\"content\":\"hi\"}],\"max_tokens\":10}'"
echo ""
echo -e "${YELLOW}Management Commands:${NC}"
echo " docker logs -f cli-proxy-api # View logs"
echo " docker restart cli-proxy-api # Restart"
echo " cd ${INSTALL_DIR} && docker compose up -d --pull always # Update"
echo ""
echo -e "${GREEN}============================================================================${NC}"
# Save credentials to file
cat > "$INSTALL_DIR/credentials.txt" << EOF
CLIProxyAPI Credentials
Generated: $(date)
API Endpoint: https://${DOMAIN}
API Key: ${API_KEY}
Management: https://${DOMAIN}/management.html
Management Key: ${MGMT_KEY}
Tunnel ID: ${TUNNEL_ID}
Tunnel Name: ${TUNNEL_NAME}
Install Dir: ${INSTALL_DIR}
Auth Dir: ${INSTALL_DIR}/auths
EOF
log "Credentials saved to $INSTALL_DIR/credentials.txt"
準備工作
- Cloudflare 帳號(免費即可)
- 一個域名托管在 Cloudflare 上
- ChatGPT Token 文件(.zip / .7z / .json)
使用步驟
1. 複製模板
cp cpa-config-template.txt my-config.txt
2. 填入你的資訊(5 個必填項)
nano my-config.txt
3. 一鍵部署
bash deploy-cpa.sh my-config.txt
必填的 5 個欄位
┌───────────────┬─────────────────────┬───────────────────────────────┐
│ 欄位 │ 說明 │ 在哪裡找 │
├───────────────┼─────────────────────┼───────────────────────────────┤
│ CF_EMAIL │ Cloudflare 登錄郵箱 │ 你的帳號 │
├───────────────┼─────────────────────┼───────────────────────────────┤
│ CF_API_KEY │ Global API Key │ CF後台 → 個人資料 → API Token │
├───────────────┼─────────────────────┼───────────────────────────────┤
│ CF_ACCOUNT_ID │ 帳號 ID │ 任意域名首頁右側欄 │
├───────────────┼─────────────────────┼───────────────────────────────┤
│ CF_ZONE_ID │ 域名 Zone ID │ 具體域名首頁右側欄 │
├───────────────┼─────────────────────┼───────────────────────────────┤
│ DOMAIN │ 要用的子域名 │ 例如 cpa.你的域名.com │
├───────────────┼─────────────────────┼───────────────────────────────┤
│ TOKENS_PATH │ Token 文件路徑 │ 支持 .zip/.7z/.json/目錄 │
└───────────────┴─────────────────────┴───────────────────────────────┘
部署完成後
腳本會顯示:
- API 地址:https://cpa.你的域名.com
- API Key:客戶端連接用的密鑰
- 管理面板:https://cpa.你的域名.com/management.html
把 API 地址和 Key 填進 Cherry Studio 等客戶端即可使用。
4 个帖子 - 4 位参与者