Proxy-only control plane for CLIProxyAPI
Next.js 16 / React 19 dashboard for provider credentials, proxy runtime settings, usage history, quotas, updates, logs, and safe container operations.
Quick Start · Docs · Features · Development
Important
The dashboard intentionally manages the proxy stack only. It is not a general product control plane and the bundled deployment keeps the dashboard and primary proxy API loopback-only by default.
| Surface | What it covers |
|---|---|
| Access control | Dashboard users, admin access, session revocation, dashboard API keys |
| Provider management | Direct keys for Claude, Gemini, OpenAI/Codex, and OpenAI-compatible upstreams |
| OAuth inventory | Claude Code, Gemini CLI, Codex, Antigravity, iFlow, Kimi, Qwen Code, GitHub Copilot, Kiro, Cursor, CodeBuddy |
| Proxy operations | Routing, retries, logging, streaming, TLS, pprof, payload transforms, OAuth model aliases |
| Observability | Usage collection, quota views, logs, container state, and update workflows |
This repository is a workspace-structured monorepo with the active application in apps/dashboard/.
Current state:
apps/dashboard/is the runnable Next.js app and remains the primary surface for dashboard UI/API behavior- root scripts proxy to the app workspace through npm workspaces (for example,
npm run devruns thedashboardworkspace script) npm run build:collectoris available at the repository root and delegates to the dashboard workspace collector build- the embedded usage collector runtime lives under
apps/dashboard/src/server/jobs/workers/usage-collector/and is packaged into the dashboard image packages/*now holds shared contracts and foundations (api-contracts,auth-contracts,config,db,logger,shared,usage-contracts) used by the refactored structure
| Mode | Use it when | Command |
|---|---|---|
| Local appliance | You want the published dashboard image and bundled proxy stack running locally | ./setup-local.sh |
| Source development | You want to run the dashboard from the checked-out source tree | cd apps/dashboard && ./tools/dev/dev-local.sh |
| Server install | You want the bundled production compose stack on Ubuntu/Debian | `curl -fsSL .../install.sh |
The bundled deployment is a four-service Docker stack:
| Service | Role |
|---|---|
dashboard |
Next.js app, UI, API routes, JWT auth, Prisma access |
cliproxyapi |
CLIProxyAPIPlus runtime and management API |
postgres |
Persistent store for users, settings, audit logs, usage, and provider metadata |
docker-proxy |
Restricted Docker socket proxy for allowlisted container and image operations |
Operational boundaries:
apps/dashboard/: application code, Prisma schema, local source-dev workflow, and load-bearing Next instrumentation entrypoints (src/instrumentation.ts,src/instrumentation-node.ts)apps/dashboard/src/server/jobs/workers/usage-collector/: embedded worker runtime sources that are packaged into the dashboard imagepackages/: shared workspace modules for contracts, db foundations, config, and logginginfrastructure/: production compose stack, runtime config,manage.sh, backup/restore ops, webhook helpersapps/dashboard/scripts/runtime/: dashboard runtime scripts (entrypoint.sh, collector bootstrap)apps/dashboard/tools/dev/: local source-dev orchestration scripts and dev compose assetsdocs/: canonical documentation set
Default bundled endpoints:
- Dashboard:
http://127.0.0.1:3000 - Proxy API:
http://127.0.0.1:8317
OAuth callback ports remain published because upstream login flows require them.
Common public ingress shape:
flowchart TD
internet["Internet"]
nginx["Nginx reverse proxy"]
dashboard["Dashboard<br/>127.0.0.1:3000"]
proxy["CLIProxyAPI<br/>127.0.0.1:8317"]
postgres["PostgreSQL<br/>internal Docker network"]
dockerproxy["docker-socket-proxy<br/>internal Docker network"]
internet --> nginx
nginx -->|"dashboard host"| dashboard
nginx -->|"API host"| proxy
dashboard -->|"Prisma"| postgres
dashboard -->|"Docker API allowlist"| dockerproxy
dashboard -->|"CLIPROXYAPI_MANAGEMENT_URL<br/>/v0/management/*"| proxy
The repo now ships infrastructure/nginx/cliproxyapi-dashboard.http.conf.template as the starter config for this split-host ingress pattern.
git clone https://github.com/quanpersie2001/cliproxyapi-dashboard.git
cd cliproxyapi-dashboard
./setup-local.sh
# Windows: .\setup-local.ps1This creates a root .env, generates config.local.yaml, and starts the stack from docker-compose.local.yml. Then open http://localhost:3000, create the first admin user, connect providers, and issue client API keys.
Useful commands:
./setup-local.sh --down
./setup-local.sh --resetcd apps/dashboard
./tools/dev/dev-local.sh
# Windows: .\tools\dev\dev-local.ps1The source-dev workflow starts PostgreSQL and CLIProxyAPI in Docker, applies Prisma bootstrap and migrations, writes apps/dashboard/.env.local, and runs npm run dev:embedded so the Next.js dev server and embedded usage collector companion start together.
Source-dev endpoints:
- Dashboard:
http://localhost:3000 - Proxy API:
http://localhost:28317 - PostgreSQL:
localhost:5433
curl -fsSL https://raw.githubusercontent.com/quanpersie2001/cliproxyapi-dashboard/main/install.sh | sudo bashThe same install.sh file works in both modes:
- from a repo checkout:
sudo ./install.sh - as a one-file bootstrap:
curl .../install.sh | sudo bash
When run as a one-file bootstrap, it installs a minimal production bundle into /opt/cliproxyapi-dashboard by default, preserves existing runtime state files when re-run, and then continues the interactive installer.
The installed tree is intentionally small:
install.shinfrastructure/- generated runtime files such as
infrastructure/.env,infrastructure/docker-compose.override.yml, andbackups/
The installer accepts either full URLs like https://dash.example.com or bare hostnames like dash.example.com, and normalizes them automatically.
To install into a different path:
curl -fsSL https://raw.githubusercontent.com/quanpersie2001/cliproxyapi-dashboard/main/install.sh | sudo env INSTALL_DIR=/srv/cliproxyapi-dashboard bashThe bundled installer currently:
- installs Docker Engine and Compose if missing
- generates stack secrets
- writes
infrastructure/.env - optionally installs Nginx and renders a split-host HTTP reverse proxy config from the public dashboard/API URLs you entered
- optionally configures firewall rules, backup cron, and the dashboard deploy webhook
After install:
cd infrastructure
./manage.sh up
./manage.sh ps
./manage.sh logs dashboardThe canonical documentation hub lives at docs/README.md.
| Guide | Purpose |
|---|---|
docs/README.md |
Documentation hub and reading order |
docs/FEATURES.md |
Product surfaces, page map, access model |
docs/ARCHITECTURE.md |
Runtime topology, module boundaries, API and data overview |
docs/INSTALLATION.md |
Local setup, source-dev vs appliance setup, server install |
docs/CONFIGURATION.md |
Config sources, managed runtime settings, provider surfaces |
docs/ENV.md |
Environment variable reference |
docs/OPERATIONS.md |
Lifecycle commands, health, updates, backup/restore, webhook deploy |
docs/SECURITY.md |
Security posture, secrets, firewall guidance |
docs/TROUBLESHOOTING.md |
Common failure cases and fixes |
CONTRIBUTING.md |
Local development and contribution rules |
Run from the repository root (delegates to apps/dashboard/):
npm run dev
npm run typecheck
npm run lint
npm test
npm run build
npm run build:collectorEquivalent direct run inside apps/dashboard/ is still supported.
Implementation notes:
- Prisma client generation is wired into
predev,prebuild, andpretest - The production image uses
apps/dashboard/scripts/runtime/entrypoint.shto bootstrap core tables at startup with a PostgreSQL advisory lock - The bundled deployment runs an embedded resident usage collector worker;
POST /api/usage/collectis an authenticated fast trigger/wake seam GET /api/usageremains a compatibility route, but new code should useGET /api/usage/history
The release flow is split into three stages:
ci.ymlruns on pull requests andmainpushes to gate changes with lint, typecheck, tests, app build, and a Docker build smoke testrelease.ymlis a manualworkflow_dispatchthat only creates or updates the Release Please PRpublish.ymlpublishes images fromdashboard-v*tags or an explicit workflow dispatch, buildsamd64onubuntu-latestandarm64onubuntu-24.04-arm, merges a multi-arch manifest in GHCR, and updatesversion.json- manual
publish.ymlruns can rebuild an existing tag for recovery, but they do not movelatestor rewriteversion.json release.ymldispatchespublish.ymlautomatically after a release is created whenRELEASE_PLEASE_TOKENis absent; if the secret is configured, the normal tag-push trigger handles publish instead