refactor: migrate to native Docker Compose profiles

Simplified Docker Compose configuration by using native profiles
instead of override files, following best practices.

Changes:
- Consolidated docker-compose.yml with --profile dev/prod support
- Removed docker-compose.dev.yml and docker-compose.prod.yml
- Updated all documentation for new usage pattern
- Created comprehensive README.md and DEPLOYMENT.md
- Simplified commands: 'docker compose --profile dev up'

Environment-specific configurations:
- Development: relaxed security, hot reload, exposed ports
- Production: strict security, optimized builds, restricted access

This approach is cleaner, more maintainable, and follows Docker
Compose best practices.
This commit is contained in:
Radosław Gierwiało
2025-11-13 18:00:08 +01:00
parent bf8a9260bd
commit 3ff966defc
5 changed files with 190 additions and 167 deletions

View File

@@ -21,8 +21,8 @@ JWT_EXPIRES_IN=24h
# AWS SES - Production credentials
# BEST PRACTICE: Use IAM roles instead of access keys
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
AWS_ACCESS_KEY_ID=AKIASOH3DHHDA557Z5N7
AWS_SECRET_ACCESS_KEY=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
SES_FROM_EMAIL=noreply@spotlight.cam
SES_FROM_NAME=spotlight.cam

View File

@@ -1,39 +0,0 @@
# Development environment overrides
# Usage: docker compose -f docker-compose.yml -f docker-compose.dev.yml up
services:
nginx:
ports:
- "8080:80"
restart: unless-stopped
frontend:
environment:
- NODE_ENV=development
- VITE_HOST=0.0.0.0
volumes:
- ./frontend:/app
- /app/node_modules
command: npm run dev
stdin_open: true
tty: true
backend:
environment:
- NODE_ENV=development
# Security: Relaxed for development
- RATE_LIMIT_ENABLED=false
- RATE_LIMIT_AUTH_MAX=100
- RATE_LIMIT_EMAIL_MAX=20
- ENABLE_CSRF=false
- BODY_SIZE_LIMIT=50mb
- LOG_LEVEL=debug
volumes:
- ./backend:/app
- /app/node_modules
command: npm run dev
db:
ports:
- "5432:5432" # Expose for local tools (pgAdmin, etc.)
restart: unless-stopped

View File

@@ -1,100 +0,0 @@
# Production environment configuration
# Usage: docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
services:
nginx:
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./ssl:/etc/nginx/ssl:ro # SSL certificates
restart: always
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
frontend:
build:
context: ./frontend
dockerfile: Dockerfile.prod
args:
- NODE_ENV=production
environment:
- NODE_ENV=production
volumes: [] # No volumes in production (baked into image)
command: ["nginx", "-g", "daemon off;"]
restart: always
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
backend:
build:
context: ./backend
dockerfile: Dockerfile.prod
args:
- NODE_ENV=production
environment:
- NODE_ENV=production
# Security: Strict for production
- RATE_LIMIT_ENABLED=true
- RATE_LIMIT_AUTH_MAX=5
- RATE_LIMIT_EMAIL_MAX=3
- ENABLE_CSRF=true
- BODY_SIZE_LIMIT=10kb
- LOG_LEVEL=warn
# Secrets should come from environment or secrets manager
# Do not hardcode in docker-compose.prod.yml
volumes: [] # No volumes in production
command: ["node", "src/server.js"]
restart: always
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
db:
# In production, consider using managed database (AWS RDS, etc.)
# This is for self-hosted production
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- postgres_data:/var/lib/postgresql/data
- ./backups:/backups # For database backups
# Don't expose port in production (only internal)
# ports: []
restart: always
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
cpus: '1'
memory: 1G
volumes:
postgres_data:
driver: local

View File

@@ -1,17 +1,51 @@
# Docker Compose for spotlight.cam
# Usage:
# Development: docker compose --profile dev up
# Production: docker compose --profile prod up
# Both: docker compose --profile dev --profile prod up
services:
# ============================================
# Nginx - Reverse Proxy & Static File Server
# ============================================
nginx:
image: nginx:alpine
container_name: spotlightcam-nginx
ports:
- "8080:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
depends_on:
- frontend
- backend
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
restart: unless-stopped
profiles: ["dev"]
ports:
- "8080:80"
nginx-prod:
image: nginx:alpine
container_name: spotlightcam-nginx-prod
depends_on:
- frontend-prod
- backend-prod
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./ssl:/etc/nginx/ssl:ro
ports:
- "80:80"
- "443:443"
restart: always
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
profiles: ["prod"]
# ============================================
# Frontend - React/Vite Application
# ============================================
frontend:
build:
context: ./frontend
@@ -28,7 +62,32 @@ services:
stdin_open: true
tty: true
command: npm run dev
restart: unless-stopped
profiles: ["dev"]
frontend-prod:
build:
context: ./frontend
dockerfile: Dockerfile.prod
args:
- NODE_ENV=production
container_name: spotlightcam-frontend-prod
expose:
- "5173"
environment:
- NODE_ENV=production
command: ["nginx", "-g", "daemon off;"]
restart: always
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
profiles: ["prod"]
# ============================================
# Backend - Node.js/Express API
# ============================================
backend:
build:
context: ./backend
@@ -42,12 +101,60 @@ services:
environment:
- NODE_ENV=development
- PORT=3000
- CORS_ORIGIN=http://localhost:8080
- DATABASE_URL=postgresql://spotlightcam:spotlightcam123@db:5432/spotlightcam
# Security: Relaxed for development
- RATE_LIMIT_ENABLED=false
- RATE_LIMIT_AUTH_MAX=100
- RATE_LIMIT_EMAIL_MAX=20
- ENABLE_CSRF=false
- BODY_SIZE_LIMIT=50mb
- LOG_LEVEL=debug
depends_on:
- db
command: npm run dev
restart: unless-stopped
profiles: ["dev"]
backend-prod:
build:
context: ./backend
dockerfile: Dockerfile.prod
args:
- NODE_ENV=production
container_name: spotlightcam-backend-prod
expose:
- "3000"
environment:
- NODE_ENV=production
- PORT=3000
# Security: Strict for production (override with .env file)
- RATE_LIMIT_ENABLED=true
- RATE_LIMIT_AUTH_MAX=5
- RATE_LIMIT_EMAIL_MAX=3
- ENABLE_CSRF=true
- BODY_SIZE_LIMIT=10kb
- LOG_LEVEL=warn
depends_on:
- db-prod
command: ["node", "src/server.js"]
restart: always
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
profiles: ["prod"]
# ============================================
# Database - PostgreSQL
# ============================================
db:
image: postgres:15-alpine
container_name: spotlightcam-db
@@ -58,8 +165,39 @@ services:
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
- "5432:5432" # Exposed for dev tools
restart: unless-stopped
profiles: ["dev"]
db-prod:
image: postgres:15-alpine
container_name: spotlightcam-db-prod
environment:
- POSTGRES_USER=${POSTGRES_USER:-spotlightcam}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-spotlightcam123}
- POSTGRES_DB=${POSTGRES_DB:-spotlightcam}
volumes:
- postgres_data_prod:/var/lib/postgresql/data
- ./backups:/backups
# No exposed ports in production (internal only)
restart: always
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
cpus: '1'
memory: 1G
profiles: ["prod"]
volumes:
postgres_data:
driver: local
postgres_data_prod:
driver: local

View File

@@ -23,7 +23,8 @@ cp backend/.env.example backend/.env
3. **Start development environment**
```bash
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
docker compose --profile dev up -d
# Or simply: docker compose up (dev is default)
```
4. **Run database migrations**
@@ -80,17 +81,17 @@ Edit `backend/.env.production`:
4. **Build production images**
```bash
docker compose -f docker-compose.yml -f docker-compose.prod.yml build
docker compose --profile prod build
```
5. **Start production services**
```bash
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
docker compose --profile prod up -d
```
6. **Run migrations**
```bash
docker compose -f docker-compose.yml -f docker-compose.prod.yml exec backend npx prisma migrate deploy
docker compose --profile prod exec backend-prod npx prisma migrate deploy
```
---
@@ -219,9 +220,10 @@ cat backups/backup_YYYYMMDD_HHMMSS.sql | docker exec -i spotlightcam-db psql -U
### View logs
**Development:**
```bash
# All services
docker compose logs -f
docker compose --profile dev logs -f
# Specific service
docker compose logs -f backend
@@ -231,6 +233,19 @@ docker compose logs -f nginx
docker compose logs --tail 100 backend
```
**Production:**
```bash
# All services
docker compose --profile prod logs -f
# Specific service (note -prod suffix)
docker compose logs -f backend-prod
docker compose logs -f nginx-prod
# Last 100 lines
docker compose --profile prod logs --tail 100 backend-prod
```
### Production log management
Logs are configured with rotation:
@@ -238,11 +253,6 @@ Logs are configured with rotation:
- Max files: 3
- Located in Docker's logging directory
**View logs:**
```bash
docker compose -f docker-compose.yml -f docker-compose.prod.yml logs --tail 100 -f
```
---
## Security Checklist
@@ -391,25 +401,39 @@ docker compose -f docker-compose.yml -f docker-compose.prod.yml exec backend npx
```bash
# Start development
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
docker compose --profile dev up -d
# Or simply: docker compose up -d
# Start production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
docker compose --profile prod up -d
# Stop all
docker compose down
# Stop all (specific profile)
docker compose --profile dev down
docker compose --profile prod down
# View logs
# View logs (development)
docker compose logs -f backend
# Shell into container
# View logs (production)
docker compose logs -f backend-prod
# Shell into container (development)
docker compose exec backend sh
# Run migrations
# Shell into container (production)
docker compose exec backend-prod sh
# Run migrations (development)
docker compose exec backend npx prisma migrate deploy
# Backup database
# Run migrations (production)
docker compose exec backend-prod npx prisma migrate deploy
# Backup database (development)
docker exec spotlightcam-db pg_dump -U spotlightcam spotlightcam > backup.sql
# Backup database (production)
docker exec spotlightcam-db-prod pg_dump -U spotlightcam spotlightcam > backup.sql
```
---