#!/usr/bin/env bash # ========================================================== # CPA (CLIProxyAPI) one-click deploy script # Target : Tencent SG server ubuntu@43.156.118.130 # Effect : create /opt/cpa + start cli-proxy-api container # existing new-api / nginx / xray are NOT modified # (only a runtime docker network attach for new-api) # Idempotent: safe to run multiple times. # Run as root: sudo bash deploy-cpa.sh # ========================================================== set -euo pipefail step() { echo ""; echo "========== [$1] $2 =========="; } step 1 "Pre-check" [ "$(id -u)" -eq 0 ] || { echo "ERROR: run as root (sudo bash)"; exit 1; } docker ps --format ' {{.Names}} | {{.Status}}' step 2 "Create /opt/cpa" mkdir -p /opt/cpa/auths /opt/cpa/logs /opt/cpa/plugins cd /opt/cpa step 3 "Generate config.yaml (keep existing if present)" if [ -f config.yaml ]; then echo " config.yaml exists, keep it" else CPA_API_KEY="sk-cpa-$(openssl rand -hex 16)" MGMT_KEY="$(openssl rand -hex 16)" cat > config.yaml < KEYS.txt < docker-compose.yml <<'EOF' services: cli-proxy-api: image: eceasy/cli-proxy-api:latest container_name: cli-proxy-api restart: unless-stopped ports: # all bound to server loopback only -> NOT reachable from public internet # 8317 = API + management panel, others = OAuth callback ports per provider - "127.0.0.1:8317:8317" - "127.0.0.1:8085:8085" - "127.0.0.1:1455:1455" - "127.0.0.1:54545:54545" - "127.0.0.1:51121:51121" # Antigravity OAuth callback - "127.0.0.1:11451:11451" volumes: - ./config.yaml:/CLIProxyAPI/config.yaml - ./auths:/root/.cli-proxy-api - ./logs:/CLIProxyAPI/logs - ./plugins:/CLIProxyAPI/plugins networks: - ai-net networks: ai-net: external: true EOF echo " done" step 5 "Docker network ai-net (shared with new-api)" docker network inspect ai-net >/dev/null 2>&1 || docker network create ai-net docker network connect ai-net new-api 2>/dev/null && echo " new-api joined ai-net" || echo " new-api already in ai-net (or not running)" step 6 "Start container" docker compose up -d sleep 6 docker ps --filter name=cli-proxy-api --format ' {{.Names}} | {{.Status}} | {{.Ports}}' step 7 "Verify" CPA_API_KEY=$(grep -oE 'sk-cpa-[0-9a-f]+' config.yaml | head -1 || true) [ -n "$CPA_API_KEY" ] || { echo "ERROR: api key not found in config.yaml"; exit 1; } echo "-- no key (expect 401):" curl -s -o /dev/null -w ' HTTP %{http_code}\n' http://127.0.0.1:8317/v1/models echo "-- with key (expect 200; model list may be empty before OAuth login):" curl -s -w '\n HTTP %{http_code}\n' http://127.0.0.1:8317/v1/models -H "Authorization: Bearer ${CPA_API_KEY}" | head -c 400 echo "" echo "-- new-api container -> cli-proxy-api connectivity:" if docker exec new-api sh -c 'command -v curl' >/dev/null 2>&1; then docker exec new-api sh -c "curl -s -o /dev/null -w '%{http_code}' --max-time 5 http://cli-proxy-api:8317/v1/models" | sed 's/^/ HTTP /' echo " (any HTTP code = network OK)" elif docker exec new-api sh -c 'command -v wget' >/dev/null 2>&1; then docker exec new-api sh -c "wget -S -q -O /dev/null http://cli-proxy-api:8317/v1/models 2>&1 | head -1" | sed 's/^/ /' else echo " no curl/wget inside new-api, skip (use New API channel test later)" fi echo "" echo "==========================================================" echo " DEPLOY DONE. Secrets (also saved at /opt/cpa/KEYS.txt):" echo "==========================================================" cat KEYS.txt echo "" echo "Next: open tunnel.bat locally, then visit" echo " http://localhost:8317/management.html"