Skip to main content

Docker Setup

Complete guide for running Bitrate with Docker.

🐳 Overview

Docker Compose files live in infra/:

FilePurpose
infra/docker-compose.dev.yamlMinimal — postgres + redis only (~320 MB). Use with native app dev.
infra/docker-compose.preprod.yamlFull development stack — all apps in containers.
infra/docker-compose.prod.yamlProduction 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

# 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: