Files
dd0c/products/01-llm-cost-router/infra/INFRASTRUCTURE.md
Max Mayfield 8a4c7c256d Add V1 infrastructure: Gitea Actions CI/CD + Fly.io + Cloudflare Pages
- Gitea Actions workflows: ci.yml (tests+clippy+fmt), benchmark.yml (P99 gate), deploy.yml (Fly+CF)
- Fly.io configs: proxy (shared-cpu, 256MB, min 1 machine), API (scale-to-zero)
- Dockerfiles: multi-stage Rust builds for proxy and API binaries
- INFRASTRUCTURE.md: full V1 stack (~$5/mo), AWS migration path, Gitea runner setup, DNS plan
- Stack: Fly.io + Cloudflare Pages + Neon + Upstash + Gitea Actions
2026-03-01 02:37:48 +00:00

2.3 KiB

dd0c/route — V1 Infrastructure Stack

Hosting (Bootstrap Budget)

Component Provider Tier Monthly Cost
Proxy Engine Fly.io 1x shared-cpu-1x (256MB) ~$3
Dashboard API Fly.io 1x shared-cpu-1x (scale-to-zero) ~$2
Dashboard UI Cloudflare Pages Free $0
PostgreSQL (config) Neon Free (0.5GB) $0
TimescaleDB (telemetry) Neon (plain PG) Free (0.5GB) $0
Redis (cache) Upstash Free (10K cmd/day) $0
CI/CD Gitea Actions Self-hosted (NAS) $0
DNS + CDN Cloudflare Free $0
Email (digests) Resend Free (100/day) $0
Total ~$5/mo

Migration Path to AWS (at scale)

When dd0c/route hits ~$1K MRR or needs guaranteed SLAs:

Component From To
Proxy Fly.io ECS Fargate (same Docker image)
API Fly.io ECS Fargate
UI Cloudflare Pages CloudFront + S3
PostgreSQL Neon RDS PostgreSQL
TimescaleDB Neon RDS + TimescaleDB extension
Redis Upstash ElastiCache
CI/CD Gitea Actions Gitea Actions (keep)
Email Resend SES

The migration is container-level — same Dockerfiles, same binaries. Only env vars change.

Gitea Actions Setup

Runner on Brian's NAS (TrueNAS, 500/500 fiber):

# Install Gitea runner
wget https://dl.gitea.com/act_runner/latest/act_runner-linux-amd64
chmod +x act_runner-linux-amd64
./act_runner-linux-amd64 register --instance http://192.168.86.11:3005 --token <runner-token>
./act_runner-linux-amd64 daemon

Workflows at .gitea/workflows/:

  • ci.yml — Rust tests + clippy + fmt + UI build (every push)
  • benchmark.yml — Proxy latency P99 gate (pushes to src/proxy/)
  • deploy.yml — Fly.io + Cloudflare Pages deploy (main branch)

Secrets Required

Set in Gitea → Repository → Settings → Secrets:

  • FLY_API_TOKEN — Fly.io deploy token
  • CLOUDFLARE_API_TOKEN — Cloudflare Pages deploy
  • CLOUDFLARE_ACCOUNT_ID — Cloudflare account
  • DATABASE_URL — Neon connection string
  • REDIS_URL — Upstash connection string
  • JWT_SECRET — Production JWT signing key

DNS

route.dd0c.dev    → Fly.io proxy (CNAME dd0c-route-proxy.fly.dev)
api.dd0c.dev      → Fly.io API (CNAME dd0c-route-api.fly.dev)
app.dd0c.dev      → Cloudflare Pages (auto)