version: '3.8' # ============================================================================= # DATABASE SERVICES: Production-ready database stack for Lilith Platform # ============================================================================= # # Host: apricot (10.9.0.1 on VPN) # Purpose: Centralized database services for all environments # Data Location: /mnt/bigdisk/_/lilith-platform/databases/ # # Usage: # docker-compose -f docker-compose.databases.yml --env-file .env.databases up -d # # Architecture: # - PostgreSQL 16 + TimescaleDB: Primary data store with time-series optimization # - Redis 7: Caching layer, sessions, rate limiting, job queues # - Meilisearch: Full-text search engine for content discovery # # Network: # - All services bind to 0.0.0.0 (accessible via VPN) # - VPN subnet: 10.9.0.0/24 # - Apricot: 10.9.0.1, VPS: 10.9.0.2 # # ============================================================================= services: # ============================================================================= # PRIMARY DATABASE: PostgreSQL 16 with TimescaleDB Extension # ============================================================================= # TimescaleDB provides time-series optimizations for analytics, metrics, logs # All existing PostgreSQL functionality remains unchanged postgres: image: timescale/timescaledb:2.16.1-pg16 container_name: lilith-postgres-production restart: unless-stopped network_mode: host environment: # Database credentials POSTGRES_USER: ${POSTGRES_USER:-postgres} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB:-lilith_platform} # Performance tuning - generous settings for dedicated database server # shared_buffers: 25% of RAM (assuming 32GB+ available) POSTGRES_SHARED_BUFFERS: ${POSTGRES_SHARED_BUFFERS:-8GB} # work_mem: Per-operation memory for sorting/hashing POSTGRES_WORK_MEM: ${POSTGRES_WORK_MEM:-256MB} # effective_cache_size: Hint for query planner (50-75% of RAM) POSTGRES_EFFECTIVE_CACHE_SIZE: ${POSTGRES_EFFECTIVE_CACHE_SIZE:-24GB} # maintenance_work_mem: Memory for VACUUM, CREATE INDEX POSTGRES_MAINTENANCE_WORK_MEM: ${POSTGRES_MAINTENANCE_WORK_MEM:-2GB} # Connection pool settings POSTGRES_MAX_CONNECTIONS: ${POSTGRES_MAX_CONNECTIONS:-200} # WAL settings for performance POSTGRES_WAL_BUFFERS: ${POSTGRES_WAL_BUFFERS:-16MB} POSTGRES_CHECKPOINT_COMPLETION_TARGET: ${POSTGRES_CHECKPOINT_COMPLETION_TARGET:-0.9} # Enable SSL for VPN connections POSTGRES_HOST_AUTH_METHOD: ${POSTGRES_HOST_AUTH_METHOD:-scram-sha-256} volumes: # Data persistence on /mnt/bigdisk - ${POSTGRES_DATA_DIR:-/mnt/bigdisk/_/lilith-platform/databases/postgresql}:/var/lib/postgresql/data # Custom PostgreSQL configuration - ./postgresql/postgresql.conf:/etc/postgresql/postgresql.conf:ro - ./postgresql/pg_hba.conf:/etc/postgresql/pg_hba.conf:ro # SSL certificates for VPN connections - ${POSTGRES_SSL_CERT:-./postgresql/ssl/server.crt}:/var/lib/postgresql/server.crt:ro - ${POSTGRES_SSL_KEY:-./postgresql/ssl/server.key}:/var/lib/postgresql/server.key:ro # Initialization scripts - ./postgresql/init.d:/docker-entrypoint-initdb.d:ro command: - postgres - -c - config_file=/etc/postgresql/postgresql.conf - -c - hba_file=/etc/postgresql/pg_hba.conf - -c - listen_addresses=0.0.0.0 - -c - port=5432 - -c - shared_buffers=${POSTGRES_SHARED_BUFFERS:-8GB} - -c - effective_cache_size=${POSTGRES_EFFECTIVE_CACHE_SIZE:-24GB} - -c - maintenance_work_mem=${POSTGRES_MAINTENANCE_WORK_MEM:-2GB} - -c - work_mem=${POSTGRES_WORK_MEM:-256MB} - -c - max_connections=${POSTGRES_MAX_CONNECTIONS:-200} - -c - wal_buffers=${POSTGRES_WAL_BUFFERS:-16MB} - -c - checkpoint_completion_target=${POSTGRES_CHECKPOINT_COMPLETION_TARGET:-0.9} - -c - random_page_cost=1.1 - -c - effective_io_concurrency=200 - -c - max_worker_processes=4 - -c - max_parallel_workers_per_gather=2 - -c - max_parallel_workers=4 - -c - log_timezone=UTC - -c - timezone=UTC healthcheck: test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-lilith_platform}'] interval: 10s timeout: 5s retries: 5 start_period: 30s logging: driver: "json-file" options: max-size: "100m" max-file: "10" labels: "service=postgres,env=production" # ============================================================================= # CACHE & QUEUES: Redis 7 # ============================================================================= # Used for: Sessions, caching, rate limiting, BullMQ job queues, pub/sub # Configured for generous memory usage as primary caching layer redis: image: redis:7.4-alpine container_name: lilith-redis-production restart: unless-stopped network_mode: host environment: # Redis configuration via environment REDIS_PASSWORD: ${REDIS_PASSWORD} volumes: # Data persistence with AOF (Append-Only File) - ${REDIS_DATA_DIR:-/mnt/bigdisk/_/lilith-platform/databases/redis}:/data # Custom Redis configuration - ./redis/redis.conf:/usr/local/etc/redis/redis.conf:ro command: - redis-server - /usr/local/etc/redis/redis.conf - --port - "6379" - --bind - "0.0.0.0" - --requirepass - "${REDIS_PASSWORD}" # Persistence: AOF enabled for durability - --appendonly - "yes" - --appendfsync - "everysec" # Memory management - --maxmemory - "${REDIS_MAX_MEMORY:-4GB}" - --maxmemory-policy - "allkeys-lru" # Performance tuning - --tcp-backlog - "511" - --timeout - "300" - --tcp-keepalive - "300" # Disable RDB snapshots (AOF is sufficient) - --save - "" # Logging - --loglevel - "${REDIS_LOG_LEVEL:-notice}" healthcheck: test: ['CMD', 'redis-cli', '--raw', 'incr', 'ping'] interval: 10s timeout: 3s retries: 5 start_period: 10s logging: driver: "json-file" options: max-size: "50m" max-file: "5" labels: "service=redis,env=production" # ============================================================================= # SEARCH: Meilisearch # ============================================================================= # Full-text search engine for profile discovery, content search # Features: Typo tolerance, faceted filtering, geo search, sub-50ms responses meilisearch: image: getmeili/meilisearch:v1.12 container_name: lilith-meilisearch-production restart: unless-stopped network_mode: host environment: # Master key for API authentication MEILI_MASTER_KEY: ${MEILI_MASTER_KEY} # Environment (production/development) MEILI_ENV: ${MEILI_ENV:-production} # HTTP address binding MEILI_HTTP_ADDR: ${MEILI_HTTP_ADDR:-0.0.0.0:7700} # Database path MEILI_DB_PATH: /meili_data # Disable telemetry MEILI_NO_ANALYTICS: ${MEILI_NO_ANALYTICS:-true} # Performance settings MEILI_MAX_INDEXING_MEMORY: ${MEILI_MAX_INDEXING_MEMORY:-2GB} MEILI_MAX_INDEXING_THREADS: ${MEILI_MAX_INDEXING_THREADS:-2} # Logging MEILI_LOG_LEVEL: ${MEILI_LOG_LEVEL:-INFO} volumes: # Data persistence - ${MEILI_DATA_DIR:-/mnt/bigdisk/_/lilith-platform/databases/meilisearch}:/meili_data # Snapshots directory (for backups) - ${MEILI_SNAPSHOT_DIR:-/mnt/bigdisk/_/lilith-platform/databases/meilisearch-snapshots}:/snapshots healthcheck: test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:7700/health'] interval: 10s timeout: 5s retries: 5 start_period: 20s logging: driver: "json-file" options: max-size: "50m" max-file: "5" labels: "service=meilisearch,env=production" # ============================================================================= # NOTES # ============================================================================= # # 1. Network Configuration: # - Using host network mode for maximum performance and VPN accessibility # - All services bind to 0.0.0.0 (accessible from VPN: 10.9.0.0/24) # - No port mapping needed (services use standard ports directly) # # 2. Data Persistence: # - All data stored on /mnt/bigdisk for large capacity # - Volumes are bind mounts (not Docker volumes) for direct access # - Backup strategy should target these directories # # 3. Security: # - PostgreSQL: SSL-enabled, scram-sha-256 authentication # - Redis: Password-protected (set REDIS_PASSWORD in .env.databases) # - Meilisearch: Master key authentication (set MEILI_MASTER_KEY) # - VPN-only access (no public internet exposure) # # 4. Performance: # - PostgreSQL: Tuned for 32GB+ RAM server # - Redis: 4GB max memory with LRU eviction # - Meilisearch: 2GB indexing memory limit # # 5. Monitoring: # - Health checks enabled for all services # - Logs limited to prevent disk fill (100MB/50MB max per service) # - Use `docker-compose logs -f ` to monitor # # 6. Backup Strategy: # - PostgreSQL: pg_dump + WAL archiving (configure separately) # - Redis: AOF persistence (automatic) # - Meilisearch: Snapshots stored in separate directory # # =============================================================================