# Munich News Daily - Docker Compose Configuration # # GPU Support: # To enable GPU acceleration for Ollama (5-10x faster): # 1. Check GPU availability: ./check-gpu.sh # 2. Start with GPU: ./start-with-gpu.sh # Or manually: docker-compose -f docker-compose.yml -f docker-compose.gpu.yml up -d # # Security: # - Only Backend API (port 5001) is exposed to host # - MongoDB is internal-only (not exposed to host) # - Ollama is internal-only (not exposed to host) # - Crawler and Sender are internal-only # All services communicate via internal Docker network # # See docs/OLLAMA_SETUP.md for detailed setup instructions services: # Ollama AI Service (Internal only - not exposed to host) ollama: image: ollama/ollama:latest container_name: munich-news-ollama restart: unless-stopped # No ports exposed - only accessible within Docker network volumes: - ollama_data:/root/.ollama networks: - munich-news-network dns: - 8.8.8.8 - 1.1.1.1 # GPU support (uncomment if you have NVIDIA GPU) # deploy: # resources: # reservations: # devices: # - driver: nvidia # count: all # capabilities: [gpu] healthcheck: test: [ "CMD-SHELL", "ollama list || exit 1" ] interval: 30s timeout: 10s retries: 3 start_period: 30s # Ollama Model Loader - Pulls phi3:latest on startup ollama-setup: image: curlimages/curl:latest container_name: munich-news-ollama-setup depends_on: ollama: condition: service_healthy networks: - munich-news-network env_file: - backend/.env volumes: - ./scripts/setup-ollama-model.sh:/setup-ollama-model.sh:ro dns: - 8.8.8.8 - 1.1.1.1 command: sh /setup-ollama-model.sh restart: on-failure # Redis - Message queue for async tasks (Internal only - not exposed to host) redis: image: redis:7-alpine container_name: munich-news-redis restart: unless-stopped # No ports exposed - only accessible within Docker network networks: - munich-news-network healthcheck: test: [ "CMD", "redis-cli", "ping" ] interval: 30s timeout: 10s retries: 3 # MongoDB Database (Internal only - not exposed to host) mongodb: image: mongo:latest container_name: munich-news-mongodb restart: unless-stopped # No ports exposed - only accessible within Docker network environment: # For production, set MONGO_PASSWORD environment variable MONGO_INITDB_ROOT_USERNAME: ${MONGO_USERNAME:-admin} MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD:-changeme} MONGO_INITDB_DATABASE: munich_news volumes: - mongodb_data:/data/db - mongodb_config:/data/configdb networks: - munich-news-network command: mongod --bind_ip_all ${MONGO_AUTH:---auth} healthcheck: test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quiet interval: 30s timeout: 10s retries: 3 # ChromaDB - Vector Database for AI features chromadb: image: chromadb/chroma:latest container_name: munich-news-chromadb restart: unless-stopped # No ports exposed - only accessible within Docker network environment: - IS_PERSISTENT=TRUE volumes: - chromadb_data:/chroma/chroma networks: - munich-news-network healthcheck: test: [ "CMD", "curl", "-f", "http://localhost:8000/api/v1/heartbeat" ] interval: 30s timeout: 10s retries: 3 # News Crawler - Runs at 6 AM Berlin time crawler: build: context: . dockerfile: news_crawler/Dockerfile container_name: munich-news-crawler restart: unless-stopped depends_on: - mongodb - ollama - redis environment: - MONGODB_URI=mongodb://${MONGO_USERNAME:-admin}:${MONGO_PASSWORD:-changeme}@mongodb:27017/ - REDIS_URL=redis://redis:6379 - TZ=Europe/Berlin volumes: - ./backend/.env:/app/.env:ro networks: - munich-news-network healthcheck: test: [ "CMD", "python", "-c", "import sys; sys.exit(0)" ] interval: 1m timeout: 10s retries: 3 # Backend API - Tracking and analytics backend: build: context: ./backend dockerfile: Dockerfile container_name: munich-news-backend restart: unless-stopped depends_on: - mongodb - redis # ports: # - "5001:5001" environment: - MONGODB_URI=mongodb://${MONGO_USERNAME:-admin}:${MONGO_PASSWORD:-changeme}@mongodb:27017/ - REDIS_URL=redis://redis:6379 - FLASK_PORT=5001 - TZ=Europe/Berlin volumes: - ./backend/.env:/app/.env:ro - /var/run/docker.sock:/var/run/docker.sock:ro networks: - munich-news-network - proxy healthcheck: test: [ "CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:5001/health')" ] interval: 30s timeout: 10s retries: 3 start_period: 40s labels: - traefik.enable=true - traefik.docker.network=proxy - traefik.http.routers.news-api.entrypoints=http - traefik.http.routers.news-api.rule=Host(`news-api.dongho.kim`) - traefik.http.middlewares.news-api-redirect.redirectscheme.permanent=true - traefik.http.middlewares.news-api-redirect.redirectscheme.scheme=https - traefik.http.routers.news-api.middlewares=news-api-redirect - traefik.http.routers.news-api-secure.entrypoints=https - traefik.http.routers.news-api-secure.rule=Host(`news-api.dongho.kim`) - traefik.http.routers.news-api-secure.tls=true - traefik.http.routers.news-api-secure.tls.certresolver=cloudflare - traefik.http.services.news-api-secure-service.loadbalancer.server.port=5001 # Transport Crawler - API service for MVG disruptions (Internal only - not exposed to host) transport-crawler: build: context: ./transport_crawler dockerfile: Dockerfile container_name: munich-news-transport-crawler restart: unless-stopped depends_on: - mongodb - redis # No ports exposed - only accessible within Docker network environment: - MONGODB_URI=mongodb://${MONGO_USERNAME:-admin}:${MONGO_PASSWORD:-changeme}@mongodb:27017/ - REDIS_URL=redis://redis:6379 - TZ=Europe/Berlin volumes: - ./backend/.env:/app/.env:ro networks: - munich-news-network healthcheck: test: [ "CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:5002/health')" ] interval: 30s timeout: 10s retries: 3 start_period: 40s # Newsletter Sender - Runs at 7 AM Berlin time sender: build: context: . dockerfile: news_sender/Dockerfile container_name: munich-news-sender restart: unless-stopped depends_on: - mongodb - backend - crawler - transport-crawler environment: - MONGODB_URI=mongodb://${MONGO_USERNAME:-admin}:${MONGO_PASSWORD:-changeme}@mongodb:27017/ - TZ=Europe/Berlin volumes: - ./backend/.env:/app/.env:ro networks: - munich-news-network healthcheck: test: [ "CMD", "python", "-c", "import sys; sys.exit(0)" ] interval: 1m timeout: 10s retries: 3 # Frontend Web Interface frontend: build: ./frontend container_name: munich-news-frontend restart: unless-stopped # ports: # - "3000:3000" # Traefik Configuration (commented out - uncomment when using Traefik) # Remove port exposure when using Traefik # ports: # - "3000:3000" environment: - API_URL=http://backend:5001 - PORT=3000 depends_on: - backend networks: - munich-news-network - proxy healthcheck: test: [ "CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000" ] interval: 30s timeout: 10s retries: 3 labels: - traefik.enable=true - traefik.docker.network=proxy - traefik.http.routers.news.entrypoints=http - traefik.http.routers.news.rule=Host(`news.dongho.kim`) - traefik.http.middlewares.news-redirect.redirectscheme.permanent=true - traefik.http.middlewares.news-redirect.redirectscheme.scheme=https - traefik.http.routers.news.middlewares=news-redirect - traefik.http.routers.news-secure.entrypoints=https - traefik.http.routers.news-secure.rule=Host(`news.dongho.kim`) - traefik.http.routers.news-secure.tls=true - traefik.http.routers.news-secure.tls.certresolver=cloudflare - traefik.http.services.news-secure-service.loadbalancer.server.port=3000 volumes: mongodb_data: driver: local mongodb_config: driver: local ollama_data: driver: local chromadb_data: driver: local networks: munich-news-network: internal: false proxy: external: true