Docker Setup
Complete guide for running Bitrate with Docker.
🐳 Overview
Docker Compose files live in infra/:
| File | Purpose |
|---|---|
infra/docker-compose.dev.yaml | Minimal — postgres + redis only (~320 MB). Use with native app dev. |
infra/docker-compose.preprod.yaml | Full development stack — all apps in containers. |
infra/docker-compose.prod.yaml | Production stack with nginx reverse proxy. |
📦 Services
Development Stack (docker-compose.preprod.yaml)
services:
postgres: # PostgreSQL 16 database
redis: # Cache & sessions
api: # NestJS backend
web: # Next.js frontend (web-player)
mobile: # React Native / Expo bundler [--profile mobile]
desktop: # Vite dev server (UI only) [--profile desktop]
Production Services (docker-compose.prod.yaml)
services:
nginx: # Reverse proxy
postgres: # Database
redis: # Cache
api: # Backend API
web: # Web app
🚀 Quick Start
Recommended: minimal infra + native apps
# Start postgres + redis only
docker compose -f infra/docker-compose.dev.yaml up -d
# Run apps natively
pnpm dev
Full Docker development stack
# First run (build images, migrate, seed)
docker compose -f infra/docker-compose.preprod.yaml up -d --build
docker compose -f infra/docker-compose.preprod.yaml exec api pnpm --filter @bitrate/api run db:migration:start
docker compose -f infra/docker-compose.preprod.yaml exec api pnpm --filter @bitrate/api run seed
# Subsequent runs
docker compose -f infra/docker-compose.preprod.yaml up -d
# Stop
docker compose -f infra/docker-compose.preprod.yaml down
Via task (cross-platform shortcut)
task infra:up # minimal: postgres + redis
task dev:up # full dev stack
task init # first-time: build + migrate + seed
task dev:down # stop
task dev:logs # tail all logs
task dev:logs -- api # tail specific service
🔧 Service Configuration
PostgreSQL
postgres:
image: postgres:16-alpine
ports:
- "5432:5432"
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: admin
POSTGRES_DB: bitrate
Access:
- Host:
localhost:5432 - User:
admin/ Password:admin - Database:
bitrate
Redis
redis:
image: redis:7-alpine
ports:
- "6379:6379"
Access: localhost:6379
📝 Docker Commands
Container Management
DC="docker compose -f infra/docker-compose.preprod.yaml"
# View running containers
$DC ps
# View logs
$DC logs -f
# View logs for specific service
$DC logs -f api
# Restart service
$DC restart api
# Stop all services
$DC down
# Stop and remove volumes
$DC down -v
Exec Commands
DC="docker compose -f infra/docker-compose.preprod.yaml"
# Run migrations
$DC exec api pnpm --filter @bitrate/api run db:migration:start
# Open shell
$DC exec api sh
# Open psql
$DC exec postgres psql -U admin bitrate
Build & Rebuild
DC="docker compose -f infra/docker-compose.preprod.yaml"
# Build specific service
$DC build api
# Rebuild and start
$DC up -d --build
# Force rebuild (no cache)
$DC build --no-cache api
🛠️ Development Workflow
1. Start Infrastructure
# Minimal (recommended for native dev)
docker compose -f infra/docker-compose.dev.yaml up -d
# Full stack
docker compose -f infra/docker-compose.preprod.yaml up -d
2. Run Apps Locally
pnpm --filter @bitrate/api start:dev
pnpm --filter @bitrate/web-player dev
📱 Optional: Mobile & Desktop containers
Mobile and Desktop services use Docker Compose profiles:
# Mobile (Metro Bundler + Expo tunnel)
docker compose -f infra/docker-compose.preprod.yaml --profile mobile up -d mobile
# Open http://localhost:19000
# Desktop (Vite only, no Tauri)
docker compose -f infra/docker-compose.preprod.yaml --profile desktop up -d desktop
# Open http://localhost:1420
# Stop profile containers
docker compose -f infra/docker-compose.preprod.yaml --profile mobile down
docker compose -f infra/docker-compose.preprod.yaml --profile desktop down
🔍 Debugging
View Logs
DC="docker compose -f infra/docker-compose.preprod.yaml"
$DC logs -f # all services
$DC logs -f api # specific service
$DC logs --tail=100 api # last 100 lines
Inspect Container
DC="docker compose -f infra/docker-compose.preprod.yaml"
$DC exec api env # environment variables
$DC exec api ps aux # processes
$DC exec api ls -la /app
Network Issues
DC="docker compose -f infra/docker-compose.preprod.yaml"
docker network ls
$DC exec api ping postgres
📦 Volumes
Backup PostgreSQL
docker compose -f infra/docker-compose.preprod.yaml exec -T postgres \
pg_dump -U admin bitrate > backups/backup.sql
# Or via task:
task db:backup
Restore
docker compose -f infra/docker-compose.preprod.yaml exec -T postgres \
psql -U admin bitrate < backups/backup.sql
# Or via task:
task db:restore -- backup_20260101_120000.sql
Clear All Data
docker compose -f infra/docker-compose.preprod.yaml down -v
# Or via task (with prompt):
task dev:clean
🚀 Production Deployment
Start Production
# First time (build + start)
docker compose -f infra/docker-compose.prod.yaml up -d --build
# Subsequent runs (with confirmation via task)
task prod:up
Environment Variables
# Create .env from example
cp .env.example .env
# Edit production values
🔒 Security
Network Isolation
The docker-compose files use a dedicated bridge network (bitrate-network) that isolates services from the host network. Only required ports are published.
📊 Monitoring
Health Checks
task dev:status # container status
task monitor:health # status + an HTTP probe per app
task monitor:report # health, resources, database, disk, recent errors
task monitor # interactive menu
monitor:* wraps infra/docker-monitor.sh, which can also be called directly
(./infra/docker-monitor.sh health|resources|disk|db|network|errors|report|fix).
🐛 Troubleshooting
Port Already in Use
# Find process using port
lsof -i :3000
kill -9 <PID>
Container Won't Start
DC="docker compose -f infra/docker-compose.preprod.yaml"
$DC logs api
$DC build --no-cache api
$DC up -d api
Database Connection Failed
DC="docker compose -f infra/docker-compose.preprod.yaml"
$DC ps postgres
$DC logs postgres
$DC restart postgres
Permission Errors on dist/ After Docker Build
Docker may write dist/ files as root. Clean before pushing:
pnpm clean:dist
# or: task clean:dist
Related: