Social LiveDocumentationPLATFORM DOCS

Deployment & Operations

How code reaches production -the containers, nginx, and the deploy commands.

Last updated Thu Jul 16 2026 00:00:00 GMT+0000 (Coordinated Universal Time)

TL;DR -Production is one server running a small set of Docker containers, with nginx handling secure connections. Deploying is mostly git pull followed by one docker compose ... up command per piece that changed.

Who this is for -DevOps & Operations: your day-to-day deploy reference. Executive & Product: a plain sense of how simple and low-risk a routine deploy is. Engineering: the exact commands, the postgres-blip caveat, and how the mobile app differs.

"Operations" is the running of the live service -shipping new code, watching logs, keeping the database backed up. This section is the operator's handbook.

The whole production system lives on a single rented server (a VPS). On that box, each part of the app runs in its own container -a sealed package holding a program and everything it needs. In front of all of them sits nginx, the single secure front door that greets every visitor and forwards each request to the right container. Deploying a change means updating the code and restarting the affected container; the rest keep running untouched.

The system is defined by one file, docker-compose.prod.yml at the repo root, with secrets in .env.production (gitignored) beside it.

What runs on the box

Each row below is one container -one running piece of the app -plus the database. The "Port" column is the internal port nginx forwards to.

ContainerImage sourcePortRole
social-live-postgrespostgres:16internalDatabase (volume social_live_postgres_data)
social-live-backendbackend/Dockerfile3000 + UDP 40000–40100API, sockets, SFU (volume social_live_uploads)
social-live-adminadmin/Dockerfile3011Operator dashboard
social-live-room-simulatortools/.../Dockerfile3012QA console
social-live-docsdocs-portal/Dockerfile3013Public docs portal (this site)

nginx (host) terminates TLS for the API domain (→3000, including WebSocket upgrade) and the admin/simulator/docs hosts (→3011/3012/3013). WebRTC media bypasses nginx entirely over the published UDP range -that's the direct, fast path live video and audio take.

How it works

Standard deploys

A normal deploy is: pull the latest code, then rebuild only the piece you changed. Pick the matching command.

git pull

# Backend (code change)
docker compose -f docker-compose.prod.yml --env-file .env.production up -d --build backend

# Admin / docs change
docker compose -f docker-compose.prod.yml --env-file .env.production up -d --build admin

# Env-only change (no rebuild)
docker compose -f docker-compose.prod.yml --env-file .env.production up -d backend

Notes:

  • Validate config first when unsure: docker compose -f docker-compose.prod.yml --env-file .env.production config --quiet
  • Compose recreates dependents when env_file content changes -expect a few-second postgres blip on env edits (data is on the volume; nothing is lost).
  • The backend Dockerfile runs Prisma generate/migrate during build/start, so schema changes deploy with the code that needs them.

The mobile app is deployed separately

The phone app is not on this server. It ships through the app stores, so a server deploy can never fix a client-side bug -and vice versa.

Client fixes ship by building the Flutter app (flutter build) and installing through the stores/devices -server deploys never fix client-side bugs. See docs/device-deployment.md in the repo for device workflows.

Environments

Local development runs the backend with npm run backend:dev against local PostgreSQL/Redis using backend/.env; the Flutter app points at it with --dart-define=API_BASE_URL. Full variable reference: Environment variables.