Files
sexy.pivoine.art/COMPOSE.md
2025-10-26 14:48:30 +01:00

12 KiB

Docker Compose Guide

This guide explains the Docker Compose setup for sexy.pivoine.art with local development and production configurations.

Architecture Overview

The application uses a multi-file compose setup with two configurations:

  1. compose.yml - Base configuration for local development
  2. compose.production.yml - Production overrides with Traefik integration

Service Architecture

┌─────────────────────────────────────────────────────────────┐
│  🌐 Traefik Reverse Proxy (Production Only)                │
│  ├─ HTTPS Termination                                       │
│  ├─ Automatic Let's Encrypt                                 │
│  └─ Routes traffic to frontend & Directus API              │
├─────────────────────────────────────────────────────────────┤
│  💄 Frontend (SvelteKit)                                    │
│  ├─ Port 3000 (internal)                                    │
│  ├─ Serves on https://sexy.pivoine.art                     │
│  └─ Proxies /api to Directus                               │
├─────────────────────────────────────────────────────────────┤
│  🎭 Directus CMS                                            │
│  ├─ Port 8055 (internal)                                    │
│  ├─ Serves on https://sexy.pivoine.art/api                 │
│  ├─ Custom bundle extensions mounted                        │
│  └─ Uploads volume                                          │
├─────────────────────────────────────────────────────────────┤
│  🗄️ PostgreSQL (Local) / External (Production)            │
│  └─ Database for Directus                                   │
├─────────────────────────────────────────────────────────────┤
│  💾 Redis (Local) / External (Production)                  │
│  └─ Cache & session storage                                 │
└─────────────────────────────────────────────────────────────┘

Local Development Setup

Prerequisites

  • Docker 20.10+
  • Docker Compose 2.0+

Quick Start

  1. Create environment file:
cp .env.example .env
# Edit .env with your local settings (defaults work fine)
  1. Start all services:
docker-compose up -d
  1. Access services:

  2. View logs:

docker-compose logs -f
  1. Stop services:
docker-compose down

Local Services

PostgreSQL

  • Image: postgres:16-alpine
  • Port: 5432 (internal only)
  • Volume: postgres-data
  • Database: sexy

Redis

  • Image: redis:7-alpine
  • Port: 6379 (internal only)
  • Volume: redis-data
  • Persistence: AOF enabled

Directus

  • Image: directus/directus:11
  • Port: 8055 (exposed)
  • Volumes:
    • directus-uploads - File uploads
    • ./packages/bundle/dist - Custom extensions
  • Features:
    • Auto-reload extensions
    • WebSockets enabled
    • CORS enabled for localhost

Local Development Workflow

# Start infrastructure (Postgres, Redis, Directus)
docker-compose up -d

# Develop frontend locally with hot reload
cd packages/frontend
pnpm dev

# Build Directus bundle
pnpm --filter @sexy.pivoine.art/bundle build

# Restart Directus to load new bundle
docker-compose restart directus

Production Deployment

Prerequisites

  • External PostgreSQL database
  • External Redis instance
  • Traefik reverse proxy configured
  • External network: compose_network

Setup

The production compose file now uses the include directive to automatically extend compose.yml, making deployment simpler.

  1. Create production environment file:
cp .env.production.example .env.production
  1. Edit .env.production with your values:
# Database (external)
CORE_DB_HOST=your-postgres-host
SEXY_DB_NAME=sexy_production
DB_USER=sexy
DB_PASSWORD=your-secure-password

# Redis (external)
CORE_REDIS_HOST=your-redis-host

# Directus
SEXY_DIRECTUS_SECRET=your-32-char-random-secret
ADMIN_PASSWORD=your-secure-admin-password

# Traefik
SEXY_TRAEFIK_HOST=sexy.pivoine.art

# Frontend
PUBLIC_API_URL=https://sexy.pivoine.art/api
PUBLIC_URL=https://sexy.pivoine.art

# Email (SMTP)
EMAIL_SMTP_HOST=smtp.your-provider.com
EMAIL_SMTP_USER=your-email@domain.com
EMAIL_SMTP_PASSWORD=your-smtp-password
  1. Deploy:
# Simple deployment - compose.production.yml includes compose.yml automatically
docker-compose -f compose.production.yml --env-file .env.production up -d

# Or use the traditional multi-file approach (same result)
docker-compose -f compose.yml -f compose.production.yml --env-file .env.production up -d

Production Services

Directus

  • Image: directus/directus:11 (configurable)
  • Network: compose_network (external)
  • Volumes:
    • /var/www/sexy.pivoine.art/uploads - Persistent uploads
    • /var/www/sexy.pivoine.art/packages/bundle/dist - Extensions
  • Traefik routing:
    • Domain: sexy.pivoine.art/api
    • Strips /api prefix before forwarding
    • HTTPS with auto-certificates

Frontend

  • Image: ghcr.io/valknarxxx/sexy:latest (from GHCR)
  • Network: compose_network (external)
  • Volume: /var/www/sexy.pivoine.art - Application code
  • Traefik routing:
    • Domain: sexy.pivoine.art
    • HTTPS with auto-certificates

Traefik Integration

Both services are configured with Traefik labels for automatic routing:

Frontend:

  • HTTP → HTTPS redirect
  • Routes sexy.pivoine.art to port 3000
  • Gzip compression enabled

Directus API:

  • HTTP → HTTPS redirect
  • Routes sexy.pivoine.art/api to port 8055
  • Strips /api prefix
  • Gzip compression enabled

Production Commands

# Deploy/update (simplified - uses include)
docker-compose -f compose.production.yml --env-file .env.production up -d

# View logs
docker-compose -f compose.production.yml logs -f

# Restart specific service
docker-compose -f compose.production.yml restart frontend

# Stop all services
docker-compose -f compose.production.yml down

# Update images
docker-compose -f compose.production.yml pull
docker-compose -f compose.production.yml up -d

Environment Variables

Local Development (.env)

Variable Default Description
DB_DATABASE sexy Database name
DB_USER sexy Database user
DB_PASSWORD sexy Database password
DIRECTUS_SECRET - Secret for Directus (min 32 chars)
ADMIN_EMAIL admin@sexy.pivoine.art Admin email
ADMIN_PASSWORD admin Admin password
CORS_ORIGIN http://localhost:3000 CORS allowed origins

See .env.example for full list.

Production (.env.production)

Variable Description Required
CORE_DB_HOST External PostgreSQL host
SEXY_DB_NAME Database name
DB_PASSWORD Database password
CORE_REDIS_HOST External Redis host
SEXY_DIRECTUS_SECRET Directus secret key
SEXY_TRAEFIK_HOST Domain name
EMAIL_SMTP_HOST SMTP server
EMAIL_SMTP_PASSWORD SMTP password
SEXY_FRONTEND_PUBLIC_API_URL Frontend API URL
SEXY_FRONTEND_PUBLIC_URL Frontend public URL

See .env.production.example for full list.

Note: All frontend-specific variables are prefixed with SEXY_FRONTEND_ for clarity.

Volumes

Local Development

  • postgres-data - PostgreSQL database
  • redis-data - Redis persistence
  • directus-uploads - Uploaded files

Production

  • /var/www/sexy.pivoine.art/uploads - Directus uploads
  • /var/www/sexy.pivoine.art - Application code (frontend)

Networks

Local: sexy-network

  • Bridge network
  • Internal communication only
  • Directus exposed on 8055

Production: compose_network

  • External network (pre-existing)
  • Connects to Traefik
  • No exposed ports (Traefik handles routing)

Health Checks

All services include health checks:

PostgreSQL:

  • Command: pg_isready
  • Interval: 10s

Redis:

  • Command: redis-cli ping
  • Interval: 10s

Directus:

  • Endpoint: /server/health
  • Interval: 30s

Frontend:

  • HTTP GET: localhost:3000
  • Interval: 30s

Troubleshooting

Local Development

Problem: Directus won't start

# Check logs
docker-compose logs directus

# Common issues:
# 1. Database not ready - wait for postgres to be healthy
# 2. Wrong secret - check DIRECTUS_SECRET is at least 32 chars

Problem: Can't connect to database

# Check if postgres is running
docker-compose ps postgres

# Verify health
docker-compose exec postgres pg_isready -U sexy

Problem: Extensions not loading

# Rebuild bundle
pnpm --filter @sexy.pivoine.art/bundle build

# Verify volume mount
docker-compose exec directus ls -la /directus/extensions/

# Restart Directus
docker-compose restart directus

Production

Problem: Services not accessible via domain

# Check Traefik labels
docker inspect sexy_frontend | grep traefik

# Verify compose_network exists
docker network ls | grep compose_network

# Check Traefik is running
docker ps | grep traefik

Problem: Can't connect to external database

# Test connection from Directus container
docker-compose exec directus sh
apk add postgresql-client
psql -h $CORE_DB_HOST -U $DB_USER -d $SEXY_DB_NAME

Problem: Frontend can't reach Directus API

# Check Directus is accessible
curl https://sexy.pivoine.art/api/server/health

# Verify CORS settings
# PUBLIC_API_URL should match the public Directus URL

Migration from Old Setup

If migrating from docker-compose.production.yml:

  1. Rename environment variables according to .env.production.example
  2. Update command to use both compose files
  3. Verify Traefik labels match your setup
  4. Test with docker-compose config to see merged configuration
# Validate configuration
docker-compose -f compose.yml -f compose.production.yml --env-file .env.production config

# Deploy
docker-compose -f compose.yml -f compose.production.yml --env-file .env.production up -d

Best Practices

Local Development

  1. Use default credentials (they're fine for local)
  2. Keep EXTENSIONS_AUTO_RELOAD=true for quick iteration
  3. Run frontend via pnpm dev for hot reload
  4. Restart Directus after bundle changes

Production

  1. Use strong passwords for database and admin
  2. Set EXTENSIONS_AUTO_RELOAD=false for stability
  3. Use GHCR images for frontend
  4. Enable Gzip compression via Traefik
  5. Monitor logs regularly
  6. Keep backups of uploads and database

See Also