version: '3.8' # ========================================== # CoopCredits Production Docker Compose # Server Infrastructure: 172.20.1.0/24 # ========================================== services: # ========================================== # PostgreSQL Database # ========================================== postgres: image: postgres:16-alpine container_name: coop-postgres environment: POSTGRES_USER: coop POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-coop_secure_password_change_me} POSTGRES_DB: coop_credits volumes: - postgres_data:/var/lib/postgresql/data - ./docker/postgres/init:/docker-entrypoint-initdb.d ports: - "127.0.0.1:5432:5432" # Only accessible locally healthcheck: test: ["CMD-SHELL", "pg_isready -U coop -d coop_credits"] interval: 10s timeout: 5s retries: 5 start_period: 30s networks: - coop-internal restart: unless-stopped logging: driver: "json-file" options: max-size: "10m" max-file: "3" # ========================================== # Redis Cache # ========================================== redis: image: redis:7-alpine container_name: coop-redis command: redis-server --requirepass ${REDIS_PASSWORD:-redis_secure_password} volumes: - redis_data:/data ports: - "127.0.0.1:6379:6379" # Only accessible locally healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 networks: - coop-internal restart: unless-stopped logging: driver: "json-file" options: max-size: "10m" max-file: "3" # ========================================== # Backend API Server # ========================================== backend: build: context: . dockerfile: ./backend/Dockerfile container_name: coop-backend environment: - NODE_ENV=production - DATABASE_URL=postgresql://coop:${POSTGRES_PASSWORD:-coop_secure_password}@postgres:5432/coop_credits?schema=public - REDIS_URL=redis://:${REDIS_PASSWORD:-redis_secure_password}@redis:6379 - PORT=3001 - JWT_SECRET=${JWT_SECRET} - API_URL=https://coop.hobokenchicken.com - FRONTEND_URL=https://coop.hobokenchicken.com # Plex - PLEX_CLIENT_ID=${PLEX_CLIENT_ID} - PLEX_CLIENT_SECRET=${PLEX_CLIENT_SECRET} - PLEX_REDIRECT_URI=${PLEX_REDIRECT_URI:-https://coop.hobokenchicken.com/auth/callback} # Tautulli (172.20.1.255:8181) - TAUTULLI_URL=http://172.20.1.255:8181 - TAUTULLI_API_KEY=${TAUTULLI_API_KEY} - TAUTULLI_WEBHOOK_SECRET=${TAUTULLI_WEBHOOK_SECRET} # Overseer (172.20.1.225:5055) - OVERSEER_URL=http://172.20.1.225:5055 - OVERSEER_API_KEY=${OVERSEER_API_KEY} # Solana - SOLANA_RPC_URL=${SOLANA_RPC_URL:-https://api.devnet.solana.com} - SOLANA_PROGRAM_ID=${SOLANA_PROGRAM_ID} - SOLANA_MINT_AUTHORITY_KEYPAIR=${SOLANA_MINT_AUTHORITY_KEYPAIR} - SOLANA_TOKEN_DECIMALS=6 # Security - ENCRYPTION_KEY=${ENCRYPTION_KEY} - TRUST_PROXY=true ports: - "127.0.0.1:3001:3001" # Only accessible via Nginx depends_on: postgres: condition: service_healthy redis: condition: service_healthy networks: - coop-internal # Allow access to local network for Tautulli/Overseer/Plex - coop-external restart: unless-stopped logging: driver: "json-file" options: max-size: "50m" max-file: "5" # Health check healthcheck: test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3001/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s # ========================================== # Frontend Next.js App # ========================================== frontend: build: context: . dockerfile: ./frontend/Dockerfile args: - NEXT_PUBLIC_API_URL=https://coop.hobokenchicken.com - NEXT_PUBLIC_SOLANA_NETWORK=devnet - NEXT_PUBLIC_SOLANA_RPC_URL=https://api.devnet.solana.com container_name: coop-frontend environment: - NODE_ENV=production - NEXT_PUBLIC_API_URL=https://coop.hobokenchicken.com - NEXT_PUBLIC_SOLANA_NETWORK=devnet - NEXT_PUBLIC_SOLANA_RPC_URL=https://api.devnet.solana.com ports: - "127.0.0.1:3000:3000" # Only accessible via Nginx depends_on: - backend networks: - coop-internal restart: unless-stopped logging: driver: "json-file" options: max-size: "50m" max-file: "5" # ========================================== # Nginx Reverse Proxy # ========================================== nginx: image: nginx:alpine container_name: coop-nginx ports: - "80:80" - "443:443" volumes: - ./docker/nginx/nginx.prod.conf:/etc/nginx/nginx.conf:ro - ./docker/nginx/ssl:/etc/nginx/ssl:ro - ./docker/nginx/logs:/var/log/nginx # Let's Encrypt certificates (if using certbot) - ./docker/nginx/letsencrypt:/etc/letsencrypt:ro - ./docker/nginx/www:/var/www/certbot:ro depends_on: - frontend - backend networks: - coop-internal restart: unless-stopped logging: driver: "json-file" options: max-size: "50m" max-file: "5" # ========================================== # Certbot (for Let's Encrypt SSL) # ========================================== certbot: image: certbot/certbot container_name: coop-certbot volumes: - ./docker/nginx/letsencrypt:/etc/letsencrypt - ./docker/nginx/www:/var/www/certbot entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'" networks: - coop-internal restart: unless-stopped # ========================================== # Volumes # ========================================== volumes: postgres_data: driver: local redis_data: driver: local # ========================================== # Networks # ========================================== networks: # Internal network for container communication coop-internal: driver: bridge internal: false # External network for accessing local services (172.20.1.0/24) coop-external: driver: bridge ipam: config: - subnet: 172.20.2.0/24 gateway: 172.20.2.1