# ============================================== # Docker Compose PROD (порты не пересекаются с dev на одном хосте) # ============================================== # Порты на хосте (prod): db 5434, redis 6381, web 8123, nginx 8084, # front_material 3010, yjs 1236, excalidraw 3004, whiteboard 8083, # livekit 7880/7881, celery/beat — без портов (внутренние) # Dev использует: 5433, 6380, 8124, 8081, 3002, 1235, 3003, 8082, livekit 7890/7891 # # ВАЖНО: PROD использует отдельную сеть (prod_network) и именованные volumes # НЕ используйте: docker compose down --volumes (удалит данные БД!) # Используйте: docker compose down (остановит контейнеры, сохранит volumes) # Для полной очистки: сначала сделайте бэкап БД, затем docker compose down --volumes services: db: image: postgres:16-alpine container_name: platform_prod_db restart: unless-stopped environment: POSTGRES_DB: platform_prod_db POSTGRES_USER: platform_prod_user POSTGRES_PASSWORD: platform_prod_password ports: - "5434:5432" volumes: - prod_postgres_data:/var/lib/postgresql/data networks: - prod_network redis: image: redis:7-alpine container_name: platform_prod_redis restart: unless-stopped ports: - "6381:6379" volumes: - prod_redis_data:/data networks: - prod_network web: build: context: ./backend dockerfile: Dockerfile container_name: platform_prod_web restart: unless-stopped user: "0:0" env_file: .env # Daphne (ASGI): HTTP + WebSocket (/ws/notifications/, /ws/chat/, /ws/board/ и т.д.) command: sh -c "python manage.py migrate && python manage.py init_subjects && daphne -b 0.0.0.0 -p 8000 config.asgi:application" environment: - DEBUG=${DEBUG:-False} - SECRET_KEY=${SECRET_KEY} - ALLOWED_HOSTS=${ALLOWED_HOSTS} - CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS} - CSRF_TRUSTED_ORIGINS=${CSRF_TRUSTED_ORIGINS} - DATABASE_URL=postgresql://platform_prod_user:platform_prod_password@platform_prod_db:5432/platform_prod_db - REDIS_URL=redis://platform_prod_redis:6379/0 - CELERY_BROKER_URL=redis://platform_prod_redis:6379/1 - CELERY_RESULT_BACKEND=redis://platform_prod_redis:6379/2 # Явно передаём переменные почты из .env (иначе контейнер может не видеть их) - EMAIL_BACKEND=${EMAIL_BACKEND:-smtp} - EMAIL_HOST=${EMAIL_HOST} - EMAIL_PORT=${EMAIL_PORT:-2525} - EMAIL_USE_TLS=${EMAIL_USE_TLS:-True} - EMAIL_USE_SSL=${EMAIL_USE_SSL:-False} - EMAIL_HOST_USER=${EMAIL_HOST_USER} - EMAIL_HOST_PASSWORD=${EMAIL_HOST_PASSWORD} - DEFAULT_FROM_EMAIL=${DEFAULT_FROM_EMAIL} - EMAIL_TIMEOUT=${EMAIL_TIMEOUT:-10} # Ссылки в письмах (сброс пароля, подтверждение, приглашения) — без localhost - FRONTEND_URL=${FRONTEND_URL:-https://app.uchill.online} # LiveKit: публичный URL для браузера (обязательно в prod — иначе клиент идёт на 127.0.0.1) - LIVEKIT_PUBLIC_URL=${LIVEKIT_PUBLIC_URL:-wss://api.uchill.online/livekit} # Telegram бот (профиль: bot-info, привязка аккаунта) - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN} - TELEGRAM_USE_WEBHOOK=${TELEGRAM_USE_WEBHOOK:-False} - TELEGRAM_WEBHOOK_URL=${TELEGRAM_WEBHOOK_URL:-} - TELEGRAM_WEBHOOK_SECRET_TOKEN=${TELEGRAM_WEBHOOK_SECRET_TOKEN:-} ports: - "8123:8000" volumes: - ./backend:/app depends_on: - db - redis networks: - prod_network celery: build: context: ./backend dockerfile: Dockerfile container_name: platform_prod_celery restart: unless-stopped user: "0:0" env_file: .env command: celery -A config worker -l info environment: - DEBUG=${DEBUG:-False} - DATABASE_URL=postgresql://platform_prod_user:platform_prod_password@platform_prod_db:5432/platform_prod_db - REDIS_URL=redis://platform_prod_redis:6379/0 - CELERY_BROKER_URL=redis://platform_prod_redis:6379/1 - CELERY_RESULT_BACKEND=redis://platform_prod_redis:6379/2 - EMAIL_BACKEND=${EMAIL_BACKEND:-smtp} - EMAIL_HOST=${EMAIL_HOST} - EMAIL_PORT=${EMAIL_PORT:-2525} - EMAIL_USE_TLS=${EMAIL_USE_TLS:-True} - EMAIL_USE_SSL=${EMAIL_USE_SSL:-False} - EMAIL_HOST_USER=${EMAIL_HOST_USER} - EMAIL_HOST_PASSWORD=${EMAIL_HOST_PASSWORD} - DEFAULT_FROM_EMAIL=${DEFAULT_FROM_EMAIL} - EMAIL_TIMEOUT=${EMAIL_TIMEOUT:-10} - FRONTEND_URL=${FRONTEND_URL:-https://app.uchill.online} - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN} - TELEGRAM_USE_WEBHOOK=${TELEGRAM_USE_WEBHOOK:-False} - TELEGRAM_WEBHOOK_URL=${TELEGRAM_WEBHOOK_URL:-} - TELEGRAM_WEBHOOK_SECRET_TOKEN=${TELEGRAM_WEBHOOK_SECRET_TOKEN:-} volumes: - ./backend:/app depends_on: - db - redis - web networks: - prod_network celery-beat: build: context: ./backend dockerfile: Dockerfile container_name: platform_prod_celery_beat restart: unless-stopped user: "0:0" env_file: .env command: celery -A config beat -l info environment: - DEBUG=${DEBUG:-False} - DATABASE_URL=postgresql://platform_prod_user:platform_prod_password@platform_prod_db:5432/platform_prod_db - REDIS_URL=redis://platform_prod_redis:6379/0 - CELERY_BROKER_URL=redis://platform_prod_redis:6379/1 - CELERY_RESULT_BACKEND=redis://platform_prod_redis:6379/2 - EMAIL_BACKEND=${EMAIL_BACKEND:-smtp} - EMAIL_HOST=${EMAIL_HOST} - EMAIL_PORT=${EMAIL_PORT:-2525} - EMAIL_USE_TLS=${EMAIL_USE_TLS:-True} - EMAIL_USE_SSL=${EMAIL_USE_SSL:-False} - EMAIL_HOST_USER=${EMAIL_HOST_USER} - EMAIL_HOST_PASSWORD=${EMAIL_HOST_PASSWORD} - DEFAULT_FROM_EMAIL=${DEFAULT_FROM_EMAIL} - EMAIL_TIMEOUT=${EMAIL_TIMEOUT:-10} - FRONTEND_URL=${FRONTEND_URL:-https://app.uchill.online} - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN} - TELEGRAM_USE_WEBHOOK=${TELEGRAM_USE_WEBHOOK:-False} - TELEGRAM_WEBHOOK_URL=${TELEGRAM_WEBHOOK_URL:-} - TELEGRAM_WEBHOOK_SECRET_TOKEN=${TELEGRAM_WEBHOOK_SECRET_TOKEN:-} volumes: - ./backend:/app depends_on: - db - redis - web networks: - prod_network # Telegram бот (polling): получает /start, /link <код> и т.д. Если используете webhook — не поднимайте этот сервис. telegram-bot: build: context: ./backend dockerfile: Dockerfile container_name: platform_prod_telegram_bot restart: unless-stopped user: "0:0" env_file: .env command: python manage.py runtelegrambot environment: - DEBUG=${DEBUG:-False} - DATABASE_URL=postgresql://platform_prod_user:platform_prod_password@platform_prod_db:5432/platform_prod_db - REDIS_URL=redis://platform_prod_redis:6379/0 - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN} - TELEGRAM_USE_WEBHOOK=${TELEGRAM_USE_WEBHOOK:-False} - TELEGRAM_WEBHOOK_URL=${TELEGRAM_WEBHOOK_URL:-} - TELEGRAM_WEBHOOK_SECRET_TOKEN=${TELEGRAM_WEBHOOK_SECRET_TOKEN:-} volumes: - ./backend:/app depends_on: - db - redis - web networks: - prod_network # Видеоуроки: хост nginx (api.uchill.online) проксирует /livekit на 7880. Dev на том же хосте — 7890. # LIVEKIT_KEYS — строго один ключ в формате "key: secret" (пробел после двоеточия). В .env задайте одну строку: LIVEKIT_KEYS=APIKeyPlatform2024Secret: ThisIsAVerySecureSecretKeyForPlatform2024VideoConf livekit: image: livekit/livekit-server:latest container_name: platform_prod_livekit restart: unless-stopped environment: # Одна строка "key: secret" (пробел после двоеточия). В кавычках, чтобы YAML не воспринял двоеточие как ключ. - "LIVEKIT_KEYS=APIKeyPlatform2024Secret: ThisIsAVerySecureSecretKeyForPlatform2024VideoConf" ports: - "7880:7880" - "7881:7881" networks: - prod_network nginx: image: nginx:alpine container_name: platform_prod_nginx restart: unless-stopped ports: - "8084:80" volumes: - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./docker/nginx/conf.d:/etc/nginx/conf.d:ro depends_on: - web networks: - prod_network front_material: build: context: ./front_material dockerfile: Dockerfile target: production args: - NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL} - NEXT_PUBLIC_WS_URL=${NEXT_PUBLIC_WS_URL} - NEXT_PUBLIC_LIVEKIT_URL=${NEXT_PUBLIC_LIVEKIT_URL} - NEXT_PUBLIC_EXCALIDRAW_URL=${NEXT_PUBLIC_EXCALIDRAW_URL:-} container_name: platform_prod_front_material restart: unless-stopped env_file: .env environment: - NODE_ENV=production - HOSTNAME=0.0.0.0 # Доска: поддомен board.uchill.online (прокси nginx на 3004) или путь на том же домене - NEXT_PUBLIC_EXCALIDRAW_URL=${NEXT_PUBLIC_EXCALIDRAW_URL:-} - NEXT_PUBLIC_EXCALIDRAW_PATH=${NEXT_PUBLIC_EXCALIDRAW_PATH:-/excalidraw} ports: - "3010:3000" networks: - prod_network yjs-whiteboard: build: context: ./yjs-whiteboard-server dockerfile: Dockerfile container_name: platform_prod_yjs_whiteboard restart: unless-stopped ports: - "1236:1234" networks: - prod_network excalidraw: build: context: ./excalidraw-server dockerfile: Dockerfile target: production container_name: platform_prod_excalidraw restart: unless-stopped environment: - NODE_ENV=production # Поддомен board.uchill.online: basePath не нужен (приложение на корне поддомена) - NEXT_PUBLIC_BASE_PATH= ports: - "3004:3001" networks: - prod_network whiteboard: build: context: ./whiteboard-server dockerfile: Dockerfile container_name: platform_prod_whiteboard restart: unless-stopped ports: - "8083:8080" networks: - prod_network volumes: # ВАЖНО: Эти volumes содержат данные БД и Redis # НЕ используйте docker compose down --volumes без бэкапа! prod_postgres_data: name: platform_prod_postgres_data prod_redis_data: name: platform_prod_redis_data front_material_node_modules: name: platform_prod_front_material_node_modules front_material_next: name: platform_prod_front_material_next networks: prod_network: name: platform_prod_network driver: bridge