# SkateSpots AI proxy — placement on the CVM host Why: the Netlify Function (`netlify/functions/ai.mjs`) works, but every AI call spends Netlify **compute + response bandwidth** credits. This service is the same proxy running on the CVM host we already own, so AI traffic never touches Netlify and the Routstr key lives on our box. ``` browser / APK ──HTTPS──▶ Caddy (TLS) ──http──▶ 127.0.0.1:8787 (Bun) │ └──HTTPS──▶ Routstr node (sats) ``` ## What's needed (once) 1. **A hostname** pointing at the CVM host, e.g. `ai.skate-spots.org` → the host's public IPv4. Add it wherever `skate-spots.org` DNS is managed. 2. **Ports 80 + 443 open** to the internet (firewall at the provider; `ufw` is inactive on the host). 3. **Caddy** for automatic TLS (see `Caddyfile` for the install snippet). ## Deploy ```bash npm run deploy:ai # uploads server.ts + package.json + unit, installs, restarts bash scripts/deploy-ai-proxy.sh --logs ``` The **first** deploy needs `/home/ubuntu/skatespots-ai/.env` to exist (the unit reads it). Create it from `ai-proxy/.env.example` with the real Routstr key — that key is the one currently in Netlify env `SASQUATCH_AI_KEY`: ```bash ssh 'cat > ~/skatespots-ai/.env' <<'EOF' SASQUATCH_AI_BASE=https://routstr.githappens.space/v1 SASQUATCH_AI_KEY= SASQUATCH_MODELS= SASQUATCH_REQUIRE_PRO=1 AI_PROXY_HOST=127.0.0.1 AI_PROXY_PORT=8787 EOF ssh 'chmod 600 ~/skatespots-ai/.env' ``` ## Point the app at it The client resolves its AI base in one place (`src/lib/sasquatchAi.ts`). Set the build-time override and redeploy the web app: ``` VITE_SASQUATCH_AI_BASE=https://ai.skate-spots.org/api/ai ``` Leave it unset and the app keeps using `/api/ai` (the Netlify Function), so the move is reversible and can be rolled out gradually. The proxy's CORS allowlist already includes `https://skate-spots.org` and the local/Capacitor origins. ## Verify ```bash # from anywhere, once TLS is up: curl -s -X POST https://ai.skate-spots.org/api/ai/status # → {"configured":true,...} (owner balance; public on purpose) ``` ## Notes - `SASQUATCH_REQUIRE_PRO=1` keeps the Pro gate (owner pubkeys bypass). A client without a valid NIP-98 header gets 401; without an active Pro pass, 402. - The proxy is per-IP throttled at 20 req/min. It's a single long-lived process, so the throttle actually holds (unlike the serverless version). - `netlify/functions/ai.mjs` stays in the repo as the fallback path; nothing breaks if this service is down and the client is still pointed at `/api/ai`.