Trovella Wiki

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:

ContainerImagePortPurpose
caddycaddy:2-alpine80, 443 (public)TLS termination, HTTP/3, reverse proxy, www redirect
webus-central1-docker.pkg.dev/trovella-shared/trovella/web:latest3000 (internal)Next.js application (standalone server.js)
cloud-sql-proxygcr.io/cloud-sql-connectors/cloud-sql-proxy:2.21.25432 (internal)IAM-authenticated tunnel to Cloud SQL
typesensetypesense/typesense:27.18108 (internal)Keyword search engine with persistent data volume
inngestinngest/inngest:latest8288 (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

PropertyValue
Machine typee2-custom-2-6144 (2 vCPU, 6 GB RAM)
OSUbuntu 24.04 LTS
Disk50 GB pd-standard
Zoneus-central1-a
Static IPReserved via Terraform
Monthly cost~$37
Upgrade pathe2-standard-2 (8 GB, ~$49/month) -- one gcloud command, ~2 min downtime

Memory Budget

ServiceEstimated Usage
Next.js768 MB -- 1 GB
Typesense1 -- 2 GB
Inngest256 -- 512 MB
Cloud SQL ProxyMinimal (~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:

ContainerImagePortNotes
postgrespgvector/pgvector:pg185433Local PostgreSQL (no Cloud SQL Proxy needed)
redisredis:8-alpine6379Local Redis (production uses Upstash)
mailpitaxllent/mailpit:latest1025, 8025SMTP testing (UI at localhost:8025)
inngestinngest/inngest:latest8288Dev mode (inngest dev)
typesensetypesense/typesense:27.18108Same 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/:

FileContents
main.tfService account, firewall rules, static IP, VM instance
variables.tfMachine type, disk size, zone, notification email
startup.shFirst-boot script: installs Docker, configures Artifact Registry auth, installs Cloud Ops Agent
monitoring.tfAlert policies (CPU, memory, disk) and HTTPS uptime check
outputs.tfExternal 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.

On this page