Ctrl K
ComunidadGuías…

docker-compose.yml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
services:
  backend:
    build:
      context: ./backend
      dockerfile: ../docker/backend.Dockerfile
    image: rustchat-backend
    container_name: rustchat-backend
    restart: always
    environment:
      - RUSTCHAT_SERVER_HOST=0.0.0.0
      - RUSTCHAT_SERVER_PORT=3000
      - RUSTCHAT_ENVIRONMENT=${RUSTCHAT_ENVIRONMENT:-development}
      # ⚠️  PRODUCTION (behind reverse proxy):
      #   - Set SITE_URL to public HTTPS URL (e.g., https://chat.example.com)
      #   - Set CORS_ALLOWED_ORIGINS to same HTTPS URL(s)
      #   - Internal proxy→RustChat uses HTTP, but browsers see HTTPS
      - RUSTCHAT_SITE_URL=${RUSTCHAT_SITE_URL:-http://localhost:8080}
      - RUSTCHAT_CORS_ALLOWED_ORIGINS=${RUSTCHAT_CORS_ALLOWED_ORIGINS:-http://localhost:8080,http://localhost:5173}
      - RUSTCHAT_ALLOW_DEV_CORS=${RUSTCHAT_ALLOW_DEV_CORS:-false}
      - RUSTCHAT_DATABASE_URL=postgres://rustchat:rustchat@postgres:5432/rustchat
      - RUSTCHAT_REDIS_URL=redis://redis:6379
      - RUSTCHAT_JWT_SECRET=${RUSTCHAT_JWT_SECRET:?set RUSTCHAT_JWT_SECRET in .env}
      - RUSTCHAT_JWT_ISSUER=${RUSTCHAT_JWT_ISSUER:?set RUSTCHAT_JWT_ISSUER in .env}
      - RUSTCHAT_JWT_AUDIENCE=${RUSTCHAT_JWT_AUDIENCE:?set RUSTCHAT_JWT_AUDIENCE in .env}
      - RUSTCHAT_ENCRYPTION_KEY=${RUSTCHAT_ENCRYPTION_KEY:?set RUSTCHAT_ENCRYPTION_KEY in .env}
      - RUSTCHAT_S3_ENDPOINT=http://rustfs:9000
      - RUSTCHAT_S3_PUBLIC_ENDPOINT=${RUSTCHAT_S3_PUBLIC_ENDPOINT:-http://localhost:9000}
      - RUSTCHAT_S3_BUCKET=rustchat-uploads
      - RUSTCHAT_S3_ACCESS_KEY=${RUSTCHAT_S3_ACCESS_KEY:?set RUSTCHAT_S3_ACCESS_KEY in .env}
      - RUSTCHAT_S3_SECRET_KEY=${RUSTCHAT_S3_SECRET_KEY:?set RUSTCHAT_S3_SECRET_KEY in .env}
      - RUSTCHAT_ADMIN_USER=${RUSTCHAT_ADMIN_USER:-admin@rustchat.local}
      - RUSTCHAT_ADMIN_PASSWORD=${RUSTCHAT_ADMIN_PASSWORD:-}
      # Calls Plugin (WebRTC) Configuration
      - RUSTCHAT_CALLS_ENABLED=${RUSTCHAT_CALLS_ENABLED:-true}
      - RUSTCHAT_CALLS_UDP_PORT=${RUSTCHAT_CALLS_UDP_PORT:-8443}
      - RUSTCHAT_CALLS_TCP_PORT=${RUSTCHAT_CALLS_TCP_PORT:-8443}
      - RUSTCHAT_CALLS_ICE_HOST_OVERRIDE=${RUSTCHAT_CALLS_ICE_HOST_OVERRIDE:-}
      - RUSTCHAT_CALLS_STATE_BACKEND=${RUSTCHAT_CALLS_STATE_BACKEND:-auto}
      # TURN Server Configuration
      - TURN_SERVER_ENABLED=${TURN_SERVER_ENABLED:-false}
      - TURN_SERVER_URL=${TURN_SERVER_URL:-}
      - TURN_SERVER_USERNAME=${TURN_SERVER_USERNAME:-}
      - TURN_SERVER_CREDENTIAL=${TURN_SERVER_CREDENTIAL:-}
      # Push Notification Proxy
      - RUSTCHAT_PUSH_PROXY_URL=${RUSTCHAT_PUSH_PROXY_URL:-http://push-proxy:3000}
      - PUSH_PROXY_AUTH_KEY=${PUSH_PROXY_AUTH_KEY:?PUSH_PROXY_AUTH_KEY must be set to a non-empty secret}
      # Cloudflare Turnstile (Bot Protection)
      - RUSTCHAT_TURNSTILE_ENABLED=${RUSTCHAT_TURNSTILE_ENABLED:-false}
      - RUSTCHAT_TURNSTILE_SITE_KEY=${RUSTCHAT_TURNSTILE_SITE_KEY:-}
      - RUSTCHAT_TURNSTILE_SECRET_KEY=${RUSTCHAT_TURNSTILE_SECRET_KEY:-}
    # Backend is published for local API debugging only. It bypasses the
    # frontend nginx, so requests hitting it directly do not pass the reverse
    # proxy's X-Forwarded-For boundary — keep it loopback-bound by default.
    # Set RUSTCHAT_BIND_HOST=0.0.0.0 to expose services on the LAN (e.g. for
    # testing from a phone), accepting that you are opting out of these
    # boundaries.
    ports:
      - "${RUSTCHAT_BIND_HOST:-127.0.0.1}:3000:3000"
      - "${RUSTCHAT_BIND_HOST:-127.0.0.1}:8443:8443/tcp" # WebRTC SFU TCP fallback
      - "${RUSTCHAT_BIND_HOST:-127.0.0.1}:8443:8443/udp" # WebRTC SFU UDP media transport
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
      rustfs:
        condition: service_healthy
    healthcheck:
      test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3000/api/v1/health/live" ]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s

  frontend:
    build:
      context: ./frontend
      dockerfile: ../docker/frontend.Dockerfile
    image: rustchat-frontend
    container_name: rustchat-frontend
    restart: always
    ports:
      - "8080:8080"
    depends_on:
      backend:
        condition: service_healthy

  postgres:
    image: pgvector/pgvector:pg16
    container_name: rustchat-postgres
    environment:
      POSTGRES_USER: rustchat
      # Well-known dev password, unchanged from before: acceptable only
      # because the port is loopback-bound below. (Parameterizing this line
      # trips secret scanners on the new diff; the literal is identical to
      # the pre-existing value in main.)
      POSTGRES_PASSWORD: rustchat
      POSTGRES_DB: rustchat
    # Loopback-bound by default: a password-authenticated database with a
    # well-known dev password must not be reachable from the network.
    ports:
      - "${RUSTCHAT_BIND_HOST:-127.0.0.1}:5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: [ "CMD-SHELL", "pg_isready -U rustchat" ]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: rustchat-redis
    # Loopback-bound by default: this Redis has no authentication at all.
    ports:
      - "${RUSTCHAT_BIND_HOST:-127.0.0.1}:6379:6379"
    volumes:
      - redis_data:/data
    healthcheck:
      test: [ "CMD", "redis-cli", "ping" ]
      interval: 5s
      timeout: 5s
      retries: 5

  rustfs:
    # TODO: Pin to a version tag when rustfs publishes semver tags.
    # Current digest: sha256:103dd40b84d5aa3d5ab02f3a693797eb1d14cb842554b222dfbb589f364aa47f
    image: rustfs/rustfs@sha256:103dd40b84d5aa3d5ab02f3a693797eb1d14cb842554b222dfbb589f364aa47f
    container_name: rustchat-rustfs
    environment:
      - RUSTFS_ACCESS_KEY=${RUSTFS_ACCESS_KEY:?set RUSTFS_ACCESS_KEY in .env}
      - RUSTFS_SECRET_KEY=${RUSTFS_SECRET_KEY:?set RUSTFS_SECRET_KEY in .env}
    # Loopback-bound by default: the S3 API carries the instance credentials,
    # and the unauthenticated console must never be network-reachable.
    ports:
      - "${RUSTCHAT_BIND_HOST:-127.0.0.1}:9000:9000" # S3 API
      - "${RUSTCHAT_BIND_HOST:-127.0.0.1}:9001:9001" # Console/UI
    volumes:
      - rustfs_data:/data
    healthcheck:
      test: [ "CMD", "curl", "-f", "http://localhost:9000/health" ]
      interval: 10s
      timeout: 5s
      retries: 5

  push-proxy:
    build:
      context: ./push-proxy
      dockerfile: Dockerfile
    image: rustchat-push-proxy
    container_name: rustchat-push-proxy
    restart: always
    environment:
      # Firebase (Android)
      - FIREBASE_PROJECT_ID=${FIREBASE_PROJECT_ID:-}
      - GOOGLE_APPLICATION_CREDENTIALS=/secrets/firebase-key.json
      # APNS (iOS) - JWT-based authentication
      - APNS_KEY_PATH=/secrets/apns-key.p8
      - APNS_KEY_ID=${APNS_KEY_ID:-}
      - APNS_TEAM_ID=${APNS_TEAM_ID:-}
      - APNS_BUNDLE_ID=${APNS_BUNDLE_ID:-}
      - APNS_USE_PRODUCTION=${APNS_USE_PRODUCTION:-false}
      # General
      - RUSTCHAT_PUSH_PORT=3000
      - RUST_LOG=push_proxy=info,tower_http=info
      - PUSH_PROXY_AUTH_KEY=${PUSH_PROXY_AUTH_KEY:-}
    volumes:
      # Firebase credentials
      - ${FIREBASE_KEY_PATH:-./secrets/firebase-key.json}:/secrets/firebase-key.json:ro
      # APNS Auth Key (JWT-based)
      # Backward-compatible fallback order:
      # 1) APNS_KEY_HOST_PATH (preferred)
      # 2) APNS_KEY_PATH (legacy host-path usage in older .env files)
      # 3) ./secrets/apns-key.p8
      - ${APNS_KEY_HOST_PATH:-${APNS_KEY_PATH:-./secrets/apns-key.p8}}:/secrets/apns-key.p8:ro
    ports:
      - "${RUSTCHAT_BIND_HOST:-127.0.0.1}:3001:3000"
    healthcheck:
      test: ["CMD-SHELL", "wget -qO- http://localhost:3000/health 2>&1 | grep -q 'ok' || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 5s

volumes:
  postgres_data:
  redis_data:
  rustfs_data: