VOD Docs

Infrastructure overview

Where each part of VOD runs and how the pieces are wired together.

VOD runs in three places:

PartHostingDomain
Frontend (Next.js)Vercelvod.spokhrel.dev
Docs site (this site)Verceldocs.vod.spokhrel.dev
Backend (API, worker, databases, storage, proxy)One Hetzner VPS running Docker Composeapi.vod.spokhrel.dev
Architecture diagram · placeholder
Deployment topology: Vercel (frontend, docs) and one Hetzner VPS running seven containers behind Caddy

Show public ports (80/443 only) vs loopback-only and private-network-only services.

The backend server

Seven containers on one host, defined in infra/docker-compose.yml:

ServiceImageNetwork exposure
caddycaddy:2-alpineHost network: the only public entry point (ports 80 and 443)
apibuilt from backend/Loopback only (127.0.0.1:8000)
workerbuilt from backend/ (same image)None
postgrespostgres:16-alpineNone (private Docker network)
redisredis:7-alpineNone (private Docker network)
miniominio/minioLoopback only (127.0.0.1:9000); the admin console is not published
tusdtusproject/tusd:v2.9.2Loopback only (127.0.0.1:1080)

All services except Caddy share a private bridge network (backend_net) and reach each other by service name (postgres:5432, redis:6379, minio:9000, api:8000). Caddy runs on the host network and reaches the three services it proxies through their loopback ports.

Why one server

The project is built to show that a complete VOD platform can run on a small, inexpensive server. That choice drives several decisions documented elsewhere:

  • The worker processes one video at a time (ADR 0002).
  • Each container has a memory limit, so a heavy transcode cannot starve the database or the API.
  • Video bytes bypass Python on the way in (tusd) and on the way out (Caddy → MinIO).

Resource budget

Memory limits from the production compose file:

Servicemem_limitNotes
worker1800 MBFFmpeg needs the most headroom; CPU weight lowered (cpu_shares: 256) so the API wins under contention
api768 MBcpu_shares: 1024
postgres512 MB
minio512 MB
redis256 MB
tusd192 MB
caddy64 MB

cpu_shares are relative weights, not hard caps: they only matter when processes compete for CPU.

Environments

EnvironmentCompose fileStatus
Localinfra/docker-compose.local.ymlIn daily use; adds pgAdmin, Flower and RedisInsight
Productioninfra/docker-compose.ymlLive
Staginginfra/docker-compose.staging.ymlIncomplete: no Caddy or tusd service, and the staging.env file it expects does not exist, so it is not used

Details: Docker Compose, Caddy, Local development, Deployment.

On this page