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 pullfollowed by onedocker compose ... upcommand 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.
| Container | Image source | Port | Role |
|---|---|---|---|
social-live-postgres | postgres:16 | internal | Database (volume social_live_postgres_data) |
social-live-backend | backend/Dockerfile | 3000 + UDP 40000–40100 | API, sockets, SFU (volume social_live_uploads) |
social-live-admin | admin/Dockerfile | 3011 | Operator dashboard |
social-live-room-simulator | tools/.../Dockerfile | 3012 | QA console |
social-live-docs | docs-portal/Dockerfile | 3013 | Public 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_filecontent 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.
Related pages
- Runbooks -copy-paste procedures for common tasks.
- Backup & Restore -nightly backups and the restore drill.
- Android release & Drive upload -building and shipping an Android build.
- Infrastructure -the server, containers, and nginx in depth.
- Environment variables -every backend setting.