services: # Redis cache service redis: image: redis:7-alpine container_name: privydrop-redis restart: unless-stopped command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru volumes: - redis_data:/data networks: - privydrop-network healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 3s retries: 3 start_period: 5s # Backend signaling service backend: build: context: ./backend dockerfile: Dockerfile args: - HTTP_PROXY=${HTTP_PROXY} - HTTPS_PROXY=${HTTPS_PROXY} - NO_PROXY=${NO_PROXY} container_name: privydrop-backend restart: unless-stopped environment: - NODE_ENV=production - BACKEND_PORT=3001 - REDIS_HOST=redis - REDIS_PORT=6379 - CORS_ORIGIN=${CORS_ORIGIN:-http://localhost} ports: - "${BACKEND_PORT:-3001}:3001" depends_on: redis: condition: service_healthy networks: - privydrop-network volumes: - ./logs:/app/logs healthcheck: test: ["CMD", "node", "health-check.js"] interval: 30s timeout: 10s retries: 3 start_period: 40s # Frontend app frontend: build: context: ./frontend dockerfile: Dockerfile args: - HTTP_PROXY=${HTTP_PROXY} - HTTPS_PROXY=${HTTPS_PROXY} - NO_PROXY=${NO_PROXY} - NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL} - NEXT_PUBLIC_TURN_HOST=${NEXT_PUBLIC_TURN_HOST} - NEXT_PUBLIC_TURN_USERNAME=${NEXT_PUBLIC_TURN_USERNAME} - NEXT_PUBLIC_TURN_PASSWORD=${NEXT_PUBLIC_TURN_PASSWORD} - NEXT_IMAGE_UNOPTIMIZED=${NEXT_IMAGE_UNOPTIMIZED:-true} container_name: privydrop-frontend restart: unless-stopped environment: - NODE_ENV=production - NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL:-http://localhost:3001} - BACKEND_INTERNAL_URL=${BACKEND_INTERNAL_URL:-http://backend:3001} - NEXT_IMAGE_UNOPTIMIZED=${NEXT_IMAGE_UNOPTIMIZED:-true} - PORT=3002 - HOSTNAME=0.0.0.0 - NODE_EXTRA_CA_CERTS=/opt/privydrop/ssl/ca-cert.pem ports: - "${FRONTEND_PORT:-3002}:3002" depends_on: backend: condition: service_healthy networks: - privydrop-network volumes: - ./docker/ssl:/opt/privydrop/ssl:ro healthcheck: test: ["CMD", "node", "health-check.js"] interval: 30s timeout: 10s retries: 3 start_period: 120s # Nginx reverse proxy nginx: image: nginx:alpine container_name: privydrop-nginx restart: unless-stopped ports: - "${HTTP_PORT:-80}:80" - "${HTTPS_PORT:-443}:${DOCKER_HTTPS_CONTAINER_PORT:-443}" volumes: - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./docker/nginx/conf.d:/etc/nginx/conf.d:ro - ./docker/letsencrypt-www:/var/www/certbot:ro - ./docker/ssl:/etc/nginx/ssl:ro - ./logs/nginx:/var/log/nginx depends_on: - frontend - backend networks: - privydrop-network profiles: - nginx # TURN/STUN server (optional, for NAT traversal) coturn: image: coturn/coturn:4.6.2 container_name: privydrop-coturn restart: unless-stopped ports: - "3478:3478/tcp" - "3478:3478/udp" - "5349:5349/tcp" - "5349:5349/udp" - "${TURN_MIN_PORT:-49152}-${TURN_MAX_PORT:-49252}:${TURN_MIN_PORT:-49152}-${TURN_MAX_PORT:-49252}/udp" volumes: - ./docker/coturn/turnserver.conf:/etc/coturn/turnserver.conf:ro - ./docker/ssl:/etc/ssl/certs:ro - ./logs/coturn:/var/log networks: - privydrop-network profiles: - turn command: ["-c", "/etc/coturn/turnserver.conf"] networks: privydrop-network: driver: bridge ipam: config: - subnet: 172.20.0.0/16 volumes: redis_data: driver: local