-
Notifications
You must be signed in to change notification settings - Fork 78
Reverse Proxy CPA and CPA Manager Plus with the Same Domain
This guide explains how to use a single domain for both:
- CPA Manager Plus panel:
https://your-domain.com/management.html - CPA / CLI Proxy API:
https://your-domain.com/v1/... - CPA OAuth callbacks, Codex API, Amp routes, and other CPA-side endpoints
This guide is intended for CPA Manager Plus Full Docker mode / Manager Server mode.
If you are using CPA panel mode, where CPA itself serves
/management.html, you do not need this mixed reverse proxy setup. This guide assumes CPAMP runs separately on18317, while CPA runs separately on8317.
Recommended routing:
Browser
└── https://your-domain.com
├── /management.html -> CPA Manager Plus :18317
├── /usage-service/* -> CPA Manager Plus :18317
├── /v0/management/* -> CPA Manager Plus :18317
│ ├── CPAMP handles usage / model-prices / aliases / dashboard
│ │ / monitoring / codex-inspection itself
│ └── Other management APIs are proxied by CPAMP to CPA
└── /v1/*, /backend-api/* -> CPA :8317
In other words:
- The panel, usage analytics, request monitoring, model prices, API key aliases, server-side inspection, and other CPAMP-backed features go to CPA Manager Plus
- Normal API requests, Codex API, OAuth callbacks, and unknown future CPA endpoints go to CPA
- Users access one domain, while Nginx routes requests to different upstreams by path
CPA Manager Plus does not bundle CPA itself. You still need to run CPA / CLI Proxy API separately.
Common ports:
CPA / CLI Proxy API: 8317
CPA Manager Plus: 18317
CPA must have Management API enabled, for example:
remote-management: secret-key: "your CPA Management Key" allow-remote: true
Even when both containers are in the same Docker network, CPA usually does not see the request source as localhost, so allow-remote: true is required.
Use a recent CPA version. Request monitoring depends on the CPA usage queue:
- Recommended CPA version:
v7.1.39+ - Minimum version for HTTP usage queue:
v6.10.8+
Older versions may still support basic management features, but request monitoring, usage collection, and some request metadata may be incomplete.
The example below assumes:
- CPA service name:
cli-proxy-api - CPAMP service name:
cpa-manager-plus - Nginx, CPA, and CPAMP are in the same Docker network
- Only Nginx exposes
80/443to the public network
services: cli-proxy-api: image: your-cpa-image:latest container_name: cli-proxy-api restart: unless-stopped volumes: - ./cliproxyapi/config.yaml:/app/config.yaml - ./cliproxyapi/auths:/app/auths - ./cliproxyapi/logs:/app/logs expose: - "8317" cpa-manager-plus: image: seakee/cpa-manager-plus:latest container_name: cpa-manager-plus restart: unless-stopped volumes: - ./cpa-manager-plus-data:/data expose: - "18317" depends_on: - cli-proxy-api nginx: image: nginx:alpine container_name: cpa-nginx restart: unless-stopped ports: - "80:80" # Expose 443 if HTTPS is enabled # - "443:443" volumes: - ./nginx/conf.d:/etc/nginx/conf.d:ro # Mount certificates if HTTPS is enabled # - ./nginx/ssl:/etc/nginx/ssl:ro depends_on: - cli-proxy-api - cpa-manager-plus
If CPA already runs on the host machine, you can omit the CPA service from compose and point the Nginx upstream to a host-accessible address instead.
Add this to the http {} block in nginx.conf:
map $http_upgrade $connection_upgrade { default upgrade; '' close; }
Then add the site config:
upstream cpa_api { server cli-proxy-api:8317; } upstream cpamp { server cpa-manager-plus:18317; } server { listen 80; server_name your-domain.com; client_max_body_size 64m; proxy_http_version 1.1; proxy_read_timeout 3600s; proxy_send_timeout 3600s; proxy_buffering off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; # Default entry point: CPAMP panel location = / { return 302 /management.html; } # ===== CPA Manager Plus ===== location = /management.html { proxy_pass http://cpamp; } location = /health { proxy_pass http://cpamp; } location = /status { proxy_pass http://cpamp; } location = /setup { proxy_pass http://cpamp; } # CPAMP compatibility and runtime APIs location ^~ /usage-service/ { proxy_pass http://cpamp; } # /v0/management/* goes to CPAMP first: # - usage / model-prices / api-key-aliases / dashboard / monitoring / # codex-inspection / import-export are handled by CPAMP # - other CPA management APIs are proxied by CPAMP to CPA using the saved CPA Management Key # # Do not only configure location = /v0/management # Use the prefix match with trailing slash: /v0/management/ location ^~ /v0/management/ { proxy_pass http://cpamp; } # /models is provided through CPAMP's compatibility proxy # If CPAMP has not completed setup yet, this path may return 412 location = /models { proxy_pass http://cpamp; } # ===== CPA / CLI Proxy API ===== # Actual OpenAI / Claude Code / Codex API requests should go directly to CPA location ^~ /v1/ { proxy_pass http://cpa_api; } location ^~ /v1beta/ { proxy_pass http://cpa_api; } location ^~ /backend-api/codex/ { proxy_pass http://cpa_api; } location ^~ /api/ { proxy_pass http://cpa_api; } # CPA special routes and OAuth callbacks location = /v1internal:method { proxy_pass http://cpa_api; } location = /healthz { proxy_pass http://cpa_api; } location = /anthropic/callback { proxy_pass http://cpa_api; } location = /codex/callback { proxy_pass http://cpa_api; } location = /google/callback { proxy_pass http://cpa_api; } location = /antigravity/callback { proxy_pass http://cpa_api; } # Fallback to CPA # This covers CPA root routes, Amp routes, and future CPA endpoints location / { proxy_pass http://cpa_api; } }
For HTTPS, only the listener and certificate settings change. The location routing rules stay the same:
server { listen 443 ssl http2; server_name your-domain.com; ssl_certificate /etc/nginx/ssl/your-domain.com/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/your-domain.com/privkey.pem; # Keep the same proxy_set_header and location blocks as above } server { listen 80; server_name your-domain.com; return 301 https://$host$request_uri; }
If Nginx runs directly on the host instead of inside the Docker network, change the upstreams to host ports:
upstream cpa_api { server 127.0.0.1:8317; } upstream cpamp { server 127.0.0.1:18317; }
Make sure both services expose ports to the host:
ports: - "8317:8317"
ports: - "18317:18317"
Open:
https://your-domain.com/management.html
During first setup, enter:
Admin Key: cmp_admin_... from CPAMP startup logs
CPA URL: http://cli-proxy-api:8317
CPA Management Key: CPA remote-management.secret-key
Important notes:
- CPAMP panel login uses the CPAMP Admin Key
- The CPA Management Key is stored server-side and used by CPAMP when talking to CPA
- The recommended CPA URL is the Docker internal URL:
http://cli-proxy-api:8317 - Avoid using the public domain itself as the CPA URL, because it creates a loop like
CPAMP -> Nginx -> CPAMP/CPA, which makes troubleshooting harder
If CPAMP runs directly on the host, the CPA URL can be:
http://127.0.0.1:8317
If CPAMP runs in Docker and CPA runs on the host, Docker Desktop may support:
http://host.docker.internal:8317
For Linux Docker environments, it is usually better to put CPA and CPAMP in the same Docker network and use the service name.
After configuring Nginx, test in this order:
# 1. CPAMP panel should be reachable curl -I https://your-domain.com/management.html # 2. CPAMP health check curl -i https://your-domain.com/health # 3. CPA health check curl -i https://your-domain.com/healthz # 4. CPAMP runtime info curl -i https://your-domain.com/usage-service/info # 5. CPA API request, should hit CPA curl -i https://your-domain.com/v1/models \ -H "Authorization: Bearer your API Key" # 6. CPAMP-proxied management API, should hit CPAMP first and then CPA curl -i https://your-domain.com/v0/management/config \ -H "Authorization: Bearer your CPAMP Admin Key"
Check whether the CPAMP container can reach CPA:
docker exec -it cpa-manager-plus sh
wget -O- http://cli-proxy-api:8317/healthzIf it fails, check:
- Whether CPA and CPAMP are in the same Docker network
- Whether CPA listens on
0.0.0.0:8317 - Whether the service name is really
cli-proxy-api - Whether the CPA container is running
- Whether
remote-management.allow-remoteis set totrue
In CPAMP Full Docker mode:
Panel login: CPAMP Admin Key
CPA connection setup: CPA Management Key
Normal API requests: CPA API Key
Do not mix these three keys.
This usually means CPAMP has not completed first setup yet.
Open:
https://your-domain.com/management.html
Complete setup first, then retry.
Check these items in order:
- CPA Management API is enabled
- CPA Management Key is correct
- Request monitoring is enabled in CPAMP
- CPA usage publishing is enabled
- CPA version supports HTTP usage queue
- No other CPAMP / Usage Service instance is consuming the same CPA usage queue
- CPAMP keeps running continuously so queue items do not expire before collection
/v1/models is a CPA API route, not a CPAMP management route.
Use a normal API Key:
curl -i https://your-domain.com/v1/models \
-H "Authorization: Bearer your API Key"Do not use the CPAMP Admin Key or CPA Management Key here.
In this setup, /v0/management/* goes to CPAMP first.
In Full Docker mode, browser-side login uses the CPAMP Admin Key. If you manually call management APIs with curl, use the CPAMP Admin Key first:
curl -i https://your-domain.com/v0/management/config \
-H "Authorization: Bearer your CPAMP Admin Key"Make sure the fallback rule exists:
location / { proxy_pass http://cpa_api; }
This ensures future CPA endpoints are not blocked just because they do not have explicit Nginx location rules yet.
Usually, do not add them at first.
Start with:
location ^~ /v0/management/ { proxy_pass http://cpamp; } location ^~ /usage-service/ { proxy_pass http://cpamp; }
If the CPAMP panel later shows 401 / 404 on config, logs, or auth file pages, add precise routing rules based on the actual failing path.
Avoid sending every uncertain path to CPAMP by default, because it may interfere with native CPA routes or future CPA endpoints.
The core idea is:
Panel and management paths explicitly owned by CPAMP -> CPAMP :18317
CPA API, OAuth callbacks, Codex API, and unknown future paths -> CPA :8317
Most important routing rules:
/management.html -> CPAMP
/usage-service/* -> CPAMP
/v0/management/* -> CPAMP
/v1/* -> CPA
/backend-api/codex/* -> CPA
OAuth callbacks -> CPA
Fallback routes -> CPA
With this setup, the same domain can serve both the CPAMP management panel and the CPA API Base URL.