version: '3.8' services: # PostgreSQL Database ydn-db: image: postgres:15-alpine container_name: YDN-Prod-DB environment: POSTGRES_DB: ${DB_NAME} POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C" volumes: - postgres_data:/var/lib/postgresql/data - ./backups:/backups networks: - ydn-internal restart: always healthcheck: test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"] interval: 10s timeout: 5s retries: 5 deploy: resources: limits: memory: 1G reservations: memory: 512M # Redis for sessions and caching ydn-redis: image: redis:7-alpine container_name: YDN-Prod-Redis command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD} --maxmemory 256mb --maxmemory-policy allkeys-lru volumes: - redis_data:/data networks: - ydn-internal restart: always healthcheck: test: ["CMD", "redis-cli", "--raw", "incr", "ping"] interval: 10s timeout: 3s retries: 5 deploy: resources: limits: memory: 256M reservations: memory: 128M # Dolibarr ERP/CRM ydn-dolibarr: image: tuxgasy/dolibarr:latest container_name: YDN-Prod-Dolibarr environment: DOLI_DB_HOST: ydn-db DOLI_DB_USER: ${DB_USER} DOLI_DB_PASSWORD: ${DB_PASSWORD} DOLI_DB_NAME: dolibarr_db DOLI_URL_ROOT: 'https://${DOMAIN}/dolibarr' PHP_INI_DATE_TIMEZONE: UTC volumes: - dolibarr_data:/var/www/documents - dolibarr_html:/var/www/html depends_on: ydn-db: condition: service_healthy networks: - ydn-internal restart: always deploy: resources: limits: memory: 512M reservations: memory: 256M # Main Application ydn-app: image: ${DOCKER_REGISTRY}/ydn-app:${VERSION} container_name: YDN-Prod-App environment: APP_ENV: production APP_PORT: 8080 APP_HOST: 0.0.0.0 DB_HOST: ydn-db DB_PORT: 5432 DB_USER: ${DB_USER} DB_PASSWORD: ${DB_PASSWORD} DB_NAME: ${DB_NAME} DB_SSLMODE: require REDIS_HOST: ydn-redis REDIS_PORT: 6379 REDIS_PASSWORD: ${REDIS_PASSWORD} REDIS_DB: 0 JWT_SECRET: ${JWT_SECRET} STRIPE_PUBLIC_KEY: ${STRIPE_PUBLIC_KEY} STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY} STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET} STRIPE_PRICE_ID: ${STRIPE_PRICE_ID} OVH_ENDPOINT: ${OVH_ENDPOINT} OVH_APPLICATION_KEY: ${OVH_APPLICATION_KEY} OVH_APPLICATION_SECRET: ${OVH_APPLICATION_SECRET} OVH_CONSUMER_KEY: ${OVH_CONSUMER_KEY} DOLIBARR_URL: https://${DOMAIN}/dolibarr DOLIBARR_API_TOKEN: ${DOLIBARR_API_TOKEN} SMTP_HOST: ${SMTP_HOST} SMTP_PORT: ${SMTP_PORT} SMTP_USER: ${SMTP_USER} SMTP_PASSWORD: ${SMTP_PASSWORD} SMTP_FROM: ${SMTP_FROM} LOG_LEVEL: info LOG_FORMAT: json CORS_ORIGINS: https://${DOMAIN} RATE_LIMIT_REQUESTS: 100 RATE_LIMIT_WINDOW: 1m volumes: - app_logs:/app/logs depends_on: ydn-db: condition: service_healthy ydn-redis: condition: service_healthy networks: - ydn-internal restart: always healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s deploy: replicas: 2 resources: limits: memory: 512M reservations: memory: 256M # Nginx Reverse Proxy with SSL ydn-nginx: image: nginx:alpine container_name: YDN-Prod-Nginx volumes: - ./configs/nginx.prod.conf:/etc/nginx/nginx.conf:ro - ./web/static:/usr/share/nginx/html/static:ro - ./ssl:/etc/nginx/ssl:ro - /var/log/nginx:/var/log/nginx ports: - "80:80" - "443:443" depends_on: - ydn-app - ydn-dolibarr networks: - ydn-internal - ydn-external restart: always deploy: resources: limits: memory: 256M reservations: memory: 128M # Database Backup Service ydn-backup: image: postgres:15-alpine container_name: YDN-Prod-Backup environment: PGPASSWORD: ${DB_PASSWORD} volumes: - ./backups:/backups - ./scripts/backup.sh:/backup.sh:ro command: sh -c "chmod +x /backup.sh && crond -f" depends_on: ydn-db: condition: service_healthy networks: - ydn-internal restart: always deploy: resources: limits: memory: 128M reservations: memory: 64M # Log Aggregation with Loki (Optional) ydn-loki: image: grafana/loki:latest container_name: YDN-Prod-Loki command: -config.file=/etc/loki/local-config.yaml volumes: - ./configs/loki.yml:/etc/loki/local-config.yaml:ro - loki_data:/loki ports: - "3100:3100" networks: - ydn-internal restart: always profiles: - logging # Monitoring with Prometheus ydn-prometheus: image: prom/prometheus:latest container_name: YDN-Prod-Prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--web.console.libraries=/etc/prometheus/console_libraries' - '--web.console.templates=/etc/prometheus/consoles' - '--storage.tsdb.retention.time=30d' - '--web.enable-lifecycle' volumes: - ./configs/prometheus.prod.yml:/etc/prometheus/prometheus.yml:ro - prometheus_data:/prometheus networks: - ydn-internal restart: always profiles: - monitoring deploy: resources: limits: memory: 1G reservations: memory: 512M # Grafana for monitoring ydn-grafana: image: grafana/grafana:latest container_name: YDN-Prod-Grafana environment: GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD} GF_USERS_ALLOW_SIGN_UP: false GF_SERVER_DOMAIN: ${DOMAIN} GF_SERVER_ROOT_URL: https://${DOMAIN}/grafana/ volumes: - grafana_data:/var/lib/grafana - ./configs/grafana/provisioning:/etc/grafana/provisioning:ro networks: - ydn-internal restart: always profiles: - monitoring deploy: resources: limits: memory: 512M reservations: memory: 256M volumes: postgres_data: driver: local redis_data: driver: local dolibarr_data: driver: local dolibarr_html: driver: local app_logs: driver: local prometheus_data: driver: local grafana_data: driver: local loki_data: driver: local networks: ydn-internal: driver: bridge internal: true ydn-external: driver: bridge