Deploying CAPScore
Recommended: free single-container hosts
The whole app runs as one container β FastAPI serves both the dashboard and
the REST API (frontend is same-origin, no nginx needed). The root Dockerfile
is all any free Docker host needs; it reads $PORT automatically.
The optional Node cap-provider (live CROO WebSocket listener) is not part of
the single container and is only needed once real CROO credentials exist.
| Host | Free? | URL | Notes |
|---|---|---|---|
| Render | Yes (free web service) | *.onrender.com |
Easiest. render.yaml included. Cold start ~50s after idle. |
| Hugging Face Spaces | Yes (no card) | *.hf.space |
Docker Space. Use deploy/huggingface-space-README.md. Great for AI demos. |
| Google Cloud Run | Yes (free tier) | *.run.app |
Scales to zero, fast. Needs gcloud + a billing-enabled project. |
| Koyeb | Yes (free instance) | *.koyeb.app |
Docker-native. |
Render (quickest)
- Push this repo to GitHub (also required for the hackathon submission).
- Render β New β Blueprint β pick the repo (it reads
render.yaml). - Set secrets
ANTHROPIC_API_KEYand/orOPENAI_API_KEY. - Deploy β live at
https://capscore-agent.onrender.com. - Set
CAPSCORE_PUBLIC_BASE_URLto that URL and redeploy.
Local single-container test
docker build -t capscore .
docker run --rm -p 8000:8000 --env-file .env capscore
# open http://localhost:8000
Self-hosting behind a custom domain (Cloudflare Tunnel)
Original notes for serving under a custom domain via a Cloudflare Tunnel.
The stack runs three containers (api, frontend, cloudflared) and is fronted
by a Cloudflare Tunnel, so no inbound ports need to be opened on the host.
nginx (the frontend container) serves the dashboard and reverse-proxies the
/health and /jobs API surface to the api container, so the whole app is
served same-origin under https://croo.maaihub.com.
Internet ββTLSββ> Cloudflare ββtunnelββ> cloudflared ββ> frontend (nginx :80)
ββ / -> static dashboard
ββ /health,/jobs -> api (:8000)
Prerequisites
- Docker + Docker Compose on the host.
.envfilled in (copy from.env.example). For the analysis layer you need at leastANTHROPIC_API_KEYorOPENAI_API_KEY(the LLM helper falls back Anthropic β OpenAI β deterministic heuristics).- A Cloudflare Tunnel run token in
TUNNEL_TOKEN.
One-time Cloudflare setup (dashboard, ~3 min)
The API token in this project can read DNS but cannot create tunnels, so the tunnel is created once in the dashboard:
- Cloudflare Zero Trust β Networks β Tunnels β Create a tunnel.
- Type: Cloudflared. Name it e.g.
croo-capscore. Save. - Under Public Hostnames, add:
- Subdomain
croo, Domainmaaihub.com - Service: HTTP β
frontend:80
- Subdomain
- Copy the tunnel token (the long
eyJ...string from the "install connector" command) into.envasTUNNEL_TOKEN=....
Cloudflare automatically creates the croo.maaihub.com CNAME to the tunnel.
(The existing *.maaihub.com wildcard no longer matters once this explicit
record exists.)
Deploy
cd capscore-agent
cp .env.example .env # then fill in keys + TUNNEL_TOKEN
./deploy/deploy.sh
Verify:
curl https://croo.maaihub.com/health
# {"status":"ok","version":"0.1.0",...}
Open https://croo.maaihub.com for the dashboard.
Enabling the live CROO CAP provider (later)
Until real CROO credentials exist, the cap-provider container is not started
(the API, analysis engine, proof packs, and dashboard all work without it). Once
you create the agent on cap.croo.network:
- Set
CROO_SDK_KEY,CAPSCORE_AGENT_ID,WALLET_PRIVATE_KEYin.env. docker compose -f docker-compose.prod.yml up -d --build cap-provider
Alternative: deploy on the existing maaihub box over SSH
If you prefer the existing origin server (the host behind *.maaihub.com):
# on your machine
rsync -az --exclude .venv --exclude node_modules --exclude runs \
capscore-agent/ user@maaihub-host:/opt/capscore-agent/
ssh user@maaihub-host 'cd /opt/capscore-agent && ./deploy/deploy.sh'
The Cloudflare Tunnel approach is recommended either way β it avoids opening ports and works identically on any Docker host.