Skip to content
BoringStack
GitHub

Infra template: overview

5 min read

infra-compose

infra/compose composes apps/api and apps/ui into one running stack. It targets your laptop and a first VPS before you need cluster machinery, while keeping observability, email, and queue tooling close to the app.

Compose

local and single-host runtime

Traefik

prod ingress and TLS

Overlays

observability, mail, queues

The base stack (always on) plus per-profile services:

data

postgres

Always-on app database.

cache

valkey

Redis-protocol cache plus BullMQ queue backend.

edge

traefik

Prod reverse proxy, ACME, and one-domain path routing.

migrate

api-migrate

One-shot schema push plus optional superuser seed.

api

api-dev / api

Bun + Elysia in dev, GHCR image in production.

ui

ui-dev / ui

Vite dev server locally, nginx static image in production.

ops

observability overlays

Prometheus, Grafana, Loki, Promtail, and exporters on demand.

dev

mail and queue tools

Mailpit, Bull Board, GlitchTip, and WUD are profile overlays.

Profile model
$ ./dev.sh up -d
$ STACK=prod ./dev.sh up -d
$ WITH_OBSERVABILITY=1 ./dev.sh up -d
$ WITH_GLITCHTIP=1 ./dev.sh up -d
$ WITH_BULLMQ=1 ./dev.sh up -d
$ WITH_WUD=1 ./dev.sh up -d
$ WITH_MAILPIT=1 ./dev.sh up -d

#   baseline dev: no Traefik; Vite proxies /api/*
#   prod: GHCR images, Traefik, HTTPS via ACME
#   overlays: metrics, logs, error tracking, queues, mail, image updates

Flags compose: WITH_OBSERVABILITY=1 WITH_GLITCHTIP=1 ./dev.sh up -d brings up both overlays alongside the base. See Profiles & overlays.

Infra source map
infra/compose/
  • compose/Compose files and per-profile service overlays
    • docker-compose.ymlBase: postgres, valkey, api-migrate, api/ui, Traefik in prod
    • docker-compose.development-labels.ymlDev overlay: host-published data ports
    • docker-compose.production-labels.ymlProd overlay: HTTPS, ACME, path routing, security headers
    • docker-compose.observability.ymlPrometheus, Grafana, Loki, Promtail, exporters
    • docker-compose.glitchtip.ymlGlitchTip dev + prod
    • docker-compose.glitchtip-prod-labels.ymlProd-only HTTPS + BasicAuth labels for GlitchTip
    • docker-compose.bullmq.ymlBull-board in development
    • docker-compose.wud.ymlWUD image-update detector
    • docker-compose.mailpit.ymlLocal SMTP catcher in development
    • dev.shOrchestrator
    • .env.exampleAll knobs in one file
    • prometheus/Scrape config
    • grafana/Datasource provisioning
    • alertmanager/Alert routes
    • promtail/Log scrape config
    • glitchtip/init-db.sql
  • scripts/Operational wrappers
    • compose-up.shbring the stack up
    • compose-down.shstop without deleting data
    • compose-down-clean.shclean local services intentionally
    • backup-wrapper.example.shPostgres to rclone, with retention
    • ufw.example.shUFW + Cloudflare IP allowlist
    • glitchtip-bootstrap.shProd GlitchTip migrate + superuser
  • docs/Runbooks and cheatsheets

Two bridge networks. Services are split on purpose:

backend

Data plane network

postgres, valkey, api[-dev], api-migrate, exporters, glitchtip, and mailpit.

frontend

Ingress network

traefik in prod, ui[-dev], and glitchtip-web. Traefik joins both when it needs to route.

In prod, Traefik joins both networks so it can route HTTPS from frontend to services on backend. The data plane (Postgres, Valkey) is never exposed to frontend.

Every service has deploy.resources.limits and reservations driven by env vars with sane defaults sized for a 4-vCPU / 8 GB host. Adjust in compose/.env; see Resource limits for sizing guidance.

  • Kubernetes manifests. This template is Compose-first; mixing Compose and cluster YAML in the starter would blur the deployment path BoringStack keeps intentionally clear.
  • Application code. The apps/api and apps/ui own that.
  • Cloud-provider provisioning. The OpenTofu bootstrap in infra/bootstrap handles that.