Compute Overview
How Trovella's production compute infrastructure works -- a single Compute Engine VM running Docker Compose with Caddy, Next.js, and service containers.
Trovella runs on a single Google Compute Engine VM (e2-custom-2-6144) in us-central1-a. All services run as Docker containers orchestrated by Docker Compose. Caddy handles TLS termination and reverse proxying. There is no auto-scaling, no load balancer, and no multi-zone redundancy -- this is a deliberate MVP trade-off for simplicity and predictable cost.
Architecture at a Glance
Internet
|
| HTTPS (443) / HTTP (80, redirects to 443)
v
Caddy (caddy:2-alpine)
|
| reverse_proxy web:3000
v
Next.js (custom image, standalone server.js)
|
|-- cloud-sql-proxy:5432 --> Cloud SQL PostgreSQL 18
|-- typesense:8108 --> Typesense 27.1 (search)
|-- inngest:8288 --> Inngest Dev Server (background jobs)
All inter-service communication happens over the Docker internal network with sub-millisecond latency. No traffic between containers traverses the public internet.
Production Stack
Five containers run on the VM, defined in infra/docker-compose.prod.yml:
| Container | Image | Port | Purpose |
|---|---|---|---|
caddy | caddy:2-alpine | 80, 443 (public) | TLS termination, HTTP/3, reverse proxy, www redirect |
web | us-central1-docker.pkg.dev/trovella-shared/trovella/web:latest | 3000 (internal) | Next.js application (standalone server.js) |
cloud-sql-proxy | gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.21.2 | 5432 (internal) | IAM-authenticated tunnel to Cloud SQL |
typesense | typesense/typesense:27.1 | 8108 (internal) | Keyword search engine with persistent data volume |
inngest | inngest/inngest:latest | 8288 (internal) | Durable background job execution |
Only Caddy exposes ports to the public internet. All other services communicate on the Docker internal network via service names.
VM Specifications
| Property | Value |
|---|---|
| Machine type | e2-custom-2-6144 (2 vCPU, 6 GB RAM) |
| OS | Ubuntu 24.04 LTS |
| Disk | 50 GB pd-standard |
| Zone | us-central1-a |
| Static IP | Reserved via Terraform |
| Monthly cost | ~$37 |
| Upgrade path | e2-standard-2 (8 GB, ~$49/month) -- one gcloud command, ~2 min downtime |
Memory Budget
| Service | Estimated Usage |
|---|---|
| Next.js | 768 MB -- 1 GB |
| Typesense | 1 -- 2 GB |
| Inngest | 256 -- 512 MB |
| Cloud SQL Proxy | Minimal (~50 MB) |
| OS + Docker overhead | ~512 MB |
| Total | ~3.5 -- 5.5 GB (fits in 6 GB with headroom) |
Local Development Stack
Local development uses docker-compose.yml (root of repo) with different services:
| Container | Image | Port | Notes |
|---|---|---|---|
postgres | pgvector/pgvector:pg18 | 5433 | Local PostgreSQL (no Cloud SQL Proxy needed) |
redis | redis:8-alpine | 6379 | Local Redis (production uses Upstash) |
mailpit | axllent/mailpit:latest | 1025, 8025 | SMTP testing (UI at localhost:8025) |
inngest | inngest/inngest:latest | 8288 | Dev mode (inngest dev) |
typesense | typesense/typesense:27.1 | 8108 | Same version as production |
Start with pnpm docker:up, stop with pnpm docker:down.
Terraform Module
The VM and its associated resources are defined in infra/modules/compute-vm/:
| File | Contents |
|---|---|
main.tf | Service account, firewall rules, static IP, VM instance |
variables.tf | Machine type, disk size, zone, notification email |
startup.sh | First-boot script: installs Docker, configures Artifact Registry auth, installs Cloud Ops Agent |
monitoring.tf | Alert policies (CPU, memory, disk) and HTTPS uptime check |
outputs.tf | External IP, instance name, zone, service account email |
The module is instantiated in infra/environments/prod/main.tf alongside the Cloud SQL and Secret Manager modules.
What to Read Next
- VM Decision (ADR-008) -- why a single VM instead of Cloud Run or Firebase App Hosting
- Docker Containers -- container configuration, health checks, and the Docker build pipeline
- Caddy Reverse Proxy -- TLS, HTTP/3, and proxy configuration
- Networking -- firewall rules, DNS, IAP SSH, and the Cloud SQL Proxy
- VM Management -- upgrades, resource checks, cleanup, and monitoring alerts