# Jitsi Meet for Tvorymo CRM, based on github.com/jitsi/docker-jitsi-meet (stable-11248). # Deployed by Coolify (build_pack: dockercompose) on the Volcanic VPS (164.90.233.156). # # Routing: # https://meet.volcanic.tes.gd (443, Coolify Traefik) -> web:8000 (nginx) # / -> Jitsi web app # /xmpp-websocket -> prosody:5280 (proxied by web's nginx) # UDP JVB_PORT (10000) -> jvb (media + SCTP bridge channel), published on the host, bypasses Traefik. # # Auth: JWT only (AUTH_TYPE=jwt, ENABLE_GUESTS=0). Passes are issued by the CRM calls module # (docker-compose.calls.yml, https://crm-calls.volcanic.tes.gd): HS256, iss tvorymo-crm, aud jitsi, # one room, context.user.moderator -> owner via prosody token_affiliation. # # Voice-only calls: jitsi/custom-config.js is appended to the server config.js (browser and mobile app). # Recording: jibri (one instance, started by the calls module over its HTTP API on the crm-calls-bridge network), # jitsi/finalize.sh keeps only audio and deletes the video; files go to RECORDINGS_HOST_DIR shared with the module. # # Secrets (JICOFO_AUTH_PASSWORD, JVB_AUTH_PASSWORD, JWT_APP_SECRET, JIBRI_RECORDER_PASSWORD, JIBRI_XMPP_PASSWORD) # live only in Coolify env vars. services: web: # ghcr.io/jitsi/web + jitsi/custom-config.js (voice-only), see jitsi/web.Dockerfile. build: context: ./jitsi dockerfile: web.Dockerfile restart: unless-stopped read_only: true tmpfs: - /run:size=16M,mode=1750,exec - /tmp:size=16M,mode=1777,noexec expose: - '8000' volumes: - jitsi-web-config:/config - jitsi-web-storage:/storage environment: TZ: '${TZ:-Europe/Kyiv}' PUBLIC_URL: '${PUBLIC_URL:-https://meet.volcanic.tes.gd}' DISABLE_HTTPS: '1' ENABLE_HTTP_REDIRECT: '0' ENABLE_LETSENCRYPT: '0' ENABLE_XMPP_WEBSOCKET: '1' XMPP_SERVER: prosody XMPP_BOSH_URL_BASE: 'http://prosody:5280' XMPP_DOMAIN: meet.jitsi XMPP_AUTH_DOMAIN: auth.meet.jitsi XMPP_GUEST_DOMAIN: guest.meet.jitsi XMPP_MUC_DOMAIN: muc.meet.jitsi XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi DEFAULT_LANGUAGE: '${DEFAULT_LANGUAGE:-uk}' ENABLE_AUTH: '1' AUTH_TYPE: jwt ENABLE_GUESTS: '0' # The calls module shows its own "open in app / continue in browser" page. DISABLE_DEEP_LINKING: 'true' # Recording on: config gets hiddenDomain, so jibri can join as the hidden recorder. ENABLE_RECORDING: '1' START_AUDIO_ONLY: 'true' START_WITH_VIDEO_MUTED: 'true' # Only the calls module may embed Jitsi (call window). Jitsi's nginx sets no X-Frame-Options. CSP_HEADER: "frame-ancestors ${CALLS_ORIGIN:-https://crm-calls.volcanic.tes.gd}" depends_on: - jvb prosody: image: ghcr.io/jitsi/prosody:${JITSI_IMAGE_VERSION:-stable-11248} restart: unless-stopped read_only: true tmpfs: - /run:size=16M,mode=1750,exec - /tmp:size=16M,mode=1777,noexec expose: - '5222' - '5347' - '5280' volumes: - jitsi-prosody-config:/config - jitsi-prosody-plugins:/prosody-plugins-custom - jitsi-prosody-data:/var/lib/prosody environment: TZ: '${TZ:-Europe/Kyiv}' PUBLIC_URL: '${PUBLIC_URL:-https://meet.volcanic.tes.gd}' XMPP_SERVER: prosody XMPP_DOMAIN: meet.jitsi XMPP_AUTH_DOMAIN: auth.meet.jitsi XMPP_GUEST_DOMAIN: guest.meet.jitsi XMPP_MUC_DOMAIN: muc.meet.jitsi XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi ENABLE_XMPP_WEBSOCKET: '1' JICOFO_AUTH_PASSWORD: '${JICOFO_AUTH_PASSWORD}' JVB_AUTH_PASSWORD: '${JVB_AUTH_PASSWORD}' ENABLE_AUTH: '1' AUTH_TYPE: jwt ENABLE_GUESTS: '0' JWT_ALLOW_EMPTY: '0' JWT_APP_ID: '${JWT_APP_ID:-tvorymo-crm}' JWT_APP_SECRET: '${JWT_APP_SECRET}' JWT_ACCEPTED_ISSUERS: '${JWT_APP_ID:-tvorymo-crm}' JWT_ACCEPTED_AUDIENCES: '${JWT_AUDIENCE:-jitsi}' # context.user.moderator=true in the pass -> room owner (moderator); guests -> member. XMPP_MUC_MODULES: token_affiliation # HTTP /room?room=… (occupants) on prosody:5280 — the calls module polls it (concurrency limit, recording start/stop). XMPP_MODULES: muc_size ENABLE_RECORDING: '1' JIBRI_RECORDER_PASSWORD: '${JIBRI_RECORDER_PASSWORD}' JIBRI_XMPP_PASSWORD: '${JIBRI_XMPP_PASSWORD}' networks: default: calls-bridge: aliases: - jitsi-prosody jicofo: image: ghcr.io/jitsi/jicofo:${JITSI_IMAGE_VERSION:-stable-11248} restart: unless-stopped read_only: true tmpfs: - /run:size=32M,mode=1750,exec - /tmp:size=16M,mode=1777,noexec volumes: - jitsi-jicofo-config:/config environment: TZ: '${TZ:-Europe/Kyiv}' XMPP_SERVER: prosody XMPP_DOMAIN: meet.jitsi XMPP_AUTH_DOMAIN: auth.meet.jitsi XMPP_MUC_DOMAIN: muc.meet.jitsi XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi JICOFO_AUTH_PASSWORD: '${JICOFO_AUTH_PASSWORD}' # Prosody checks the pass. Jicofo's own auth must be off: with it, jicofo makes every # authenticated (= every JWT) participant a moderator, guests included. # Moderators come only from the pass (prosody token_affiliation); nobody becomes owner automatically. JICOFO_ENABLE_AUTH: '0' ENABLE_AUTO_OWNER: 'false' ENABLE_RECORDING: '1' JIBRI_XMPP_PASSWORD: '${JIBRI_XMPP_PASSWORD}' # Java heap (default 3072m — more than the whole server). JICOFO_MAX_MEMORY: '${JICOFO_MAX_MEMORY:-256m}' depends_on: - prosody jvb: image: ghcr.io/jitsi/jvb:${JITSI_IMAGE_VERSION:-stable-11248} restart: unless-stopped read_only: true tmpfs: - /run:size=32M,mode=1750,exec - /tmp:size=16M,mode=1777,noexec ports: # Media must reach JVB directly (not via Traefik): UDP JVB_PORT must be open # in the VPS firewall. Port and advertised IP come from Coolify env. - '${JVB_PORT:-10000}:${JVB_PORT:-10000}/udp' volumes: - jitsi-jvb-config:/config environment: TZ: '${TZ:-Europe/Kyiv}' PUBLIC_URL: '${PUBLIC_URL:-https://meet.volcanic.tes.gd}' XMPP_SERVER: prosody XMPP_DOMAIN: meet.jitsi XMPP_AUTH_DOMAIN: auth.meet.jitsi XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi JVB_AUTH_PASSWORD: '${JVB_AUTH_PASSWORD}' JVB_PORT: '${JVB_PORT:-10000}' # Comma-separated public IP(s) announced to clients; set in Coolify env (164.90.233.156). JVB_ADVERTISE_IPS: '${JVB_ADVERTISE_IPS:-164.90.233.156}' # Java heap (default 3072m — more than the whole server). VIDEOBRIDGE_MAX_MEMORY: '${VIDEOBRIDGE_MAX_MEMORY:-512m}' depends_on: - prosody # One recorder (MAX_CONCURRENT_CALLS=1). Started/stopped by the calls module via http://jitsi-jibri:2222. # Minimal video (800x480, 5 fps): only the audio is kept, see jitsi/finalize.sh. jibri: # ghcr.io/jitsi/jibri + jitsi/finalize.sh, see jitsi/jibri.Dockerfile. build: context: ./jitsi dockerfile: jibri.Dockerfile restart: unless-stopped read_only: true tmpfs: - /run:size=256M,mode=1750,exec - /tmp:size=256M,mode=1777,noexec # Jibri refuses to start with less (check in its init). tmpfs limit, memory is used only when Chrome writes there. shm_size: '2gb' volumes: - jitsi-jibri-config:/config - jitsi-jibri-storage:/storage - '${RECORDINGS_HOST_DIR:-/data/crm-calls/recordings}:/recordings' environment: TZ: '${TZ:-Europe/Kyiv}' PUBLIC_URL: '${PUBLIC_URL:-https://meet.volcanic.tes.gd}' XMPP_SERVER: prosody XMPP_DOMAIN: meet.jitsi XMPP_AUTH_DOMAIN: auth.meet.jitsi XMPP_MUC_DOMAIN: muc.meet.jitsi XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi XMPP_HIDDEN_DOMAIN: hidden.meet.jitsi DISPLAY: ':0' JIBRI_RECORDER_PASSWORD: '${JIBRI_RECORDER_PASSWORD}' JIBRI_XMPP_PASSWORD: '${JIBRI_XMPP_PASSWORD}' JIBRI_HTTP_API_EXTERNAL_PORT: '2222' JIBRI_RECORDING_DIR: /recordings JIBRI_FINALIZE_RECORDING_SCRIPT_PATH: /opt/crm-calls/finalize.sh JIBRI_RECORDING_RESOLUTION: '800x480' JIBRI_RECORDING_FRAMERATE: '5' JIBRI_RECORDING_CONSTANT_RATE_FACTOR: '40' JIBRI_RECORDING_VIDEO_ENCODE_PRESET_RECORDING: ultrafast # Jibri's own JVM: small heap. HTTP API on 0.0.0.0 (default 127.0.0.1) — reachable only inside docker networks # (crm-calls-bridge for the module), the port is not published. Voice calls: people may stay muted/silent for long — # Jibri must not stop the recording on "no media"/"all muted"; the module stops it when the room empties. JAVA_TOOL_OPTIONS: '-Xmx256m -Djibri.api.http.external-api-host=0.0.0.0 -Djibri.call-status-checks.no-media-timeout=4h -Djibri.call-status-checks.all-muted-timeout=4h -Djibri.call-status-checks.default-call-empty-timeout=60s' CALLS_AUDIO_BITRATE: '${CALLS_AUDIO_BITRATE:-32k}' CALLS_CHUNK_SECONDS: '${CALLS_CHUNK_SECONDS:-1200}' depends_on: - jicofo networks: default: calls-bridge: aliases: - jitsi-jibri networks: # Shared with the calls module app (docker-compose.calls.yml, external network of the same name). calls-bridge: name: crm-calls-bridge volumes: jitsi-jibri-config: jitsi-jibri-storage: jitsi-web-config: jitsi-web-storage: jitsi-prosody-config: jitsi-prosody-plugins: jitsi-prosody-data: jitsi-jicofo-config: jitsi-jvb-config: