# NOTE: based on https://github.com/suitenumerique/meet/blob/main/docs/installation/compose.md # and https://github.com/suitenumerique/meet/blob/main/docs/examples/compose/compose.yaml x-common-env: &common-env DJANGO_CONFIGURATION: Production DJANGO_ALLOWED_HOSTS: "*" # DJANGO_SECRET_KEY supplied via secrets DJANGO_SETTINGS_MODULE: meet.settings # DJANGO_SUPERUSER_PASSWORD supplied via secrets # Logging LOGGING_LEVEL_HANDLERS_CONSOLE: ${LOGGING_LEVEL_HANDLERS_CONSOLE:-INFO} LOGGING_LEVEL_LOGGERS_ROOT: ${LOGGING_LEVEL_LOGGERS_ROOT:-INFO} LOGGING_LEVEL_LOGGERS_APP: ${LOGGING_LEVEL_LOGGERS_APP:-INFO} # Python PYTHONPATH: /app # Mail DJANGO_EMAIL_BRAND_NAME: DJANGO_EMAIL_HOST: DJANGO_EMAIL_LOGO_IMG: DJANGO_EMAIL_PORT: DJANGO_EMAIL_HOST_USER: # DJANGO_EMAIL_HOST_PASSWORD supplied via secret DJANGO_EMAIL_USE_SSL: DJANGO_EMAIL_USE_TLS: DJANGO_EMAIL_FROM: # Backend URL MEET_BASE_URL: "https://${DOMAIN}" # Redis REDIS_URL: "redis://${STACK_NAME}_redis:6379/0" # OIDC - settings from .env, see .env.sample OIDC_OP_JWKS_ENDPOINT: OIDC_OP_AUTHORIZATION_ENDPOINT: OIDC_OP_TOKEN_ENDPOINT: OIDC_OP_USER_ENDPOINT: OIDC_OP_LOGOUT_ENDPOINT: OIDC_RP_CLIENT_ID: # OIDC_RP_CLIENT_SECRET supplied via secrets OIDC_RP_SIGN_ALGO: OIDC_RP_SCOPES: LOGIN_REDIRECT_URL: LOGIN_REDIRECT_URL_FAILURE: LOGOUT_REDIRECT_URL: OIDC_REDIRECT_ALLOWED_HOSTS: OIDC_AUTH_REQUEST_EXTRA_PARAMS: # LiveKit LIVEKIT_API_KEY: LIVEKIT_API_URL: "https://${LIVEKIT_DOMAIN}" # LIVEKIT_API_SECRET supplied via secrets ALLOW_UNREGISTERED_ROOMS: x-postgres-env: &postgres-env # Postgresql db container configuration POSTGRES_DB: meet POSTGRES_USER: meet POSTGRES_PASSWORD_FILE: /run/secrets/postgres_p # App database configuration DB_HOST: db DB_NAME: meet DB_USER: meet DB_PORT: 5432 # DB_PASSWORD supplied via secrets (this is same as POSTGRES_PASSWORD) services: app: image: lasuite/meet-frontend:v1.15.0 networks: - backend deploy: labels: - "traefik.enable=false" - "coop-cloud.${STACK_NAME}.timeout=${TIMEOUT:-120}" - "coop-cloud.${STACK_NAME}.version=0.2.0+v1.15.0" user: "${DOCKER_USER:-1000}" entrypoint: - /docker-entrypoint.sh command: ["nginx", "-g", "daemon off;"] environment: - MEET_HOST=${DOMAIN} - LIVEKIT_HOST=${LIVEKIT_DOMAIN} healthcheck: test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1:8080 || exit 1"] interval: 15s timeout: 30s retries: 20 start_period: 10s backend: image: lasuite/meet-backend:v1.15.0 networks: - backend environment: <<: [*common-env, *postgres-env] AUTO_MIGRATIONS: "${AUTO_MIGRATIONS:-true}" healthcheck: test: ["CMD", "/abra-entrypoint.sh", "python", "manage.py", "check"] interval: 15s timeout: 30s retries: 20 start_period: 10s user: "${DOCKER_USER:-1000}" entrypoint: > sh -c "if [ \"$$AUTO_MIGRATIONS\" = \"true\" ]; then /migrate.sh; fi && exec /abra-entrypoint.sh \"$$@\"" -- command: ["gunicorn", "-c", "/usr/local/etc/gunicorn/meet.py", "meet.wsgi:application"] configs: - source: abra_entrypoint target: /abra-entrypoint.sh mode: 0555 - source: migrate target: /migrate.sh mode: 0555 secrets: - django_sk - django_sp - oidc_rpcs - postgres_p - livekit_as - email_pass celery: image: lasuite/meet-backend:v1.15.0 networks: - backend healthcheck: test: ["CMD", "celery", "-A", "meet.celery_app", "inspect", "ping", "--timeout", "5"] interval: 30s timeout: 10s retries: 3 start_period: 30s user: "${DOCKER_USER:-1000}" command: ["celery", "-A", "meet.celery_app", "worker", "-l", "INFO"] environment: <<: [*common-env, *postgres-env] entrypoint: ["/abra-entrypoint.sh"] configs: - source: abra_entrypoint target: /abra-entrypoint.sh mode: 0555 secrets: - django_sk - django_sp - oidc_rpcs - postgres_p - livekit_as - email_pass db: image: pgautoupgrade/pgautoupgrade:18-debian networks: - backend healthcheck: test: ["CMD", "pg_isready", "-q", "-U", "meet", "-d", "meet"] interval: 1s timeout: 2s retries: 300 environment: <<: *postgres-env PGDATA: /var/lib/postgresql/data/pgdata volumes: - postgres:/var/lib/postgresql/data/pgdata deploy: labels: backupbot.backup: "${ENABLE_BACKUPS:-true}" backupbot.backup.pre-hook: "/pg_backup.sh backup" backupbot.backup.volumes.postgres.path: "backup.sql" backupbot.restore.post-hook: '/pg_backup.sh restore' configs: - source: pg_backup target: /pg_backup.sh mode: 0555 secrets: - postgres_p redis: image: redis:8.6.3 healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 15s timeout: 5s retries: 3 networks: - backend livekit: image: livekit/livekit-server:v1.11.0 command: --config /livekit-server.yaml environment: - STACK_NAME - LIVEKIT_API_KEY - LIVEKIT_NODE_IP - LIVEKIT_FORCE_TCP=${LIVEKIT_FORCE_TCP:-false} - LIVEKIT_TURN_ENABLED=${LIVEKIT_TURN_ENABLED:-true} - TURN_DOMAIN=${TURN_DOMAIN:-${LIVEKIT_DOMAIN}} - TURN_UDP_PORT=${TURN_UDP_PORT:-443} # WebRTC ICE ports must be published directly on the host. # These carry raw RTP media, not HTTP — cannot be proxied through Traefik without extra traefik compose. # See docs/multinode.md for multi-node deployment considerations. ports: - target: 7881 published: 7881 protocol: tcp mode: host - target: 7882 published: 7882 protocol: udp mode: host configs: - source: livekit_config target: /livekit-server.yaml secrets: - livekit_as networks: - proxy - backend deploy: labels: - "traefik.enable=true" - "traefik.docker.network=proxy" - "traefik.http.routers.${STACK_NAME}_livekit.rule=Host(`${LIVEKIT_DOMAIN}`)" - "traefik.http.routers.${STACK_NAME}_livekit.entrypoints=web-secure" - "traefik.http.routers.${STACK_NAME}_livekit.tls.certresolver=${LETS_ENCRYPT_ENV}" - "traefik.http.services.${STACK_NAME}_livekit.loadbalancer.server.port=7880" web: image: nginx:1.29.8 environment: - STACK_NAME healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8083"] interval: 15s timeout: 5s retries: 10 start_period: 30s configs: - source: nginx_conf target: /etc/nginx/conf.d/default.conf networks: proxy: backend: depends_on: - backend - app deploy: labels: - "traefik.enable=true" - "traefik.docker.network=proxy" - "traefik.http.routers.${STACK_NAME}.tls=true" - "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=8083" - "traefik.http.routers.${STACK_NAME}.rule=Host(`${DOMAIN}`${EXTRA_DOMAINS})" - "traefik.http.routers.${STACK_NAME}.tls.certresolver=${LETS_ENCRYPT_ENV}" - "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure" networks: proxy: external: true backend: volumes: postgres: configs: nginx_conf: name: ${STACK_NAME}_nginx_conf_${NGINX_CONF_VERSION} file: nginx.conf.tmpl template_driver: golang pg_backup: name: ${STACK_NAME}_pg_backup_${PG_BACKUP_VERSION} file: pg_backup.sh abra_entrypoint: name: ${STACK_NAME}_entrypoint_${ABRA_ENTRYPOINT_VERSION} file: abra-entrypoint.sh migrate: name: ${STACK_NAME}_migrate_${MIGRATE_VERSION} file: migrate.sh livekit_config: name: ${STACK_NAME}_livekit_config_${LIVEKIT_CONFIG_VERSION} file: livekit-server.yaml.tmpl template_driver: golang secrets: django_sk: external: true name: ${STACK_NAME}_django_sk_${SECRET_DJANGO_SK_VERSION} oidc_rpcs: external: true name: ${STACK_NAME}_oidc_rpcs_${SECRET_OIDC_RPCS_VERSION} django_sp: external: true name: ${STACK_NAME}_django_sp_${SECRET_DJANGO_SP_VERSION} postgres_p: external: true name: ${STACK_NAME}_postgres_p_${SECRET_POSTGRES_P_VERSION} livekit_as: external: true name: ${STACK_NAME}_livekit_as_${SECRET_LIVEKIT_AS_VERSION} email_pass: external: true name: ${STACK_NAME}_email_pass_${SECRET_EMAIL_PASS_VERSION}