├── base ├── rootfs │ ├── etc │ │ ├── cont-finish.d │ │ │ └── .gitkeep │ │ ├── cont-init.d │ │ │ ├── .gitkeep │ │ │ └── 01-set-timezone │ │ ├── fix-attrs.d │ │ │ └── .gitkeep │ │ ├── services.d │ │ │ └── .gitkeep │ │ └── apt │ │ │ └── apt.conf.d │ │ │ └── 99local │ └── usr │ │ └── bin │ │ ├── tpl │ │ ├── apt-cleanup │ │ └── apt-dpkg-wrap ├── Makefile └── Dockerfile ├── .gitignore ├── prosody ├── rootfs │ ├── etc │ │ ├── sasl │ │ │ └── xmpp.conf │ │ ├── services.d │ │ │ ├── prosody │ │ │ │ └── run │ │ │ └── 10-saslauthd │ │ │ │ └── run │ │ └── cont-init.d │ │ │ └── 10-config │ └── defaults │ │ ├── saslauthd.conf │ │ ├── conf.d │ │ └── jitsi-meet.cfg.lua │ │ └── prosody.cfg.lua ├── Makefile └── Dockerfile ├── jvb ├── Makefile ├── Dockerfile └── rootfs │ ├── defaults │ ├── logging.properties │ └── sip-communicator.properties │ └── etc │ ├── cont-init.d │ └── 10-config │ └── services.d │ └── jvb │ └── run ├── web ├── Makefile ├── rootfs │ ├── etc │ │ ├── services.d │ │ │ ├── nginx │ │ │ │ └── run │ │ │ └── cron │ │ │ │ └── run │ │ └── cont-init.d │ │ │ └── 10-config │ └── defaults │ │ ├── letsencrypt-renew │ │ ├── default │ │ ├── ssl.conf │ │ ├── nginx.conf │ │ └── meet.conf └── Dockerfile ├── jibri ├── Makefile ├── rootfs │ ├── etc │ │ ├── opt │ │ │ └── chrome │ │ │ │ └── policies │ │ │ │ └── managed │ │ │ │ └── managed_policies.json │ │ ├── services.d │ │ │ ├── 20-icewm │ │ │ │ └── run │ │ │ ├── 30-jibri │ │ │ │ └── run │ │ │ └── 10-xorg │ │ │ │ └── run │ │ └── cont-init.d │ │ │ └── 10-config │ └── defaults │ │ ├── logging.properties │ │ └── config.json └── Dockerfile ├── jicofo ├── Makefile ├── Dockerfile └── rootfs │ ├── etc │ ├── services.d │ │ └── jicofo │ │ │ └── run │ └── cont-init.d │ │ └── 10-config │ └── defaults │ ├── logging.properties │ └── sip-communicator.properties ├── jigasi ├── Makefile ├── Dockerfile └── rootfs │ ├── etc │ ├── services.d │ │ └── jigasi │ │ │ └── run │ └── cont-init.d │ │ └── 10-config │ └── defaults │ ├── logging.properties │ └── sip-communicator.properties ├── base-java ├── Makefile └── Dockerfile ├── etherpad ├── Makefile ├── Dockerfile └── rootfs │ └── defaults │ └── settings.json ├── resources ├── jitsi-docker.png ├── docker-jitsi-meet.png └── docker-jitsi-meet.xml ├── etherpad.yml ├── examples ├── kubernetes │ ├── jvb-service.yaml │ ├── web-service.yaml │ ├── README.md │ └── deployment.yaml ├── README.md ├── traefik │ ├── README.md │ └── docker-compose.yml └── traefik-v2 │ ├── README.md │ └── docker-compose.yml ├── README.md ├── gen-passwords.sh ├── jibri.yml ├── Makefile ├── release.sh ├── jigasi.yml ├── docker-compose.yml ├── CHANGELOG.md ├── env.example └── LICENSE /base/rootfs/etc/cont-finish.d/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /base/rootfs/etc/cont-init.d/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /base/rootfs/etc/fix-attrs.d/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /base/rootfs/etc/services.d/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /base/rootfs/usr/bin/tpl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec frep $1:- 4 | 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .env 3 | .env.bak 4 | docker-compose.override.yml 5 | -------------------------------------------------------------------------------- /base/rootfs/usr/bin/apt-cleanup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -rf /var/lib/apt/lists/ 4 | -------------------------------------------------------------------------------- /prosody/rootfs/etc/sasl/xmpp.conf: -------------------------------------------------------------------------------- 1 | pwcheck_method: saslauthd 2 | mech_list: PLAIN 3 | -------------------------------------------------------------------------------- /jvb/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | docker build $(BUILD_ARGS) -t $(JITSI_REPO)/jvb . 3 | 4 | .PHONY: build 5 | -------------------------------------------------------------------------------- /web/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | docker build $(BUILD_ARGS) -t $(JITSI_REPO)/web . 3 | 4 | .PHONY: build 5 | -------------------------------------------------------------------------------- /jibri/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | docker build $(BUILD_ARGS) -t $(JITSI_REPO)/jibri . 3 | 4 | .PHONY: build 5 | -------------------------------------------------------------------------------- /jicofo/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | docker build $(BUILD_ARGS) -t $(JITSI_REPO)/jicofo . 3 | 4 | .PHONY: build 5 | -------------------------------------------------------------------------------- /jigasi/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | docker build $(BUILD_ARGS) -t $(JITSI_REPO)/jigasi . 3 | 4 | .PHONY: build 5 | -------------------------------------------------------------------------------- /base-java/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | docker build $(BUILD_ARGS) -t $(JITSI_REPO)/base-java . 3 | 4 | .PHONY: build 5 | -------------------------------------------------------------------------------- /base/rootfs/etc/apt/apt.conf.d/99local: -------------------------------------------------------------------------------- 1 | APT::Install-Recommends "false"; 2 | APT::Install-Suggests "false"; 3 | -------------------------------------------------------------------------------- /etherpad/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | docker build $(BUILD_ARGS) -t $(JITSI_REPO)/etherpad . 3 | 4 | .PHONY: build 5 | -------------------------------------------------------------------------------- /prosody/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | docker build $(BUILD_ARGS) -t $(JITSI_REPO)/prosody . 3 | 4 | .PHONY: build 5 | -------------------------------------------------------------------------------- /resources/jitsi-docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vertelab/docker-jitsi-meet/master/resources/jitsi-docker.png -------------------------------------------------------------------------------- /web/rootfs/etc/services.d/nginx/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | exec nginx -c /config/nginx/nginx.conf 4 | -------------------------------------------------------------------------------- /resources/docker-jitsi-meet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vertelab/docker-jitsi-meet/master/resources/docker-jitsi-meet.png -------------------------------------------------------------------------------- /jibri/rootfs/etc/opt/chrome/policies/managed/managed_policies.json: -------------------------------------------------------------------------------- 1 | { 2 | "CommandLineFlagSecurityWarningsEnabled": false 3 | } 4 | 5 | -------------------------------------------------------------------------------- /base/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | docker build $(BUILD_ARGS) --build-arg JITSI_RELEASE=$(JITSI_RELEASE) -t $(JITSI_REPO)/base . 3 | 4 | .PHONY: build 5 | -------------------------------------------------------------------------------- /etherpad/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM etherpad/etherpad:1.8.4 2 | 3 | ADD ./rootfs/defaults/settings.json /opt/etherpad-lite/settings.json 4 | 5 | EXPOSE 9001 6 | -------------------------------------------------------------------------------- /prosody/rootfs/etc/services.d/prosody/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | exec s6-setuidgid prosody prosody --config /config/prosody.cfg.lua 3 | 4 | -------------------------------------------------------------------------------- /base/rootfs/usr/bin/apt-dpkg-wrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export LC_ALL=C 4 | export DEBIAN_FRONTEND=noninteractive 5 | 6 | bin=$1 7 | shift 8 | exec "$bin" "$@" 9 | -------------------------------------------------------------------------------- /jibri/rootfs/etc/services.d/20-icewm/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | DAEMON="/usr/bin/icewm-session" 4 | exec s6-setuidgid jibri /bin/bash -c "exec $DAEMON" 5 | 6 | -------------------------------------------------------------------------------- /prosody/rootfs/etc/services.d/10-saslauthd/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | exec s6-setuidgid root saslauthd -a ldap -O /etc/saslauthd.conf -c -m /var/run/saslauthd -n 5 -d 3 | -------------------------------------------------------------------------------- /web/rootfs/etc/services.d/cron/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | if [[ $DISABLE_HTTPS -ne 1 ]]; then 4 | if [[ $ENABLE_LETSENCRYPT -eq 1 ]]; then 5 | exec cron -f 6 | fi 7 | fi 8 | -------------------------------------------------------------------------------- /jicofo/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG JITSI_REPO=jitsi 2 | FROM ${JITSI_REPO}/base-java 3 | 4 | RUN \ 5 | apt-dpkg-wrap apt-get update && \ 6 | apt-dpkg-wrap apt-get install -y jicofo && \ 7 | apt-cleanup 8 | 9 | COPY rootfs/ / 10 | 11 | VOLUME /config 12 | 13 | -------------------------------------------------------------------------------- /base-java/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG JITSI_REPO=jitsi 2 | FROM ${JITSI_REPO}/base 3 | 4 | RUN \ 5 | mkdir -p /usr/share/man/man1 && \ 6 | apt-dpkg-wrap apt-get update && \ 7 | apt-dpkg-wrap apt-get install -y openjdk-8-jre-headless && \ 8 | apt-cleanup 9 | 10 | -------------------------------------------------------------------------------- /jibri/rootfs/etc/services.d/30-jibri/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | # we have to set it, otherwise chrome won't find ~/.asoundrc file 4 | HOME=/home/jibri 5 | 6 | DAEMON=/opt/jitsi/jibri/launch.sh 7 | exec s6-setuidgid jibri /bin/bash -c "exec $DAEMON" 8 | 9 | -------------------------------------------------------------------------------- /jvb/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG JITSI_REPO=jitsi 2 | FROM ${JITSI_REPO}/base-java 3 | 4 | RUN \ 5 | apt-dpkg-wrap apt-get update && \ 6 | apt-dpkg-wrap apt-get install -y jitsi-videobridge2 jq curl && \ 7 | apt-cleanup 8 | 9 | COPY rootfs/ / 10 | 11 | VOLUME /config 12 | -------------------------------------------------------------------------------- /web/rootfs/defaults/letsencrypt-renew: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # stop nginx 4 | s6-svc -d /var/run/s6/services/nginx 5 | 6 | # renew cert 7 | certbot-auto --no-self-upgrade -n renew >> /config/le-renew.log 8 | 9 | # start nginx 10 | s6-svc -u /var/run/s6/services/nginx 11 | -------------------------------------------------------------------------------- /jibri/rootfs/etc/services.d/10-xorg/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | DAEMON="/usr/bin/Xorg -nocursor -noreset +extension RANDR +extension RENDER -logfile /tmp/xorg.log -config /etc/jitsi/jibri/xorg-video-dummy.conf ${DISPLAY}" 4 | exec s6-setuidgid jibri /bin/bash -c "exec $DAEMON" 5 | 6 | -------------------------------------------------------------------------------- /base/rootfs/etc/cont-init.d/01-set-timezone: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv sh 2 | 3 | if [ $TZ ]; then 4 | [ -f /usr/share/zoneinfo/$TZ ] && cp /usr/share/zoneinfo/$TZ /etc/localtime || echo "WARNING: $TZ is not a valid time zone." 5 | [ -f /usr/share/zoneinfo/$TZ ] && echo "$TZ" > /etc/timezone 6 | fi 7 | -------------------------------------------------------------------------------- /etherpad.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | # Etherpad: real-time collaborative document editing 5 | etherpad: 6 | image: jitsi/etherpad:latest 7 | restart: ${RESTART_POLICY} 8 | networks: 9 | meet.jitsi: 10 | aliases: 11 | - etherpad.meet.jitsi 12 | -------------------------------------------------------------------------------- /jigasi/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG JITSI_REPO=jitsi 2 | FROM ${JITSI_REPO}/base-java 3 | 4 | ENV GOOGLE_APPLICATION_CREDENTIALS /config/key.json 5 | 6 | RUN \ 7 | apt-dpkg-wrap apt-get update && \ 8 | apt-dpkg-wrap apt-get install -y jigasi jq && \ 9 | apt-cleanup 10 | 11 | COPY rootfs/ / 12 | 13 | VOLUME ["/config", "/tmp/transcripts"] 14 | -------------------------------------------------------------------------------- /examples/kubernetes/jvb-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | service: jvb 6 | name: jvb-udp 7 | namespace: jitsi 8 | spec: 9 | type: NodePort 10 | externalTrafficPolicy: Cluster 11 | ports: 12 | - port: 30300 13 | protocol: UDP 14 | targetPort: 30300 15 | nodePort: 30300 16 | selector: 17 | k8s-app: jitsi 18 | -------------------------------------------------------------------------------- /jigasi/rootfs/etc/services.d/jigasi/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | JAVA_SYS_PROPS="-Djava.util.logging.config.file=/config/logging.properties" 4 | 5 | DAEMON=/usr/share/jigasi/jigasi.sh 6 | DAEMON_OPTS="--nocomponent=true --configdir=/ --configdirname=config --min-port=$JIGASI_PORT_MIN --max-port=$JIGASI_PORT_MAX" 7 | 8 | exec s6-setuidgid jigasi /bin/bash -c "JAVA_SYS_PROPS=\"$JAVA_SYS_PROPS\" exec $DAEMON $DAEMON_OPTS" 9 | 10 | -------------------------------------------------------------------------------- /web/rootfs/defaults/default: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80 default_server; 3 | 4 | {{ if .Env.ENABLE_HTTP_REDIRECT | default "0" | toBool }} 5 | return 301 https://$host$request_uri; 6 | {{ else }} 7 | include /config/nginx/meet.conf; 8 | {{ end }} 9 | } 10 | 11 | {{ if not (.Env.DISABLE_HTTPS | default "0" | toBool) }} 12 | server { 13 | listen 443 ssl http2; 14 | 15 | include /config/nginx/ssl.conf; 16 | include /config/nginx/meet.conf; 17 | } 18 | {{ end }} 19 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Community Examples 2 | 3 | The examples contained in this directory have been provided by the community 4 | and allow users to run the container setup in scenarios other than the 5 | default one (using Docker Compose). 6 | 7 | Since they are maintained by the community, they may not provide the same 8 | features as the default setup. 9 | 10 | No support is provided for these, but if you found a bug and can fix it 11 | we'll be happy to accept a Pull-Request to fix it! 12 | -------------------------------------------------------------------------------- /jvb/rootfs/defaults/logging.properties: -------------------------------------------------------------------------------- 1 | handlers= java.util.logging.ConsoleHandler 2 | 3 | java.util.logging.ConsoleHandler.level = ALL 4 | java.util.logging.ConsoleHandler.formatter = net.java.sip.communicator.util.ScLogFormatter 5 | 6 | net.java.sip.communicator.util.ScLogFormatter.programname=JVB 7 | 8 | .level=INFO 9 | 10 | org.jitsi.videobridge.xmpp.ComponentImpl.level=FINE 11 | 12 | # All of the INFO level logs from MediaStreamImpl are unnecessary in the context of jitsi-videobridge. 13 | org.jitsi.impl.neomedia.MediaStreamImpl.level=WARNING 14 | 15 | -------------------------------------------------------------------------------- /jicofo/rootfs/etc/services.d/jicofo/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | JAVA_SYS_PROPS="-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION=/ -Dnet.java.sip.communicator.SC_HOME_DIR_NAME=config -Djava.util.logging.config.file=/config/logging.properties" 4 | DAEMON=/usr/share/jicofo/jicofo.sh 5 | DAEMON_DIR=/usr/share/jicofo/ 6 | DAEMON_OPTS="--domain=$XMPP_DOMAIN --host=$XMPP_SERVER --secret=$JICOFO_COMPONENT_SECRET --user_name=$JICOFO_AUTH_USER --user_domain=$XMPP_AUTH_DOMAIN --user_password=$JICOFO_AUTH_PASSWORD" 7 | 8 | exec s6-setuidgid jicofo /bin/bash -c "cd $DAEMON_DIR; JAVA_SYS_PROPS=\"$JAVA_SYS_PROPS\" exec $DAEMON $DAEMON_OPTS" 9 | -------------------------------------------------------------------------------- /examples/kubernetes/web-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | service: web 6 | name: web 7 | namespace: jitsi 8 | spec: 9 | ports: 10 | - name: "http" 11 | port: 80 12 | targetPort: 80 13 | - name: "https" 14 | port: 443 15 | targetPort: 443 16 | selector: 17 | k8s-app: jitsi 18 | --- 19 | apiVersion: networking.k8s.io/v1beta1 20 | kind: Ingress 21 | metadata: 22 | name: jitsi 23 | namespace: jitsi 24 | spec: 25 | rules: 26 | - host: ... 27 | http: 28 | paths: 29 | - path: / 30 | backend: 31 | serviceName: web 32 | servicePort: https -------------------------------------------------------------------------------- /jigasi/rootfs/defaults/logging.properties: -------------------------------------------------------------------------------- 1 | handlers= java.util.logging.ConsoleHandler 2 | 3 | java.util.logging.ConsoleHandler.level = ALL 4 | java.util.logging.ConsoleHandler.formatter = net.java.sip.communicator.util.ScLogFormatter 5 | 6 | net.java.sip.communicator.util.ScLogFormatter.programname=Jigasi 7 | 8 | .level=INFO 9 | net.sf.level=SEVERE 10 | net.java.sip.communicator.plugin.reconnectplugin.level=FINE 11 | org.ice4j.level=SEVERE 12 | org.jitsi.impl.neomedia.level=SEVERE 13 | 14 | # Do not worry about missing strings 15 | net.java.sip.communicator.service.resources.AbstractResourcesService.level=SEVERE 16 | 17 | #net.java.sip.communicator.service.protocol.level=ALL 18 | 19 | -------------------------------------------------------------------------------- /jvb/rootfs/etc/cont-init.d/10-config: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | if [[ -z $JVB_AUTH_PASSWORD ]]; then 4 | echo 'FATAL ERROR: JVB auth password must be set' 5 | exit 1 6 | fi 7 | 8 | OLD_JVB_AUTH_PASSWORD=passw0rd 9 | if [[ "$JVB_AUTH_PASSWORD" == "$OLD_JVB_AUTH_PASSWORD" ]]; then 10 | echo 'FATAL ERROR: JVB auth password must be changed, check the README' 11 | exit 1 12 | fi 13 | 14 | if [[ ! -f /config/sip-communicator.properties ]]; then 15 | tpl /defaults/sip-communicator.properties > /config/sip-communicator.properties 16 | fi 17 | 18 | if [[ ! -f /config/logging.properties ]]; then 19 | cp /defaults/logging.properties /config 20 | fi 21 | 22 | chown -R jvb:jitsi /config 23 | -------------------------------------------------------------------------------- /jicofo/rootfs/defaults/logging.properties: -------------------------------------------------------------------------------- 1 | handlers= java.util.logging.ConsoleHandler 2 | 3 | java.util.logging.ConsoleHandler.level = ALL 4 | java.util.logging.ConsoleHandler.formatter = net.java.sip.communicator.util.ScLogFormatter 5 | 6 | net.java.sip.communicator.util.ScLogFormatter.programname=Jicofo 7 | 8 | .level=INFO 9 | net.sf.level=SEVERE 10 | net.java.sip.communicator.plugin.reconnectplugin.level=FINE 11 | org.ice4j.level=SEVERE 12 | org.jitsi.impl.neomedia.level=SEVERE 13 | 14 | # Do not worry about missing strings 15 | net.java.sip.communicator.service.resources.AbstractResourcesService.level=SEVERE 16 | 17 | #net.java.sip.communicator.service.protocol.level=ALL 18 | 19 | # Enable debug packets logging 20 | #org.jitsi.impl.protocol.xmpp.level=FINE 21 | 22 | -------------------------------------------------------------------------------- /jvb/rootfs/etc/services.d/jvb/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | JAVA_SYS_PROPS="-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION=/ -Dnet.java.sip.communicator.SC_HOME_DIR_NAME=config -Djava.util.logging.config.file=/config/logging.properties" 4 | 5 | if [[ ! -z "$DOCKER_HOST_ADDRESS" ]]; then 6 | LOCAL_ADDRESS=$(hostname -I | cut -d " " -f1) 7 | JAVA_SYS_PROPS="$JAVA_SYS_PROPS -Dorg.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS=$LOCAL_ADDRESS -Dorg.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS=$DOCKER_HOST_ADDRESS" 8 | fi 9 | 10 | DAEMON=/usr/share/jitsi-videobridge/jvb.sh 11 | DEFAULT_DAEMON_OPTS="none" 12 | 13 | DAEMON_OPTS=${JVB_ENABLE_APIS:=$DEFAULT_DAEMON_OPTS} 14 | 15 | exec s6-setuidgid jvb /bin/bash -c "JAVA_SYS_PROPS=\"$JAVA_SYS_PROPS\" exec $DAEMON --apis=${DAEMON_OPTS}" 16 | 17 | -------------------------------------------------------------------------------- /examples/traefik/README.md: -------------------------------------------------------------------------------- 1 | # Basic configuration to use with the traefik reverse proxy 2 | 3 | Note: Tested with traefik 1.7 4 | 5 | - When running behind traefik, it's a better practice to remove the port-binds for the web service. 6 | - The provided example uses an external network with the name "web". This is the network which moste likely was created while setting up traefik. 7 | - Look for comments starting with **#traefik:** to see the changes made in docker-compose.yml. 8 | 9 | Uncomment and set DOCKER_HOST_ADDRESS in .env. I'm pretty sure, that this is mandatory for the docker-setup and should be clearer in the original README. Could be the proxying, didn't investigate further. 10 | 11 | ## TODO 12 | 13 | Add or rewrite the example with docker-compose extends 14 | 15 | ````env 16 | DOCKER_HOST_ADDRESS=1.2.3.4 17 | ```` 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jitsi Meet on Docker 2 | 3 | ![](resources/jitsi-docker.png) 4 | 5 | [Jitsi](https://jitsi.org/) is a set of Open Source projects that allows you to easily build and deploy secure videoconferencing solutions. 6 | 7 | [Jitsi Meet](https://jitsi.org/jitsi-meet/) is a fully encrypted, 100% Open Source video conferencing solution that you can use all day, every day, for free — with no account needed. 8 | 9 | This repository contains the necessary tools to run a Jitsi Meet stack on [Docker](https://www.docker.com) using [Docker Compose](https://docs.docker.com/compose/). 10 | 11 | ## Installation 12 | 13 | The installation manual is available [here](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker). 14 | 15 | ## TODO 16 | 17 | * Support container replicas (where applicable). 18 | * TURN server. 19 | 20 | -------------------------------------------------------------------------------- /examples/traefik-v2/README.md: -------------------------------------------------------------------------------- 1 | # Basic configuration to use with the traefik reverse proxy 2 | 3 | Note: Tested with traefik 2.2.0 4 | 5 | - When running behind traefik, it's a better practice to remove the port-binds for the web service. 6 | - The provided example uses an external network with the name "web". This is the network which moste likely was created while setting up traefik. 7 | - Look for comments starting with **#traefik:** to see the changes made in docker-compose.yml. 8 | - Traefik obtains Let's Encrypt certificates automatically. 9 | 10 | Uncomment and set DOCKER_HOST_ADDRESS in .env. I'm pretty sure, that this is mandatory for the docker-setup and should be clearer in the original README. Could be the proxying, didn't investigate further. 11 | 12 | ## TODO 13 | 14 | Add or rewrite the example with docker-compose extends 15 | 16 | ````env 17 | DOCKER_HOST_ADDRESS=1.2.3.4 18 | ```` 19 | -------------------------------------------------------------------------------- /web/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG JITSI_REPO=jitsi 2 | FROM ${JITSI_REPO}/base 3 | 4 | ADD https://dl.eff.org/certbot-auto /usr/local/bin/ 5 | 6 | COPY rootfs/ / 7 | 8 | RUN \ 9 | apt-dpkg-wrap apt-get update && \ 10 | apt-dpkg-wrap apt-get install -y cron nginx-extras jitsi-meet-web && \ 11 | apt-dpkg-wrap apt-get -d install -y jitsi-meet-web-config && \ 12 | dpkg -x /var/cache/apt/archives/jitsi-meet-web-config*.deb /tmp/pkg && \ 13 | mv /tmp/pkg/usr/share/jitsi-meet-web-config/config.js /defaults && \ 14 | mv /usr/share/jitsi-meet/interface_config.js /defaults && \ 15 | apt-cleanup && \ 16 | rm -f /etc/nginx/conf.d/default.conf && \ 17 | rm -rf /tmp/pkg /var/cache/apt 18 | 19 | RUN \ 20 | chmod a+x /usr/local/bin/certbot-auto && \ 21 | certbot-auto --noninteractive --install-only 22 | 23 | EXPOSE 80 443 24 | 25 | VOLUME ["/config", "/etc/letsencrypt", "/usr/share/jitsi-meet/transcripts"] 26 | -------------------------------------------------------------------------------- /gen-passwords.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function generatePassword() { 4 | openssl rand -hex 16 5 | } 6 | 7 | JICOFO_COMPONENT_SECRET=$(generatePassword) 8 | JICOFO_AUTH_PASSWORD=$(generatePassword) 9 | JVB_AUTH_PASSWORD=$(generatePassword) 10 | JIGASI_XMPP_PASSWORD=$(generatePassword) 11 | JIBRI_RECORDER_PASSWORD=$(generatePassword) 12 | JIBRI_XMPP_PASSWORD=$(generatePassword) 13 | 14 | sed -i.bak \ 15 | -e "s#JICOFO_COMPONENT_SECRET=.*#JICOFO_COMPONENT_SECRET=${JICOFO_COMPONENT_SECRET}#g" \ 16 | -e "s#JICOFO_AUTH_PASSWORD=.*#JICOFO_AUTH_PASSWORD=${JICOFO_AUTH_PASSWORD}#g" \ 17 | -e "s#JVB_AUTH_PASSWORD=.*#JVB_AUTH_PASSWORD=${JVB_AUTH_PASSWORD}#g" \ 18 | -e "s#JIGASI_XMPP_PASSWORD=.*#JIGASI_XMPP_PASSWORD=${JIGASI_XMPP_PASSWORD}#g" \ 19 | -e "s#JIBRI_RECORDER_PASSWORD=.*#JIBRI_RECORDER_PASSWORD=${JIBRI_RECORDER_PASSWORD}#g" \ 20 | -e "s#JIBRI_XMPP_PASSWORD=.*#JIBRI_XMPP_PASSWORD=${JIBRI_XMPP_PASSWORD}#g" \ 21 | "$(dirname "$0")/.env" 22 | -------------------------------------------------------------------------------- /jicofo/rootfs/etc/cont-init.d/10-config: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | if [[ -z $JICOFO_COMPONENT_SECRET || -z $JICOFO_AUTH_PASSWORD ]]; then 4 | echo 'FATAL ERROR: Jicofo component secret and auth password must be set' 5 | exit 1 6 | fi 7 | 8 | OLD_JICOFO_COMPONENT_SECRET=s3cr37 9 | if [[ "$JICOFO_COMPONENT_SECRET" == "$OLD_JICOFO_COMPONENT_SECRET" ]]; then 10 | echo 'FATAL ERROR: Jicofo component secret must be changed, check the README' 11 | exit 1 12 | fi 13 | 14 | OLD_JICOFO_AUTH_PASSWORD=passw0rd 15 | if [[ "$JICOFO_AUTH_PASSWORD" == "$OLD_JICOFO_AUTH_PASSWORD" ]]; then 16 | echo 'FATAL ERROR: Jicofo auth password must be changed, check the README' 17 | exit 1 18 | fi 19 | 20 | if [[ ! -f /config/sip-communicator.properties ]]; then 21 | tpl /defaults/sip-communicator.properties > /config/sip-communicator.properties 22 | fi 23 | 24 | if [[ ! -f /config/logging.properties ]]; then 25 | cp /defaults/logging.properties /config 26 | fi 27 | 28 | chown -R jicofo:jitsi /config 29 | -------------------------------------------------------------------------------- /jibri.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | jibri: 5 | image: jitsi/jibri:latest 6 | restart: ${RESTART_POLICY} 7 | volumes: 8 | - ${CONFIG}/jibri:/config:Z 9 | - /dev/shm:/dev/shm 10 | cap_add: 11 | - SYS_ADMIN 12 | - NET_BIND_SERVICE 13 | devices: 14 | - /dev/snd:/dev/snd 15 | environment: 16 | - XMPP_AUTH_DOMAIN 17 | - XMPP_INTERNAL_MUC_DOMAIN 18 | - XMPP_RECORDER_DOMAIN 19 | - XMPP_SERVER 20 | - XMPP_DOMAIN 21 | - JIBRI_XMPP_USER 22 | - JIBRI_XMPP_PASSWORD 23 | - JIBRI_BREWERY_MUC 24 | - JIBRI_RECORDER_USER 25 | - JIBRI_RECORDER_PASSWORD 26 | - JIBRI_RECORDING_DIR 27 | - JIBRI_FINALIZE_RECORDING_SCRIPT_PATH 28 | - JIBRI_STRIP_DOMAIN_JID 29 | - JIBRI_LOGS_DIR 30 | - DISPLAY=:0 31 | - TZ 32 | depends_on: 33 | - jicofo 34 | networks: 35 | meet.jitsi: 36 | 37 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | FORCE_REBUILD ?= 0 2 | JITSI_RELEASE ?= stable 3 | JITSI_BUILD ?= latest 4 | JITSI_REPO ?= jitsi 5 | JITSI_SERVICES ?= base base-java web prosody jicofo jvb jigasi etherpad jibri 6 | 7 | BUILD_ARGS := --build-arg JITSI_REPO=$(JITSI_REPO) 8 | ifeq ($(FORCE_REBUILD), 1) 9 | BUILD_ARGS := $(BUILD_ARGS) --no-cache 10 | endif 11 | 12 | 13 | all: build-all 14 | 15 | release: tag-all push-all 16 | 17 | build: 18 | $(MAKE) BUILD_ARGS="$(BUILD_ARGS)" JITSI_REPO="$(JITSI_REPO)" JITSI_RELEASE="$(JITSI_RELEASE)" -C $(JITSI_SERVICE) build 19 | 20 | tag: 21 | docker tag $(JITSI_REPO)/$(JITSI_SERVICE):latest $(JITSI_REPO)/$(JITSI_SERVICE):$(JITSI_BUILD) 22 | 23 | push: 24 | docker push $(JITSI_REPO)/$(JITSI_SERVICE):latest 25 | docker push $(JITSI_REPO)/$(JITSI_SERVICE):$(JITSI_BUILD) 26 | 27 | %-all: 28 | @$(foreach SERVICE, $(JITSI_SERVICES), $(MAKE) --no-print-directory JITSI_SERVICE=$(SERVICE) $(subst -all,;,$@)) 29 | 30 | clean: 31 | docker-compose stop 32 | docker-compose rm 33 | docker network prune 34 | 35 | prepare: 36 | docker pull debian:stretch-slim 37 | FORCE_REBUILD=1 $(MAKE) 38 | 39 | .PHONY: all build tag push clean prepare release 40 | -------------------------------------------------------------------------------- /prosody/rootfs/defaults/saslauthd.conf: -------------------------------------------------------------------------------- 1 | {{ if eq (.Env.AUTH_TYPE | default "internal") "ldap" }} 2 | ldap_servers: {{ .Env.LDAP_URL }} 3 | ldap_search_base: {{ .Env.LDAP_BASE }} 4 | {{ if .Env.LDAP_BINDDN | default "" }} 5 | ldap_bind_dn: {{ .Env.LDAP_BINDDN }} 6 | ldap_bind_pw: {{ .Env.LDAP_BINDPW }} 7 | {{ end }} 8 | ldap_filter: {{ .Env.LDAP_FILTER | default "uid=%u" }} 9 | ldap_version: {{ .Env.LDAP_VERSION | default "3" }} 10 | ldap_auth_method: {{ .Env.LDAP_AUTH_METHOD | default "bind" }} 11 | {{ if .Env.LDAP_USE_TLS | default "0" | toBool }} 12 | ldap_tls_key: /config/certs/{{ .Env.XMPP_DOMAIN }}.key 13 | ldap_tls_cert: /config/certs/{{ .Env.XMPP_DOMAIN }}.crt 14 | {{ if .Env.LDAP_TLS_CHECK_PEER | default "0" | toBool }} 15 | ldap_tls_check_peer: yes 16 | ldap_tls_cacert_file: {{ .Env.LDAP_TLS_CACERT_FILE | default "/etc/ssl/certs/ca-certificates.crt" }} 17 | ldap_tls_cacert_dir: {{ .Env.LDAP_TLS_CACERT_DIR | default "/etc/ssl/certs" }} 18 | {{ end }} 19 | {{ if .Env.LDAP_TLS_CIPHERS }} 20 | ldap_tls_ciphers: {{ .Env.LDAP_TLS_CIPHERS }} 21 | {{ end }} 22 | {{ end }} 23 | {{ end }} 24 | {{ if .Env.LDAP_START_TLS | default "0" | toBool }} 25 | ldap_start_tls: yes 26 | {{ end }} 27 | -------------------------------------------------------------------------------- /web/rootfs/defaults/ssl.conf: -------------------------------------------------------------------------------- 1 | # session settings 2 | ssl_session_timeout 1d; 3 | ssl_session_cache shared:SSL:50m; 4 | ssl_session_tickets off; 5 | 6 | # ssl certs 7 | {{ if .Env.ENABLE_LETSENCRYPT | default "0" | toBool }} 8 | ssl_certificate /etc/letsencrypt/live/{{ .Env.LETSENCRYPT_DOMAIN }}/fullchain.pem; 9 | ssl_certificate_key /etc/letsencrypt/live/{{ .Env.LETSENCRYPT_DOMAIN }}/privkey.pem; 10 | {{ else }} 11 | ssl_certificate /config/keys/cert.crt; 12 | ssl_certificate_key /config/keys/cert.key; 13 | {{ end }} 14 | 15 | # protocols 16 | ssl_protocols TLSv1.2; 17 | ssl_prefer_server_ciphers on; 18 | ssl_ecdh_curve secp384r1; 19 | ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDH+CHACHA20:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK; 20 | 21 | # headers 22 | add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; 23 | add_header X-Content-Type-Options nosniff; 24 | add_header X-XSS-Protection "1; mode=block"; 25 | -------------------------------------------------------------------------------- /jicofo/rootfs/defaults/sip-communicator.properties: -------------------------------------------------------------------------------- 1 | org.jitsi.jicofo.ALWAYS_TRUST_MODE_ENABLED=true 2 | org.jitsi.jicofo.BRIDGE_MUC={{ .Env.JVB_BREWERY_MUC }}@{{ .Env.XMPP_INTERNAL_MUC_DOMAIN }} 3 | 4 | {{ if and .Env.JIBRI_BREWERY_MUC .Env.JIBRI_PENDING_TIMEOUT }} 5 | org.jitsi.jicofo.jibri.BREWERY={{ .Env.JIBRI_BREWERY_MUC}}@{{ .Env.XMPP_INTERNAL_MUC_DOMAIN }} 6 | org.jitsi.jicofo.jibri.PENDING_TIMEOUT={{ .Env.JIBRI_PENDING_TIMEOUT }} 7 | {{ end }} 8 | 9 | {{ if and .Env.JIGASI_SIP_URI .Env.JIGASI_BREWERY_MUC }} 10 | org.jitsi.jicofo.jigasi.BREWERY={{ .Env.JIGASI_BREWERY_MUC}}@{{ .Env.XMPP_INTERNAL_MUC_DOMAIN }} 11 | {{ end }} 12 | 13 | {{ if .Env.JICOFO_RESERVATION_REST_BASE_URL }} 14 | org.jitsi.impl.reservation.rest.BASE_URL={{ .Env.JICOFO_RESERVATION_REST_BASE_URL }} 15 | {{ end }} 16 | 17 | {{ if .Env.JICOFO_ENABLE_HEALTH_CHECKS | default "0" | toBool }} 18 | org.jitsi.jicofo.health.ENABLE_HEALTH_CHECKS=true 19 | {{ end }} 20 | 21 | {{ $ENABLE_AUTH := .Env.ENABLE_AUTH | default "0" | toBool }} 22 | {{ $AUTH_TYPE := .Env.AUTH_TYPE | default "internal" }} 23 | 24 | {{ if $ENABLE_AUTH }} 25 | {{ if eq $AUTH_TYPE "jwt" }} 26 | org.jitsi.jicofo.auth.URL=EXT_JWT:{{ .Env.XMPP_DOMAIN }} 27 | {{ else }} 28 | org.jitsi.jicofo.auth.URL=XMPP:{{ .Env.XMPP_DOMAIN }} 29 | {{ end }} 30 | {{ end }} 31 | -------------------------------------------------------------------------------- /base/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch-slim 2 | 3 | ARG JITSI_RELEASE=stable 4 | 5 | ENV S6_BEHAVIOUR_IF_STAGE2_FAILS=2 6 | 7 | ADD https://github.com/just-containers/s6-overlay/releases/download/v1.22.1.0/s6-overlay-amd64.tar.gz /tmp/s6-overlay.tar.gz 8 | ADD https://download.jitsi.org/jitsi-key.gpg.key /tmp/jitsi.key 9 | ADD https://github.com/subchen/frep/releases/download/v1.3.5/frep-1.3.5-linux-amd64 /usr/bin/frep 10 | 11 | COPY rootfs / 12 | 13 | RUN \ 14 | tar xfz /tmp/s6-overlay.tar.gz -C / && \ 15 | rm -f /tmp/*.tar.gz && \ 16 | apt-dpkg-wrap apt-get update && \ 17 | apt-dpkg-wrap apt-get install -y apt-transport-https apt-utils ca-certificates gnupg && \ 18 | apt-key add /tmp/jitsi.key && \ 19 | rm -f /tmp/jitsi.key && \ 20 | echo "deb https://download.jitsi.org $JITSI_RELEASE/" > /etc/apt/sources.list.d/jitsi.list && \ 21 | echo "deb http://ftp.debian.org/debian stretch-backports main" > /etc/apt/sources.list.d/backports.list && \ 22 | apt-dpkg-wrap apt-get update && \ 23 | apt-dpkg-wrap apt-get dist-upgrade -y && \ 24 | apt-cleanup && \ 25 | chmod +x /usr/bin/frep 26 | 27 | RUN \ 28 | [ "$JITSI_RELEASE" = "unstable" ] && \ 29 | apt-dpkg-wrap apt-get update && \ 30 | apt-dpkg-wrap apt-get install -y jq procps curl vim iputils-ping net-tools && \ 31 | apt-cleanup || \ 32 | true 33 | 34 | ENTRYPOINT [ "/init" ] 35 | -------------------------------------------------------------------------------- /examples/kubernetes/README.md: -------------------------------------------------------------------------------- 1 | # Install guide for kubernetes 2 | 3 | This guide will deploy jitsi in the most simple way: as several containers in a single pod. This is enough to start in case your hardware is enough. If you need to scale components to severa instance, you'll have to modify it to use several services and pods. 4 | 5 | Create a namespace to deploy jitsi to: 6 | 7 | `kubectl create namespace jitsi` 8 | 9 | Add the secret with secret values (replace `...` with some random strings): 10 | 11 | `kubectl create secret generic jitsi-config -n jitsi --from-literal=JICOFO_COMPONENT_SECRET=... --from-literal=JICOFO_AUTH_PASSWORD=... --from-literal=JVB_AUTH_PASSWORD=... ` 12 | 13 | Deploy the service to listen for JVB UDP traffic on all cluster nodes port 30300: 14 | 15 | `kubectl create -f jvb-service.yaml` 16 | 17 | Now we can deploy the rest of the application. First modify the `DOCKER_HOST_ADDRESS` env value in deployment.yaml to point to one of nodes in your cluster (or load-balancer for all nodes if you have one), and then deploy it: 18 | 19 | `kubectl create -f deployment.yaml` 20 | 21 | To expose the webapp, we can use Ingress (replace the `host` value with your actual hostname): 22 | 23 | `kubectl create -f web-service.yaml` 24 | 25 | You can either use "https" or "http" service port, depending on whether your ingress allows self-signed certs. 26 | 27 | -------------------------------------------------------------------------------- /jvb/rootfs/defaults/sip-communicator.properties: -------------------------------------------------------------------------------- 1 | org.jitsi.videobridge.SINGLE_PORT_HARVESTER_PORT={{ .Env.JVB_PORT }} 2 | org.jitsi.videobridge.DISABLE_TCP_HARVESTER={{ .Env.JVB_TCP_HARVESTER_DISABLED }} 3 | org.jitsi.videobridge.TCP_HARVESTER_PORT={{ .Env.JVB_TCP_PORT }} 4 | {{ if .Env.JVB_STUN_SERVERS }} 5 | org.ice4j.ice.harvest.STUN_MAPPING_HARVESTER_ADDRESSES={{ .Env.JVB_STUN_SERVERS }} 6 | {{ end }} 7 | {{ $JVB_TCP_PORT := .Env.JVB_TCP_PORT | default "4443" }} 8 | {{ $JVB_TCP_MAPPED_PORT := .Env.JVB_TCP_MAPPED_PORT | default $JVB_TCP_PORT }} 9 | {{ if not (eq $JVB_TCP_PORT $JVB_TCP_MAPPED_PORT) }} 10 | org.jitsi.videobridge.TCP_HARVESTER_MAPPED_PORT={{ $JVB_TCP_MAPPED_PORT }} 11 | {{ end }} 12 | 13 | org.jitsi.videobridge.xmpp.user.shard.HOSTNAME={{ .Env.XMPP_SERVER }} 14 | org.jitsi.videobridge.xmpp.user.shard.DOMAIN={{ .Env.XMPP_AUTH_DOMAIN }} 15 | org.jitsi.videobridge.xmpp.user.shard.USERNAME={{ .Env.JVB_AUTH_USER }} 16 | org.jitsi.videobridge.xmpp.user.shard.PASSWORD={{ .Env.JVB_AUTH_PASSWORD }} 17 | org.jitsi.videobridge.xmpp.user.shard.MUC_JIDS={{ .Env.JVB_BREWERY_MUC }}@{{ .Env.XMPP_INTERNAL_MUC_DOMAIN }} 18 | org.jitsi.videobridge.xmpp.user.shard.MUC_NICKNAME={{ .Env.HOSTNAME }} 19 | org.jitsi.videobridge.xmpp.user.shard.DISABLE_CERTIFICATE_VERIFICATION=true 20 | 21 | org.jitsi.videobridge.ENABLE_STATISTICS=true 22 | org.jitsi.videobridge.STATISTICS_TRANSPORT=muc 23 | org.jitsi.videobridge.STATISTICS_INTERVAL=5000 24 | -------------------------------------------------------------------------------- /web/rootfs/defaults/nginx.conf: -------------------------------------------------------------------------------- 1 | user www-data; 2 | worker_processes 4; 3 | pid /run/nginx.pid; 4 | include /etc/nginx/modules-enabled/*.conf; 5 | 6 | events { 7 | worker_connections 768; 8 | # multi_accept on; 9 | } 10 | 11 | http { 12 | 13 | ## 14 | # Basic Settings 15 | ## 16 | 17 | sendfile on; 18 | tcp_nopush on; 19 | tcp_nodelay on; 20 | keepalive_timeout 65; 21 | types_hash_max_size 2048; 22 | server_tokens off; 23 | 24 | # server_names_hash_bucket_size 64; 25 | # server_name_in_redirect off; 26 | 27 | client_max_body_size 0; 28 | 29 | include /etc/nginx/mime.types; 30 | types { 31 | # add support for wasm MIME type, that is required by specification and it is not part of default mime.types file 32 | application/wasm wasm; 33 | } 34 | default_type application/octet-stream; 35 | 36 | ## 37 | # Logging Settings 38 | ## 39 | 40 | access_log /dev/stdout; 41 | error_log /dev/stderr; 42 | 43 | ## 44 | # Gzip Settings 45 | ## 46 | 47 | gzip on; 48 | gzip_types text/plain text/css application/javascript application/json; 49 | gzip_vary on; 50 | gzip_min_length 860; 51 | 52 | # gzip_vary on; 53 | # gzip_proxied any; 54 | # gzip_comp_level 6; 55 | # gzip_buffers 16 8k; 56 | # gzip_http_version 1.1; 57 | # gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 58 | 59 | ## 60 | # Virtual Host Configs 61 | ## 62 | include /config/nginx/site-confs/*; 63 | } 64 | 65 | 66 | daemon off; 67 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Don't start a release if the tree is dirty 6 | # 7 | 8 | if [[ ! -z $(git status -s) ]]; then 9 | echo "Git tree is not clean, aborting release!" 10 | exit 1 11 | fi 12 | 13 | # Get version and branch (we only do stable for now) 14 | # 15 | 16 | V="$1" 17 | RELEASE="${2:-stable}" 18 | 19 | if [[ -z $V ]]; then 20 | echo "A version must be specified!" 21 | exit 1 22 | fi 23 | 24 | VERSION="${RELEASE}-${V}" 25 | echo "Releasing ${VERSION}" 26 | 27 | if git rev-parse "${VERSION}" >/dev/null 2>&1; then 28 | echo "Tag for such version already exists!" 29 | exit 1 30 | fi 31 | 32 | # Prepare changelog 33 | # 34 | 35 | LAST_VERSION=$(git describe --tags --abbrev=0) 36 | CHANGES=$(git log --oneline --no-decorate --no-merges ${LAST_VERSION}..HEAD --pretty=format:"%x2a%x20%h%x20%s") 37 | 38 | echo "Changelog:" 39 | echo "$CHANGES" 40 | 41 | echo -e "## ${VERSION}\n\nBased on ${RELEASE} release ${V}.\n\n${CHANGES}\n" > tmp 42 | cat CHANGELOG.md >> tmp 43 | mv tmp CHANGELOG.md 44 | 45 | # Set specific image tags in compose files 46 | # 47 | 48 | sed -i "" -e "s/latest/${VERSION}/" *.yml 49 | 50 | # Commit all changes and tag the repo 51 | # 52 | 53 | git commit -a -m "release: ${VERSION}" -m "${CHANGES}" 54 | git tag -a "${VERSION}" -m "${CHANGES}" 55 | 56 | # Tag Docker images and push them to DockerHub 57 | # 58 | 59 | JITSI_BUILD=${VERSION} make release 60 | 61 | # Revert back to "latest" for development 62 | # 63 | 64 | sed -i "" -e "s/${VERSION}/latest/" *.yml 65 | 66 | git commit -a -m "misc: working on latest" 67 | 68 | # Push all changes and tags 69 | # 70 | 71 | git push 72 | git push --tags 73 | -------------------------------------------------------------------------------- /jigasi.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | # SIP gateway (audio) 5 | jigasi: 6 | image: jitsi/jigasi:latest 7 | restart: ${RESTART_POLICY} 8 | ports: 9 | - '${JIGASI_PORT_MIN}-${JIGASI_PORT_MAX}:${JIGASI_PORT_MIN}-${JIGASI_PORT_MAX}/udp' 10 | volumes: 11 | - ${CONFIG}/jigasi:/config:Z 12 | - ${CONFIG}/transcripts:/tmp/transcripts:Z 13 | environment: 14 | - ENABLE_AUTH 15 | - XMPP_AUTH_DOMAIN 16 | - XMPP_INTERNAL_MUC_DOMAIN 17 | - XMPP_SERVER 18 | - XMPP_DOMAIN 19 | - PUBLIC_URL 20 | - JIGASI_SIP_URI 21 | - JIGASI_SIP_PASSWORD 22 | - JIGASI_SIP_SERVER 23 | - JIGASI_SIP_PORT 24 | - JIGASI_SIP_TRANSPORT 25 | - JIGASI_XMPP_USER 26 | - JIGASI_XMPP_PASSWORD 27 | - JIGASI_BREWERY_MUC 28 | - JIGASI_PORT_MIN 29 | - JIGASI_PORT_MAX 30 | - JIGASI_HEALTH_CHECK_SIP_URI 31 | - JIGASI_HEALTH_CHECK_INTERVAL 32 | - JIGASI_SIP_KEEP_ALIVE_METHOD 33 | - JIGASI_ENABLE_SDES_SRTP 34 | - ENABLE_TRANSCRIPTIONS 35 | - JIGASI_TRANSCRIBER_ADVERTISE_URL 36 | - JIGASI_TRANSCRIBER_RECORD_AUDIO 37 | - JIGASI_TRANSCRIBER_SEND_TXT 38 | - GC_PROJECT_ID 39 | - GC_PRIVATE_KEY_ID 40 | - GC_PRIVATE_KEY 41 | - GC_CLIENT_EMAIL 42 | - GC_CLIENT_ID 43 | - GC_CLIENT_CERT_URL 44 | - TZ 45 | depends_on: 46 | - prosody 47 | networks: 48 | meet.jitsi: 49 | -------------------------------------------------------------------------------- /web/rootfs/defaults/meet.conf: -------------------------------------------------------------------------------- 1 | server_name _; 2 | 3 | client_max_body_size 0; 4 | 5 | root /usr/share/jitsi-meet; 6 | 7 | # ssi on with javascript for multidomain variables in config.js 8 | ssi on; 9 | ssi_types application/x-javascript application/javascript; 10 | 11 | index index.html index.htm; 12 | error_page 404 /static/404.html; 13 | 14 | location = /config.js { 15 | alias /config/config.js; 16 | } 17 | 18 | location = /interface_config.js { 19 | alias /config/interface_config.js; 20 | } 21 | 22 | location = /external_api.js { 23 | alias /usr/share/jitsi-meet/libs/external_api.min.js; 24 | } 25 | 26 | # ensure all static content can always be found first 27 | location ~ ^/(libs|css|static|images|fonts|lang|sounds|connection_optimization|.well-known)/(.*)$ 28 | { 29 | add_header 'Access-Control-Allow-Origin' '*'; 30 | alias /usr/share/jitsi-meet/$1/$2; 31 | } 32 | 33 | # BOSH 34 | location = /http-bind { 35 | proxy_pass {{ .Env.XMPP_BOSH_URL_BASE }}/http-bind; 36 | proxy_set_header X-Forwarded-For $remote_addr; 37 | proxy_set_header Host {{ .Env.XMPP_DOMAIN }}; 38 | } 39 | 40 | location ~ ^/([^/?&:'"]+)$ { 41 | try_files $uri @root_path; 42 | } 43 | 44 | location @root_path { 45 | rewrite ^/(.*)$ / break; 46 | } 47 | 48 | {{ if .Env.ETHERPAD_URL_BASE }} 49 | # Etherpad-lite 50 | location /etherpad/ { 51 | proxy_http_version 1.1; 52 | proxy_set_header Upgrade $http_upgrade; 53 | proxy_set_header Connection 'upgrade'; 54 | proxy_set_header Host $host; 55 | proxy_cache_bypass $http_upgrade; 56 | 57 | proxy_pass {{ .Env.ETHERPAD_URL_BASE }}/; 58 | proxy_set_header X-Forwarded-For $remote_addr; 59 | proxy_buffering off; 60 | proxy_set_header Host {{ .Env.XMPP_DOMAIN }}; 61 | } 62 | {{ end }} 63 | -------------------------------------------------------------------------------- /prosody/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG JITSI_REPO=jitsi 2 | FROM ${JITSI_REPO}/base 3 | 4 | ADD https://prosody.im/files/prosody-debian-packages.key /tmp/prosody.key 5 | 6 | RUN \ 7 | apt-key add /tmp/prosody.key \ 8 | && rm -f /tmp/prosody.key \ 9 | && echo "deb http://packages.prosody.im/debian stretch main" > /etc/apt/sources.list.d/prosody.list \ 10 | && apt-dpkg-wrap apt-get update \ 11 | && apt-dpkg-wrap apt-get install -y prosody \ 12 | && apt-dpkg-wrap apt-get install -t stretch-backports -y \ 13 | liblua5.2-dev \ 14 | sasl2-bin \ 15 | libsasl2-modules-ldap \ 16 | libsasl2-dev \ 17 | libssl1.0-dev \ 18 | lua-basexx \ 19 | lua-ldap \ 20 | lua-sec \ 21 | luarocks \ 22 | git \ 23 | gcc \ 24 | patch \ 25 | && luarocks install cyrussasl 1.1.0-1 \ 26 | && luarocks install lua-cjson 2.1.0-1 \ 27 | && luarocks install luajwtjitsi 1.3-7 \ 28 | && luarocks install net-url 0.9-1 \ 29 | && apt-dpkg-wrap apt-get remove -t stretch-backports -y \ 30 | git \ 31 | gcc \ 32 | luarocks \ 33 | libsasl2-dev \ 34 | libssl1.0-dev \ 35 | liblua5.2-dev \ 36 | && apt-cleanup \ 37 | && rm -rf /etc/prosody /var/cache/apt 38 | 39 | RUN \ 40 | apt-dpkg-wrap apt-get update \ 41 | && apt-dpkg-wrap apt-get -d install -y jitsi-meet-prosody \ 42 | && dpkg -x /var/cache/apt/archives/jitsi-meet-prosody*.deb /tmp/pkg \ 43 | && mv /tmp/pkg/usr/share/jitsi-meet/prosody-plugins /prosody-plugins \ 44 | && apt-cleanup \ 45 | && rm -rf /tmp/pkg /var/cache/apt 46 | 47 | RUN patch -d /usr/lib/prosody/modules/muc -p0 < /prosody-plugins/muc_owner_allow_kick.patch 48 | 49 | COPY rootfs/ / 50 | 51 | EXPOSE 5222 5269 5347 5280 52 | 53 | VOLUME ["/config", "/prosody-plugins-custom"] 54 | -------------------------------------------------------------------------------- /jibri/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG JITSI_REPO=jitsi 2 | FROM ${JITSI_REPO}/base-java 3 | 4 | #ARG CHROME_RELEASE=latest 5 | #ARG CHROMEDRIVER_MAJOR_RELEASE=latest 6 | ARG CHROME_RELEASE=78.0.3904.97 7 | ARG CHROMEDRIVER_MAJOR_RELEASE=78 8 | 9 | RUN \ 10 | apt-dpkg-wrap apt-get update \ 11 | && apt-dpkg-wrap apt-get install -y jibri libgl1-mesa-dri \ 12 | && apt-cleanup 13 | 14 | RUN \ 15 | [ "${CHROME_RELEASE}" = "latest" ] \ 16 | && curl -4s https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ 17 | && echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list \ 18 | && apt-dpkg-wrap apt-get update \ 19 | && apt-dpkg-wrap apt-get install -y google-chrome-stable \ 20 | && apt-cleanup \ 21 | || true 22 | 23 | RUN \ 24 | [ "${CHROME_RELEASE}" != "latest" ] \ 25 | && curl -4so /tmp/google-chrome-stable_${CHROME_RELEASE}-1_amd64.deb http://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${CHROME_RELEASE}-1_amd64.deb \ 26 | && apt-dpkg-wrap apt-get update \ 27 | && apt-dpkg-wrap apt-get install -y /tmp/google-chrome-stable_${CHROME_RELEASE}-1_amd64.deb \ 28 | && apt-cleanup \ 29 | || true 30 | 31 | RUN \ 32 | [ "${CHROMEDRIVER_MAJOR_RELEASE}" = "latest" ] \ 33 | && CHROMEDRIVER_RELEASE="$(curl -4Ls https://chromedriver.storage.googleapis.com/LATEST_RELEASE)" \ 34 | || CHROMEDRIVER_RELEASE="$(curl -4Ls https://chromedriver.storage.googleapis.com/LATEST_RELEASE_${CHROMEDRIVER_MAJOR_RELEASE})" \ 35 | && curl -4Ls https://chromedriver.storage.googleapis.com/${CHROMEDRIVER_RELEASE}/chromedriver_linux64.zip \ 36 | | zcat >> /usr/bin/chromedriver \ 37 | && chmod +x /usr/bin/chromedriver \ 38 | && chromedriver --version 39 | 40 | RUN \ 41 | apt-dpkg-wrap apt-get update \ 42 | && apt-dpkg-wrap apt-get install -y jitsi-upload-integrations jq \ 43 | && apt-cleanup 44 | 45 | COPY rootfs/ / 46 | 47 | VOLUME /config 48 | 49 | -------------------------------------------------------------------------------- /jibri/rootfs/defaults/logging.properties: -------------------------------------------------------------------------------- 1 | handlers = java.util.logging.FileHandler, java.util.logging.ConsoleHandler 2 | 3 | java.util.logging.FileHandler.level = FINE 4 | java.util.logging.FileHandler.pattern = {{ .Env.JIBRI_LOGS_DIR }}/log.%g.txt 5 | java.util.logging.FileHandler.formatter = net.java.sip.communicator.util.ScLogFormatter 6 | java.util.logging.FileHandler.count = 10 7 | java.util.logging.FileHandler.limit = 10000000 8 | 9 | org.jitsi.jibri.capture.ffmpeg.util.FfmpegFileHandler.level = FINE 10 | org.jitsi.jibri.capture.ffmpeg.util.FfmpegFileHandler.pattern = {{ .Env.JIBRI_LOGS_DIR }}/ffmpeg.%g.txt 11 | org.jitsi.jibri.capture.ffmpeg.util.FfmpegFileHandler.formatter = net.java.sip.communicator.util.ScLogFormatter 12 | org.jitsi.jibri.capture.ffmpeg.util.FfmpegFileHandler.count = 10 13 | org.jitsi.jibri.capture.ffmpeg.util.FfmpegFileHandler.limit = 10000000 14 | 15 | org.jitsi.jibri.sipgateway.pjsua.util.PjsuaFileHandler.level = FINE 16 | org.jitsi.jibri.sipgateway.pjsua.util.PjsuaFileHandler.pattern = {{ .Env.JIBRI_LOGS_DIR }}/pjsua.%g.txt 17 | org.jitsi.jibri.sipgateway.pjsua.util.PjsuaFileHandler.formatter = net.java.sip.communicator.util.ScLogFormatter 18 | org.jitsi.jibri.sipgateway.pjsua.util.PjsuaFileHandler.count = 10 19 | org.jitsi.jibri.sipgateway.pjsua.util.PjsuaFileHandler.limit = 10000000 20 | 21 | org.jitsi.jibri.selenium.util.BrowserFileHandler.level = FINE 22 | org.jitsi.jibri.selenium.util.BrowserFileHandler.pattern = {{ .Env.JIBRI_LOGS_DIR }}/browser.%g.txt 23 | org.jitsi.jibri.selenium.util.BrowserFileHandler.formatter = net.java.sip.communicator.util.ScLogFormatter 24 | org.jitsi.jibri.selenium.util.BrowserFileHandler.count = 10 25 | org.jitsi.jibri.selenium.util.BrowserFileHandler.limit = 10000000 26 | 27 | java.util.logging.ConsoleHandler.level = FINE 28 | java.util.logging.ConsoleHandler.formatter = net.java.sip.communicator.util.ScLogFormatter 29 | 30 | org.jitsi.level = FINE 31 | 32 | org.glassfish.level = INFO 33 | org.osgi.level = INFO 34 | -------------------------------------------------------------------------------- /jigasi/rootfs/etc/cont-init.d/10-config: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | if [[ -z $JIGASI_XMPP_PASSWORD ]]; then 4 | echo 'FATAL ERROR: Jigasi auth password must be set' 5 | exit 1 6 | fi 7 | 8 | OLD_JIGASI_XMPP_PASSWORD=passw0rd 9 | if [[ "$JIGASI_XMPP_PASSWORD" == "$OLD_JIGASI_XMPP_PASSWORD" ]]; then 10 | echo 'FATAL ERROR: Jigasi auth password must be changed, check the README' 11 | exit 1 12 | fi 13 | 14 | if [[ ! -f /config/sip-communicator.properties ]]; then 15 | tpl /defaults/sip-communicator.properties > /config/sip-communicator.properties 16 | fi 17 | 18 | if [[ ! -f /config/logging.properties ]]; then 19 | cp /defaults/logging.properties /config 20 | fi 21 | 22 | mkdir -pm777 /tmp/transcripts 23 | chown jigasi:jitsi /tmp/transcripts 24 | 25 | # Create Google Cloud Credentials 26 | if [[ $ENABLE_TRANSCRIPTIONS -eq 1 || $ENABLE_TRANSCRIPTIONS == "true" ]] && [[ ! -f /config/key.json ]]; then 27 | if [[ -z $GC_PROJECT_ID || -z $GC_PRIVATE_KEY_ID || -z $GC_PRIVATE_KEY || -z $GC_CLIENT_EMAIL || -z $GC_CLIENT_ID || -z $GC_CLIENT_CERT_URL ]]; then 28 | echo 'Transcriptions: One or more environment variables are undefined' 29 | exit 1 30 | fi 31 | 32 | jq -n \ 33 | --arg GC_PROJECT_ID "$GC_PROJECT_ID" \ 34 | --arg GC_PRIVATE_KEY_ID "$GC_PRIVATE_KEY_ID" \ 35 | --arg GC_PRIVATE_KEY "$GC_PRIVATE_KEY" \ 36 | --arg GC_CLIENT_EMAIL "$GC_CLIENT_EMAIL" \ 37 | --arg GC_CLIENT_ID "$GC_CLIENT_ID" \ 38 | --arg GC_CLIENT_CERT_URL "$GC_CLIENT_CERT_URL" \ 39 | '{ 40 | type: "service_account", 41 | project_id: $GC_PROJECT_ID, 42 | private_key_id: $GC_PRIVATE_KEY_ID, 43 | private_key: $GC_PRIVATE_KEY, 44 | client_email: $GC_CLIENT_EMAIL, 45 | client_id: $GC_CLIENT_ID, 46 | auth_uri: "https://accounts.google.com/o/oauth2/auth", 47 | token_uri: "https://oauth2.googleapis.com/token", 48 | auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs", 49 | client_x509_cert_url: $GC_CLIENT_CERT_URL 50 | }' \ 51 | > /config/key.json 52 | fi 53 | -------------------------------------------------------------------------------- /jibri/rootfs/etc/cont-init.d/10-config: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | if [[ -z $JIBRI_RECORDER_PASSWORD || -z $JIBRI_XMPP_PASSWORD ]]; then 4 | echo 'FATAL ERROR: Jibri recorder password and auth password must be set' 5 | exit 1 6 | fi 7 | 8 | OLD_JIBRI_RECORDER_PASSWORD=passw0rd 9 | if [[ "$JIBRI_RECORDER_PASSWORD" == "$OLD_JIBRI_RECORDER_PASSWORD" ]]; then 10 | echo 'FATAL ERROR: Jibri recorder password must be changed, check the README' 11 | exit 1 12 | fi 13 | 14 | OLD_JIBRI_XMPP_PASSWORD=passw0rd 15 | if [[ "$JIBRI_XMPP_PASSWORD" == "$OLD_JIBRI_XMPP_PASSWORD" ]]; then 16 | echo 'FATAL ERROR: Jibri auth password must be changed, check the README' 17 | exit 1 18 | fi 19 | 20 | # DISPLAY is necessary for start 21 | [ -z "${DISPLAY}" ] \ 22 | && ( echo -e "\e[31mERROR: Please set DISPLAY variable.\e[39m"; kill 1; exit 1 ) 23 | 24 | # check loaded snd_aloop module and exit if is not loaded on the host 25 | [ -z "$(lsmod | grep -om1 snd_aloop)" ] \ 26 | && ( echo -e "\e[31mERROR: Please load snd-aloop module on the docker host.\e[39m"; kill 1; exit 1 ) 27 | 28 | # get host's audio group id 29 | host_audio_group="$(stat -c %g /dev/snd/pcmC0D0p 2>/dev/null)" 30 | 31 | # audio group is not found. Has it been run without jibri.yml? 32 | [ -z "${host_audio_group}" ] \ 33 | && ( echo -e "\e[31mERROR: Binding /dev/snd is not found. Please check that you run docker-compose with -f jibri.yml.\e[39m"; kill 1; exit 1 ) 34 | 35 | # try to create group with this id. If group with the id already exists, just skip 36 | groupadd -g ${host_audio_group} jibri-audio >/dev/null 2>&1 37 | # include user to the group by id 38 | usermod -aG ${host_audio_group} jibri 39 | 40 | # script for finalizing must have executing bit. 41 | [ ! -z "${JIBRI_FINALIZE_RECORDING_SCRIPT_PATH}" ] \ 42 | && [ ! -x "${JIBRI_FINALIZE_RECORDING_SCRIPT_PATH}" ] \ 43 | && chmod +x ${JIBRI_FINALIZE_RECORDING_SCRIPT_PATH} 44 | 45 | # set rundom jibri nickname for the instance if is not set 46 | [ -z "${JIBRI_INSTANCE_ID}" ] && export JIBRI_INSTANCE_ID=$(date +%N) 47 | 48 | # always recreate configs 49 | tpl /defaults/config.json > /etc/jitsi/jibri/config.json 50 | tpl /defaults/logging.properties > /etc/jitsi/jibri/logging.properties 51 | 52 | # make recording dir 53 | [ -z "${JIBRI_RECORDING_DIR}" ] && export JIBRI_RECORDING_DIR=/config/recordings 54 | mkdir -p ${JIBRI_RECORDING_DIR} 55 | chown -R jibri ${JIBRI_RECORDING_DIR} 56 | 57 | # make logs dir 58 | [ -z "${JIBRI_LOGS_DIR}" ] && export JIBRI_LOGS_DIR=/config/logs 59 | mkdir -p ${JIBRI_LOGS_DIR} 60 | chown -R jibri ${JIBRI_LOGS_DIR} 61 | -------------------------------------------------------------------------------- /jibri/rootfs/defaults/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "recording_directory":"{{ .Env.JIBRI_RECORDING_DIR }}", 3 | // The path to the script which will be run on completed recordings 4 | "finalize_recording_script_path": "{{ .Env.JIBRI_FINALIZE_RECORDING_SCRIPT_PATH }}", 5 | "xmpp_environments": [ 6 | { 7 | // A friendly name for this environment which can be used 8 | // for logging, stats, etc. 9 | "name": "prod environment", 10 | // The hosts of the XMPP servers to connect to as part of 11 | // this environment 12 | "xmpp_server_hosts": [ 13 | "{{ .Env.XMPP_SERVER }}" 14 | ], 15 | "xmpp_domain": "{{ .Env.XMPP_DOMAIN }}", 16 | // Jibri will login to the xmpp server as a privileged user 17 | "control_login": { 18 | "domain": "{{ .Env.XMPP_AUTH_DOMAIN }}", 19 | // The credentials for logging in 20 | "username": "{{ .Env.JIBRI_XMPP_USER }}", 21 | "password": "{{ .Env.JIBRI_XMPP_PASSWORD }}" 22 | }, 23 | // Using the control_login information above, Jibri will join 24 | // a control muc as a means of announcing its availability 25 | // to provide services for a given environment 26 | "control_muc": { 27 | "domain": "{{ .Env.XMPP_INTERNAL_MUC_DOMAIN }}", 28 | "room_name": "{{ .Env.JIBRI_BREWERY_MUC }}", 29 | // MUST be unic for every instanse 30 | "nickname": "jibri-instanse-{{ .Env.JIBRI_INSTANCE_ID }}" 31 | }, 32 | // All participants in a call join a muc so they can exchange 33 | // information. Jibri can be instructed to join a special muc 34 | // with credentials to give it special abilities (e.g. not being 35 | // displayed to other users like a normal participant) 36 | "call_login": { 37 | "domain": "{{ .Env.XMPP_RECORDER_DOMAIN }}", 38 | "username": "{{ .Env.JIBRI_RECORDER_USER }}", 39 | "password": "{{ .Env.JIBRI_RECORDER_PASSWORD }}" 40 | }, 41 | // When jibri gets a request to start a service for a room, the room 42 | // jid will look like: 43 | // roomName@optional.prefixes.subdomain.xmpp_domain 44 | // We'll build the url for the call by transforming that into: 45 | // https://xmpp_domain/subdomain/roomName 46 | // So if there are any prefixes in the jid (like jitsi meet, which 47 | // has its participants join a muc at conference.xmpp_domain) then 48 | // list that prefix here so it can be stripped out to generate 49 | // the call url correctly 50 | "room_jid_domain_string_to_strip_from_start": "{{ .Env.JIBRI_STRIP_DOMAIN_JID }}.", 51 | // The amount of time, in minutes, a service is allowed to continue. 52 | // Once a service has been running for this long, it will be 53 | // stopped (cleanly). A value of 0 means an indefinite amount 54 | // of time is allowed 55 | "usage_timeout": "0" 56 | } 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /prosody/rootfs/etc/cont-init.d/10-config: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | if [[ ! -f /etc/saslauthd.conf ]]; then 4 | tpl /defaults/saslauthd.conf > /etc/saslauthd.conf 5 | mkdir -pm777 /var/run/saslauthd 6 | adduser prosody sasl 7 | echo >> /etc/ldap/ldap.conf "TLS_REQCERT allow" 8 | fi 9 | 10 | PROSODY_CFG="/config/prosody.cfg.lua" 11 | 12 | if [[ ! -d /config/data ]]; then 13 | mkdir -pm 750 /config/data 14 | fi 15 | 16 | if [[ "$(stat -c %U /config)" != "prosody" ]]; then 17 | chown -R prosody /config 18 | fi 19 | 20 | if [[ "$(stat -c %U /prosody-plugins)" != "prosody" ]]; then 21 | chown -R prosody /prosody-plugins 22 | fi 23 | 24 | if [[ "$(stat -c %U /prosody-plugins-custom)" != "prosody" ]]; then 25 | chown -R prosody /prosody-plugins-custom 26 | fi 27 | 28 | if [[ ! -f $PROSODY_CFG ]]; then 29 | cp -r /defaults/* /config 30 | tpl /defaults/prosody.cfg.lua > $PROSODY_CFG 31 | tpl /defaults/conf.d/jitsi-meet.cfg.lua > /config/conf.d/jitsi-meet.cfg.lua 32 | 33 | if [[ -z $JICOFO_COMPONENT_SECRET || -z $JICOFO_AUTH_PASSWORD ]]; then 34 | echo 'FATAL ERROR: Jicofo component secret and auth password must be set' 35 | exit 1 36 | fi 37 | 38 | prosodyctl --config $PROSODY_CFG register $JICOFO_AUTH_USER $XMPP_AUTH_DOMAIN $JICOFO_AUTH_PASSWORD 39 | 40 | if [[ -z $JVB_AUTH_PASSWORD ]]; then 41 | echo 'FATAL ERROR: JVB auth password must be set' 42 | exit 1 43 | fi 44 | 45 | OLD_JVB_AUTH_PASSWORD=passw0rd 46 | if [[ "$JVB_AUTH_PASSWORD" == "$OLD_JVB_AUTH_PASSWORD" ]]; then 47 | echo 'FATAL ERROR: JVB auth password must be changed, check the README' 48 | exit 1 49 | fi 50 | 51 | prosodyctl --config $PROSODY_CFG register $JVB_AUTH_USER $XMPP_AUTH_DOMAIN $JVB_AUTH_PASSWORD 52 | 53 | if [[ ! -z $JIBRI_XMPP_USER ]] && [[ ! -z $JIBRI_XMPP_PASSWORD ]]; then 54 | OLD_JIBRI_XMPP_PASSWORD=passw0rd 55 | if [[ "$JIBRI_XMPP_PASSWORD" == "$OLD_JIBRI_XMPP_PASSWORD" ]]; then 56 | echo 'FATAL ERROR: Jibri auth password must be changed, check the README' 57 | exit 1 58 | fi 59 | prosodyctl --config $PROSODY_CFG register $JIBRI_XMPP_USER $XMPP_AUTH_DOMAIN $JIBRI_XMPP_PASSWORD 60 | fi 61 | 62 | if [[ ! -z $JIBRI_RECORDER_USER ]] && [[ ! -z $JIBRI_RECORDER_PASSWORD ]]; then 63 | OLD_JIBRI_RECORDER_PASSWORD=passw0rd 64 | if [[ "$JIBRI_RECORDER_PASSWORD" == "$OLD_JIBRI_RECORDER_PASSWORD" ]]; then 65 | echo 'FATAL ERROR: Jibri recorder password must be changed, check the README' 66 | exit 1 67 | fi 68 | prosodyctl --config $PROSODY_CFG register $JIBRI_RECORDER_USER $XMPP_RECORDER_DOMAIN $JIBRI_RECORDER_PASSWORD 69 | fi 70 | 71 | if [[ ! -z $JIGASI_XMPP_USER ]] && [[ ! -z $JIGASI_XMPP_PASSWORD ]]; then 72 | OLD_JIGASI_XMPP_PASSWORD=passw0rd 73 | if [[ "$JIGASI_XMPP_PASSWORD" == "$OLD_JIGASI_XMPP_PASSWORD" ]]; then 74 | echo 'FATAL ERROR: Jigasi auth password must be changed, check the README' 75 | exit 1 76 | fi 77 | prosodyctl --config $PROSODY_CFG register $JIGASI_XMPP_USER $XMPP_AUTH_DOMAIN $JIGASI_XMPP_PASSWORD 78 | fi 79 | fi 80 | 81 | mkdir -p /config/certs 82 | 83 | if [[ ! -f /config/certs/$XMPP_DOMAIN.crt ]]; then 84 | # echo for using all default values 85 | echo | prosodyctl --config $PROSODY_CFG cert generate $XMPP_DOMAIN 86 | fi 87 | 88 | if [[ ! -f /config/certs/$XMPP_AUTH_DOMAIN.crt ]]; then 89 | # echo for using all default values 90 | echo | prosodyctl --config $PROSODY_CFG cert generate $XMPP_AUTH_DOMAIN 91 | fi 92 | 93 | # certs will be created in /config/data 94 | mv /config/data/*.{crt,key} /config/certs/ || true 95 | rm -f /config/data/*.cnf 96 | -------------------------------------------------------------------------------- /prosody/rootfs/defaults/conf.d/jitsi-meet.cfg.lua: -------------------------------------------------------------------------------- 1 | admins = { "{{ .Env.JICOFO_AUTH_USER }}@{{ .Env.XMPP_AUTH_DOMAIN }}" } 2 | plugin_paths = { "/prosody-plugins/", "/prosody-plugins-custom" } 3 | http_default_host = "{{ .Env.XMPP_DOMAIN }}" 4 | 5 | {{ $ENABLE_AUTH := .Env.ENABLE_AUTH | default "0" | toBool }} 6 | {{ $AUTH_TYPE := .Env.AUTH_TYPE | default "internal" }} 7 | {{ $JWT_ASAP_KEYSERVER := .Env.JWT_ASAP_KEYSERVER | default "" }} 8 | {{ $JWT_ALLOW_EMPTY := .Env.JWT_ALLOW_EMPTY | default "0" | toBool }} 9 | {{ $JWT_AUTH_TYPE := .Env.JWT_AUTH_TYPE | default "token" }} 10 | {{ $JWT_TOKEN_AUTH_MODULE := .Env.JWT_TOKEN_AUTH_MODULE | default "token_verification" }} 11 | 12 | {{ if and $ENABLE_AUTH (eq $AUTH_TYPE "jwt") .Env.JWT_ACCEPTED_ISSUERS }} 13 | asap_accepted_issuers = { "{{ join "\",\"" (splitList "," .Env.JWT_ACCEPTED_ISSUERS) }}" } 14 | {{ end }} 15 | 16 | {{ if and $ENABLE_AUTH (eq $AUTH_TYPE "jwt") .Env.JWT_ACCEPTED_AUDIENCES }} 17 | asap_accepted_audiences = { "{{ join "\",\"" (splitList "," .Env.JWT_ACCEPTED_AUDIENCES) }}" } 18 | {{ end }} 19 | 20 | VirtualHost "{{ .Env.XMPP_DOMAIN }}" 21 | {{ if $ENABLE_AUTH }} 22 | {{ if eq $AUTH_TYPE "jwt" }} 23 | authentication = "{{ $JWT_AUTH_TYPE }}" 24 | app_id = "{{ .Env.JWT_APP_ID }}" 25 | app_secret = "{{ .Env.JWT_APP_SECRET }}" 26 | allow_empty_token = {{ if $JWT_ALLOW_EMPTY }}true{{ else }}false{{ end }} 27 | {{ if $JWT_ASAP_KEYSERVER }} 28 | asap_key_server = "{{ .Env.JWT_ASAP_KEYSERVER }}" 29 | {{ end }} 30 | 31 | {{ else if eq $AUTH_TYPE "ldap" }} 32 | authentication = "cyrus" 33 | cyrus_application_name = "xmpp" 34 | allow_unencrypted_plain_auth = true 35 | {{ else if eq $AUTH_TYPE "internal" }} 36 | authentication = "internal_hashed" 37 | {{ end }} 38 | {{ else }} 39 | authentication = "anonymous" 40 | {{ end }} 41 | ssl = { 42 | key = "/config/certs/{{ .Env.XMPP_DOMAIN }}.key"; 43 | certificate = "/config/certs/{{ .Env.XMPP_DOMAIN }}.crt"; 44 | } 45 | modules_enabled = { 46 | "bosh"; 47 | "pubsub"; 48 | "ping"; 49 | "speakerstats"; 50 | "conference_duration"; 51 | {{ if .Env.XMPP_MODULES }} 52 | "{{ join "\";\n\"" (splitList "," .Env.XMPP_MODULES) }}"; 53 | {{ end }} 54 | {{ if and $ENABLE_AUTH (eq $AUTH_TYPE "ldap") }} 55 | "auth_cyrus"; 56 | {{end}} 57 | } 58 | 59 | speakerstats_component = "speakerstats.{{ .Env.XMPP_DOMAIN }}" 60 | conference_duration_component = "conferenceduration.{{ .Env.XMPP_DOMAIN }}" 61 | 62 | c2s_require_encryption = false 63 | 64 | {{ if and $ENABLE_AUTH (.Env.ENABLE_GUESTS | default "0" | toBool) }} 65 | VirtualHost "{{ .Env.XMPP_GUEST_DOMAIN }}" 66 | authentication = "anonymous" 67 | c2s_require_encryption = false 68 | {{ end }} 69 | 70 | VirtualHost "{{ .Env.XMPP_AUTH_DOMAIN }}" 71 | ssl = { 72 | key = "/config/certs/{{ .Env.XMPP_AUTH_DOMAIN }}.key"; 73 | certificate = "/config/certs/{{ .Env.XMPP_AUTH_DOMAIN }}.crt"; 74 | } 75 | authentication = "internal_hashed" 76 | 77 | {{ if .Env.XMPP_RECORDER_DOMAIN }} 78 | VirtualHost "{{ .Env.XMPP_RECORDER_DOMAIN }}" 79 | modules_enabled = { 80 | "ping"; 81 | } 82 | authentication = "internal_hashed" 83 | {{ end }} 84 | 85 | Component "{{ .Env.XMPP_INTERNAL_MUC_DOMAIN }}" "muc" 86 | modules_enabled = { 87 | "ping"; 88 | {{ if .Env.XMPP_INTERNAL_MUC_MODULES }} 89 | "{{ join "\";\n\"" (splitList "," .Env.XMPP_INTERNAL_MUC_MODULES) }}"; 90 | {{ end }} 91 | } 92 | storage = "memory" 93 | muc_room_cache_size = 1000 94 | 95 | Component "{{ .Env.XMPP_MUC_DOMAIN }}" "muc" 96 | storage = "memory" 97 | modules_enabled = { 98 | {{ if .Env.XMPP_MUC_MODULES }} 99 | "{{ join "\";\n\"" (splitList "," .Env.XMPP_MUC_MODULES) }}"; 100 | {{ end }} 101 | {{ if and $ENABLE_AUTH (eq $AUTH_TYPE "jwt") }} 102 | "{{ $JWT_TOKEN_AUTH_MODULE }}"; 103 | {{ end }} 104 | } 105 | muc_room_locking = false 106 | muc_room_default_public_jids = true 107 | 108 | Component "focus.{{ .Env.XMPP_DOMAIN }}" 109 | component_secret = "{{ .Env.JICOFO_COMPONENT_SECRET }}" 110 | 111 | Component "speakerstats.{{ .Env.XMPP_DOMAIN }}" "speakerstats_component" 112 | muc_component = "{{ .Env.XMPP_MUC_DOMAIN }}" 113 | 114 | Component "conferenceduration.{{ .Env.XMPP_DOMAIN }}" "conference_duration_component" 115 | muc_component = "{{ .Env.XMPP_MUC_DOMAIN }}" 116 | -------------------------------------------------------------------------------- /web/rootfs/etc/cont-init.d/10-config: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | # make our folders 4 | mkdir -p \ 5 | /config/{nginx/site-confs,keys} \ 6 | /run \ 7 | /var/lib/nginx/tmp/client_body \ 8 | /var/tmp/nginx 9 | 10 | # generate keys (maybe) 11 | if [[ $DISABLE_HTTPS -ne 1 ]]; then 12 | if [[ $ENABLE_LETSENCRYPT -eq 1 ]]; then 13 | if [[ ! -f /etc/letsencrypt/live/$LETSENCRYPT_DOMAIN/fullchain.pem ]]; then 14 | if ! certbot-auto \ 15 | certonly \ 16 | --no-self-upgrade \ 17 | --noninteractive \ 18 | --standalone \ 19 | --preferred-challenges http \ 20 | -d $LETSENCRYPT_DOMAIN \ 21 | --agree-tos \ 22 | --email $LETSENCRYPT_EMAIL ; then 23 | 24 | echo "Failed to obtain a certificate from the Let's Encrypt CA." 25 | # this tries to get the user's attention and to spare the 26 | # authority's rate limit: 27 | sleep 15 28 | echo "Exiting." 29 | exit 1 30 | fi 31 | fi 32 | 33 | # remove default certbot renewal 34 | if [[ -f /etc/cron.d/certbot ]]; then 35 | rm /etc/cron.d/certbot 36 | fi 37 | 38 | # setup certbot renewal script 39 | if [[ ! -f /etc/cron.daily/letencrypt-renew ]]; then 40 | cp /defaults/letsencrypt-renew /etc/cron.daily/ 41 | fi 42 | else 43 | # use self-signed certs 44 | if [[ -f /config/keys/cert.key && -f /config/keys/cert.crt ]]; then 45 | echo "using keys found in /config/keys" 46 | else 47 | echo "generating self-signed keys in /config/keys, you can replace these with your own keys if required" 48 | SUBJECT="/C=US/ST=TX/L=Austin/O=jitsi.org/OU=Jitsi Server/CN=*" 49 | openssl req -new -x509 -days 3650 -nodes -out /config/keys/cert.crt -keyout /config/keys/cert.key -subj "$SUBJECT" 50 | fi 51 | fi 52 | fi 53 | 54 | # copy config files 55 | if [[ ! -f /config/nginx/nginx.conf ]]; then 56 | cp /defaults/nginx.conf /config/nginx/nginx.conf 57 | fi 58 | 59 | if [[ ! -f /config/nginx/meet.conf ]]; then 60 | tpl /defaults/meet.conf > /config/nginx/meet.conf 61 | fi 62 | 63 | if [[ ! -f /config/nginx/ssl.conf ]]; then 64 | tpl /defaults/ssl.conf > /config/nginx/ssl.conf 65 | fi 66 | 67 | if [[ ! -f /config/nginx/site-confs/default ]]; then 68 | tpl /defaults/default > /config/nginx/site-confs/default 69 | fi 70 | 71 | if [[ ! -f /config/config.js ]]; then 72 | cp /defaults/config.js /config/config.js 73 | sed -i \ 74 | -e "s#jitsi-meet.example.com#$XMPP_DOMAIN#g" \ 75 | -e "s#bosh:.*#bosh: '/http-bind',#" \ 76 | -e "s#muc:.*#muc: '${XMPP_MUC_DOMAIN}',#" \ 77 | -e "s#// focusUserJid:.*#focusUserJid: '${JICOFO_AUTH_USER}@${XMPP_AUTH_DOMAIN}',#" \ 78 | /config/config.js 79 | 80 | if [[ $ENABLE_RECORDING -eq 1 || x$ENABLE_RECORDING == xtrue ]]; then 81 | sed -i \ 82 | -e "/\/\/ Recording.*/a hiddenDomain: '$XMPP_RECORDER_DOMAIN'," \ 83 | -e "s#// fileRecordingsEnabled:.*#fileRecordingsEnabled: true,#" \ 84 | -e "s#// liveStreamingEnabled:.*#liveStreamingEnabled: true,#" \ 85 | /config/config.js 86 | fi 87 | 88 | if [[ $ENABLE_AUTH -eq 1 ]]; then 89 | if [[ $ENABLE_GUESTS -eq 1 ]]; then 90 | sed -i \ 91 | -e "s#// anonymousdomain:.*#anonymousdomain: '${XMPP_GUEST_DOMAIN}',#" \ 92 | /config/config.js 93 | fi 94 | 95 | sed -i \ 96 | -e "s#// authdomain:.*#authdomain: '${XMPP_DOMAIN}',#" \ 97 | /config/config.js 98 | fi 99 | 100 | if [[ ! -z "${ETHERPAD_URL_BASE}" && -z "$(grep -om1 'etherpad_base:' /config/config.js)" ]]; then 101 | sed -i \ 102 | -e "/enableWelcomePage/a\ etherpad_base: '${PUBLIC_URL}/etherpad/p/'," \ 103 | /config/config.js 104 | fi 105 | 106 | if [[ $ENABLE_TRANSCRIPTIONS -eq 1 || "$ENABLE_TRANSCRIPTIONS" == "true" ]]; then 107 | sed -i \ 108 | -e "s#// transcribingEnabled:.*#transcribingEnabled: true,#" \ 109 | /config/config.js 110 | fi 111 | fi 112 | 113 | if [[ ! -f /config/interface_config.js ]]; then 114 | cp /defaults/interface_config.js /config/interface_config.js 115 | 116 | # It will remove parameter 'closedcaptions' from TOOLBAR_BUTTONS if ENABLE_TRANSCRIPTIONS is false, 117 | # because it enabled by default, but not supported out of the box. 118 | if [[ $ENABLE_TRANSCRIPTIONS -ne 1 || "$ENABLE_TRANSCRIPTIONS" != "true" ]]; then 119 | sed -i \ 120 | -e "s#'closedcaptions', ##" \ 121 | /config/interface_config.js 122 | fi 123 | 124 | fi 125 | -------------------------------------------------------------------------------- /examples/kubernetes/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | k8s-app: jitsi 6 | name: jitsi 7 | namespace: jitsi 8 | spec: 9 | replicas: 1 10 | strategy: 11 | type: Recreate 12 | selector: 13 | matchLabels: 14 | k8s-app: jitsi 15 | template: 16 | metadata: 17 | labels: 18 | k8s-app: jitsi 19 | spec: 20 | containers: 21 | - name: jicofo 22 | image: jitsi/jicofo 23 | imagePullPolicy: Always 24 | env: 25 | - name: XMPP_SERVER 26 | value: localhost 27 | - name: XMPP_DOMAIN 28 | value: meet.jitsi 29 | - name: XMPP_AUTH_DOMAIN 30 | value: auth.meet.jitsi 31 | - name: XMPP_INTERNAL_MUC_DOMAIN 32 | value: internal-muc.meet.jitsi 33 | - name: JICOFO_COMPONENT_SECRET 34 | valueFrom: 35 | secretKeyRef: 36 | name: jitsi-config 37 | key: JICOFO_COMPONENT_SECRET 38 | - name: JICOFO_AUTH_USER 39 | value: focus 40 | - name: JICOFO_AUTH_PASSWORD 41 | valueFrom: 42 | secretKeyRef: 43 | name: jitsi-config 44 | key: JICOFO_AUTH_PASSWORD 45 | - name: TZ 46 | value: America/Los_Angeles 47 | - name: JVB_BREWERY_MUC 48 | value: jvbbrewery 49 | - name: prosody 50 | image: jitsi/prosody 51 | imagePullPolicy: Always 52 | env: 53 | - name: XMPP_DOMAIN 54 | value: meet.jitsi 55 | - name: XMPP_AUTH_DOMAIN 56 | value: auth.meet.jitsi 57 | - name: XMPP_MUC_DOMAIN 58 | value: muc.meet.jitsi 59 | - name: XMPP_INTERNAL_MUC_DOMAIN 60 | value: internal-muc.meet.jitsi 61 | - name: JICOFO_COMPONENT_SECRET 62 | valueFrom: 63 | secretKeyRef: 64 | name: jitsi-config 65 | key: JICOFO_COMPONENT_SECRET 66 | - name: JVB_AUTH_USER 67 | value: jvb 68 | - name: JVB_AUTH_PASSWORD 69 | valueFrom: 70 | secretKeyRef: 71 | name: jitsi-config 72 | key: JVB_AUTH_PASSWORD 73 | - name: JICOFO_AUTH_USER 74 | value: focus 75 | - name: JICOFO_AUTH_PASSWORD 76 | valueFrom: 77 | secretKeyRef: 78 | name: jitsi-config 79 | key: JICOFO_AUTH_PASSWORD 80 | - name: TZ 81 | value: America/Los_Angeles 82 | - name: JVB_TCP_HARVESTER_DISABLED 83 | value: "true" 84 | - name: web 85 | image: jitsi/web 86 | imagePullPolicy: Always 87 | env: 88 | - name: XMPP_SERVER 89 | value: localhost 90 | - name: JICOFO_AUTH_USER 91 | value: focus 92 | - name: XMPP_DOMAIN 93 | value: meet.jitsi 94 | - name: XMPP_AUTH_DOMAIN 95 | value: auth.meet.jitsi 96 | - name: XMPP_INTERNAL_MUC_DOMAIN 97 | value: internal-muc.meet.jitsi 98 | - name: XMPP_BOSH_URL_BASE 99 | value: http://127.0.0.1:5280 100 | - name: XMPP_MUC_DOMAIN 101 | value: muc.meet.jitsi 102 | - name: TZ 103 | value: America/Los_Angeles 104 | - name: JVB_TCP_HARVESTER_DISABLED 105 | value: "true" 106 | - name: jvb 107 | image: jitsi/jvb 108 | imagePullPolicy: Always 109 | env: 110 | - name: XMPP_SERVER 111 | value: localhost 112 | - name: DOCKER_HOST_ADDRESS 113 | value: 114 | - name: XMPP_DOMAIN 115 | value: meet.jitsi 116 | - name: XMPP_AUTH_DOMAIN 117 | value: auth.meet.jitsi 118 | - name: XMPP_INTERNAL_MUC_DOMAIN 119 | value: internal-muc.meet.jitsi 120 | - name: JVB_STUN_SERVERS 121 | value: stun.l.google.com:19302,stun1.l.google.com:19302,stun2.l.google.com:19302 122 | - name: JICOFO_AUTH_USER 123 | value: focus 124 | - name: JVB_TCP_HARVESTER_DISABLED 125 | value: "true" 126 | - name: JVB_AUTH_USER 127 | value: jvb 128 | - name: JVB_PORT 129 | value: "30300" 130 | - name: JVB_AUTH_PASSWORD 131 | valueFrom: 132 | secretKeyRef: 133 | name: jitsi-config 134 | key: JVB_AUTH_PASSWORD 135 | - name: JICOFO_AUTH_PASSWORD 136 | valueFrom: 137 | secretKeyRef: 138 | name: jitsi-config 139 | key: JICOFO_AUTH_PASSWORD 140 | - name: JVB_BREWERY_MUC 141 | value: jvbbrewery 142 | - name: TZ 143 | value: America/Los_Angeles 144 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | # Frontend 5 | web: 6 | image: jitsi/web:latest 7 | restart: ${RESTART_POLICY} 8 | ports: 9 | - '${HTTP_PORT}:80' 10 | - '${HTTPS_PORT}:443' 11 | volumes: 12 | - ${CONFIG}/web:/config:Z 13 | - ${CONFIG}/web/letsencrypt:/etc/letsencrypt:Z 14 | - ${CONFIG}/transcripts:/usr/share/jitsi-meet/transcripts:Z 15 | environment: 16 | - ENABLE_AUTH 17 | - ENABLE_GUESTS 18 | - ENABLE_LETSENCRYPT 19 | - ENABLE_HTTP_REDIRECT 20 | - ENABLE_TRANSCRIPTIONS 21 | - DISABLE_HTTPS 22 | - JICOFO_AUTH_USER 23 | - LETSENCRYPT_DOMAIN 24 | - LETSENCRYPT_EMAIL 25 | - PUBLIC_URL 26 | - XMPP_DOMAIN 27 | - XMPP_AUTH_DOMAIN 28 | - XMPP_BOSH_URL_BASE 29 | - XMPP_GUEST_DOMAIN 30 | - XMPP_MUC_DOMAIN 31 | - XMPP_RECORDER_DOMAIN 32 | - ETHERPAD_URL_BASE 33 | - TZ 34 | - JIBRI_BREWERY_MUC 35 | - JIBRI_PENDING_TIMEOUT 36 | - JIBRI_XMPP_USER 37 | - JIBRI_XMPP_PASSWORD 38 | - JIBRI_RECORDER_USER 39 | - JIBRI_RECORDER_PASSWORD 40 | - ENABLE_RECORDING 41 | networks: 42 | meet.jitsi: 43 | aliases: 44 | - ${XMPP_DOMAIN} 45 | 46 | # XMPP server 47 | prosody: 48 | image: jitsi/prosody:latest 49 | restart: ${RESTART_POLICY} 50 | expose: 51 | - '5222' 52 | - '5347' 53 | - '5280' 54 | volumes: 55 | - ${CONFIG}/prosody/config:/config:Z 56 | - ${CONFIG}/prosody/prosody-plugins-custom:/prosody-plugins-custom:Z 57 | environment: 58 | - AUTH_TYPE 59 | - ENABLE_AUTH 60 | - ENABLE_GUESTS 61 | - GLOBAL_MODULES 62 | - GLOBAL_CONFIG 63 | - LDAP_URL 64 | - LDAP_BASE 65 | - LDAP_BINDDN 66 | - LDAP_BINDPW 67 | - LDAP_FILTER 68 | - LDAP_AUTH_METHOD 69 | - LDAP_VERSION 70 | - LDAP_USE_TLS 71 | - LDAP_TLS_CIPHERS 72 | - LDAP_TLS_CHECK_PEER 73 | - LDAP_TLS_CACERT_FILE 74 | - LDAP_TLS_CACERT_DIR 75 | - LDAP_START_TLS 76 | - XMPP_DOMAIN 77 | - XMPP_AUTH_DOMAIN 78 | - XMPP_GUEST_DOMAIN 79 | - XMPP_MUC_DOMAIN 80 | - XMPP_INTERNAL_MUC_DOMAIN 81 | - XMPP_MODULES 82 | - XMPP_MUC_MODULES 83 | - XMPP_INTERNAL_MUC_MODULES 84 | - XMPP_RECORDER_DOMAIN 85 | - JICOFO_COMPONENT_SECRET 86 | - JICOFO_AUTH_USER 87 | - JICOFO_AUTH_PASSWORD 88 | - JVB_AUTH_USER 89 | - JVB_AUTH_PASSWORD 90 | - JIGASI_XMPP_USER 91 | - JIGASI_XMPP_PASSWORD 92 | - JIBRI_XMPP_USER 93 | - JIBRI_XMPP_PASSWORD 94 | - JIBRI_RECORDER_USER 95 | - JIBRI_RECORDER_PASSWORD 96 | - JWT_APP_ID 97 | - JWT_APP_SECRET 98 | - JWT_ACCEPTED_ISSUERS 99 | - JWT_ACCEPTED_AUDIENCES 100 | - JWT_ASAP_KEYSERVER 101 | - JWT_ALLOW_EMPTY 102 | - JWT_AUTH_TYPE 103 | - JWT_TOKEN_AUTH_MODULE 104 | - LOG_LEVEL 105 | - TZ 106 | networks: 107 | meet.jitsi: 108 | aliases: 109 | - ${XMPP_SERVER} 110 | 111 | # Focus component 112 | jicofo: 113 | image: jitsi/jicofo:latest 114 | restart: ${RESTART_POLICY} 115 | volumes: 116 | - ${CONFIG}/jicofo:/config:Z 117 | environment: 118 | - AUTH_TYPE 119 | - ENABLE_AUTH 120 | - XMPP_DOMAIN 121 | - XMPP_AUTH_DOMAIN 122 | - XMPP_INTERNAL_MUC_DOMAIN 123 | - XMPP_SERVER 124 | - JICOFO_COMPONENT_SECRET 125 | - JICOFO_AUTH_USER 126 | - JICOFO_AUTH_PASSWORD 127 | - JICOFO_RESERVATION_REST_BASE_URL 128 | - JVB_BREWERY_MUC 129 | - JIGASI_BREWERY_MUC 130 | - JIGASI_SIP_URI 131 | - JIBRI_BREWERY_MUC 132 | - JIBRI_PENDING_TIMEOUT 133 | - TZ 134 | depends_on: 135 | - prosody 136 | networks: 137 | meet.jitsi: 138 | 139 | # Video bridge 140 | jvb: 141 | image: jitsi/jvb:latest 142 | restart: ${RESTART_POLICY} 143 | ports: 144 | - '${JVB_PORT}:${JVB_PORT}/udp' 145 | - '${JVB_TCP_MAPPED_PORT}:${JVB_TCP_PORT}' 146 | volumes: 147 | - ${CONFIG}/jvb:/config:Z 148 | environment: 149 | - DOCKER_HOST_ADDRESS 150 | - XMPP_AUTH_DOMAIN 151 | - XMPP_INTERNAL_MUC_DOMAIN 152 | - XMPP_SERVER 153 | - JVB_AUTH_USER 154 | - JVB_AUTH_PASSWORD 155 | - JVB_BREWERY_MUC 156 | - JVB_PORT 157 | - JVB_TCP_HARVESTER_DISABLED 158 | - JVB_TCP_PORT 159 | - JVB_STUN_SERVERS 160 | - JVB_ENABLE_APIS 161 | - TZ 162 | depends_on: 163 | - prosody 164 | networks: 165 | meet.jitsi: 166 | 167 | # Custom network so all services can communicate using a FQDN 168 | networks: 169 | meet.jitsi: 170 | -------------------------------------------------------------------------------- /examples/traefik/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | # Frontend 5 | web: 6 | image: jitsi/web 7 | volumes: 8 | - ${CONFIG}/web:/config 9 | - ${CONFIG}/web/letsencrypt:/etc/letsencrypt 10 | - ${CONFIG}/transcripts:/usr/share/jitsi-meet/transcripts 11 | environment: 12 | - ENABLE_AUTH 13 | - ENABLE_GUESTS 14 | - ENABLE_LETSENCRYPT 15 | - ENABLE_HTTP_REDIRECT 16 | - ENABLE_TRANSCRIPTIONS 17 | - DISABLE_HTTPS 18 | - JICOFO_AUTH_USER 19 | - LETSENCRYPT_DOMAIN 20 | - LETSENCRYPT_EMAIL 21 | - PUBLIC_URL 22 | - XMPP_DOMAIN 23 | - XMPP_AUTH_DOMAIN 24 | - XMPP_BOSH_URL_BASE 25 | - XMPP_GUEST_DOMAIN 26 | - XMPP_MUC_DOMAIN 27 | - XMPP_RECORDER_DOMAIN 28 | - ETHERPAD_URL_BASE 29 | - TZ 30 | - JIBRI_BREWERY_MUC 31 | - JIBRI_PENDING_TIMEOUT 32 | - JIBRI_XMPP_USER 33 | - JIBRI_XMPP_PASSWORD 34 | - JIBRI_RECORDER_USER 35 | - JIBRI_RECORDER_PASSWORD 36 | - ENABLE_RECORDING 37 | networks: 38 | # traefik: change the following line to your external docker network 39 | web: 40 | meet.jitsi: 41 | aliases: 42 | - ${XMPP_DOMAIN} 43 | labels: 44 | # traefik: change that to your external network 45 | - "traefik.docker.network=web" 46 | - "traefik.enable=true" 47 | - "traefik.backend=jc_backend" 48 | # traefik: change that to your actual fqdn 49 | - "traefik.basic.frontend.rule=Host:your.host.name" 50 | - "traefik.basic.port=80" 51 | 52 | # XMPP server 53 | prosody: 54 | image: jitsi/prosody 55 | expose: 56 | - '5222' 57 | - '5347' 58 | - '5280' 59 | volumes: 60 | - ${CONFIG}/prosody:/config 61 | environment: 62 | - AUTH_TYPE 63 | - ENABLE_AUTH 64 | - ENABLE_GUESTS 65 | - GLOBAL_MODULES 66 | - GLOBAL_CONFIG 67 | - LDAP_URL 68 | - LDAP_BASE 69 | - LDAP_BINDDN 70 | - LDAP_BINDPW 71 | - LDAP_FILTER 72 | - LDAP_AUTH_METHOD 73 | - LDAP_VERSION 74 | - LDAP_USE_TLS 75 | - LDAP_TLS_CIPHERS 76 | - LDAP_TLS_CHECK_PEER 77 | - LDAP_TLS_CACERT_FILE 78 | - LDAP_TLS_CACERT_DIR 79 | - LDAP_START_TLS 80 | - XMPP_DOMAIN 81 | - XMPP_AUTH_DOMAIN 82 | - XMPP_GUEST_DOMAIN 83 | - XMPP_MUC_DOMAIN 84 | - XMPP_INTERNAL_MUC_DOMAIN 85 | - XMPP_MODULES 86 | - XMPP_MUC_MODULES 87 | - XMPP_INTERNAL_MUC_MODULES 88 | - XMPP_RECORDER_DOMAIN 89 | - JICOFO_COMPONENT_SECRET 90 | - JICOFO_AUTH_USER 91 | - JICOFO_AUTH_PASSWORD 92 | - JVB_AUTH_USER 93 | - JVB_AUTH_PASSWORD 94 | - JIGASI_XMPP_USER 95 | - JIGASI_XMPP_PASSWORD 96 | - JIBRI_XMPP_USER 97 | - JIBRI_XMPP_PASSWORD 98 | - JIBRI_RECORDER_USER 99 | - JIBRI_RECORDER_PASSWORD 100 | - JWT_APP_ID 101 | - JWT_APP_SECRET 102 | - JWT_ACCEPTED_ISSUERS 103 | - JWT_ACCEPTED_AUDIENCES 104 | - JWT_ASAP_KEYSERVER 105 | - JWT_ALLOW_EMPTY 106 | - JWT_AUTH_TYPE 107 | - JWT_TOKEN_AUTH_MODULE 108 | - LOG_LEVEL 109 | - TZ 110 | networks: 111 | meet.jitsi: 112 | aliases: 113 | - ${XMPP_SERVER} 114 | 115 | # Focus component 116 | jicofo: 117 | image: jitsi/jicofo 118 | volumes: 119 | - ${CONFIG}/jicofo:/config 120 | environment: 121 | - ENABLE_AUTH 122 | - XMPP_DOMAIN 123 | - XMPP_AUTH_DOMAIN 124 | - XMPP_INTERNAL_MUC_DOMAIN 125 | - XMPP_SERVER 126 | - JICOFO_COMPONENT_SECRET 127 | - JICOFO_AUTH_USER 128 | - JICOFO_AUTH_PASSWORD 129 | - JICOFO_RESERVATION_REST_BASE_URL 130 | - JVB_BREWERY_MUC 131 | - JIGASI_BREWERY_MUC 132 | - JIBRI_BREWERY_MUC 133 | - JIBRI_PENDING_TIMEOUT 134 | - TZ 135 | depends_on: 136 | - prosody 137 | networks: 138 | meet.jitsi: 139 | 140 | # Video bridge 141 | jvb: 142 | image: jitsi/jvb 143 | ports: 144 | - '${JVB_PORT}:${JVB_PORT}/udp' 145 | - '${JVB_TCP_PORT}:${JVB_TCP_PORT}' 146 | volumes: 147 | - ${CONFIG}/jvb:/config 148 | environment: 149 | - DOCKER_HOST_ADDRESS 150 | - XMPP_AUTH_DOMAIN 151 | - XMPP_INTERNAL_MUC_DOMAIN 152 | - XMPP_SERVER 153 | - JVB_AUTH_USER 154 | - JVB_AUTH_PASSWORD 155 | - JVB_BREWERY_MUC 156 | - JVB_PORT 157 | - JVB_TCP_HARVESTER_DISABLED 158 | - JVB_TCP_PORT 159 | - JVB_STUN_SERVERS 160 | - JVB_ENABLE_APIS 161 | - TZ 162 | depends_on: 163 | - prosody 164 | networks: 165 | meet.jitsi: 166 | 167 | # Custom network so all services can communicate using a FQDN 168 | networks: 169 | meet.jitsi: 170 | # traefik: change the following line to your external docker network 171 | web: 172 | external: true 173 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## stable-4548-1 2 | 3 | Based on stable release 4548-1. 4 | 5 | * abf2f73 jicofo: fix setting incorrect auth URL scheme for JWT 6 | * 3472ab0 jicofo: add ability to configure health checks 7 | * ec3622b jibri: install jitsi-upload-integrations by default 8 | * 0e7bc91 etherpad: pin image version 9 | * 4fa50b9 jwt: do not load token_verification module with disabled authentication 10 | * b0d76a2 jibri: add jq dep for upload integrations 11 | * 53b58fd jvb: add jq, curl deps for graceful_shutdown.sh 12 | * 2d063ad doc: update installation instructions 13 | * e73df5f misc: working on latest 14 | 15 | ## stable-4548 16 | 17 | Based on stable release 4548. 18 | 19 | * a79fc0c misc: add release script 20 | * 0f0adc8 compose: add image tag to compose files 21 | * 0177765 misc: fix config volumes to work with SELinux 22 | * eae3f5c jibri: chrome/driver 78 as a stopgap 23 | * 78df6a4 doc: delete unnecessary dot 24 | * 4426ed8 jibri: fix case when /dev/snd is not bound (https://github.com/jitsi/docker-jitsi-meet/issues/240#issuecomment-610422404) 25 | * 125775a web: fix WASM MIME type 26 | * e70975e web: enable GZIP compression for more file types 27 | * 774aba5 misc: set ddefault timezone to UTC 28 | * 3c3fc19 prosody: enable speaker stats and conferene duration modules 29 | * f911df2 jvb: set JVB_TCP_MAPPED_PORT default value 30 | * 1205170 jvb: allow `TCP_HARVESTER_MAPPED_PORT` to be configured 31 | * f7796a1 prosody: add volume /prosody-plugins-custom to docker-compose 32 | * d44230e prosody: use hashed xmpp auth 33 | 34 | ## stable-4416 35 | 36 | Based on stable release 4416. 37 | 38 | * b039b29 web: use certbot-auto 39 | * b95c95d web: improve nginx configuration 40 | * 2dd6b99 k8s: specify namespace for secret 41 | * 7aa2d81 ldap: avoid unnecessary copy 42 | * e1b47db exampless: update Traefik v2 example with UDP 43 | * 0940605 doc: fix typos and minor grammar issues in README 44 | * 1c4b11c doc: correct minor mistake 45 | * c06867b doc: added steps for updating kernel manually in AWS installation 46 | * dc46215 web: remove DHE suites support 47 | * 367621f prosody: remove no longer needed patch 48 | * 34e6601 doc: clarify acronym 49 | * 2c95ab7 web: revert using PUBLIC_URL for BOSH URL 50 | * 7fd7e2b Add docker-compose.override.yml to .gitignore (#438) 51 | * 67a941b misc: update gen-passwords.sh shell code 52 | * 4e2cec6 misc: add configurable service restart policy 53 | * 729f9d2 doc: fix typo in env.example 54 | 55 | ## stable-4384(-1) 56 | 57 | **Important security note:** Previous releases included default passwords for 58 | system accounts, and users who didn't change them are at risk of getting 59 | the authentication system circumvented by an attacker using a system account 60 | with the default password. Please update and use the provided script 61 | (instructions on the README) to generate a strong password for each system 62 | account. 63 | 64 | Thanks joernchen for the security report. 65 | 66 |
67 | 68 | Based on stable release 4384. 69 | 70 | * 768b6c4 security: fail to start if using the old default password 71 | * 1ffd472 security: add script to generate strong passwords 72 | * a015710 security: don't provide default passwords 73 | * aaec22d jigasi: fix typo in config 74 | * ebfa142 docs: fix grammar and typos 75 | * bab77e0 doc: update env.example 76 | * 7652807 examples: traefik v2 77 | * 10983b4 prosody: prevent item-not-found error in certain cases 78 | * 3524a52 base: fail to start the container if the init script fails 79 | * 7c0c795 jicofo: only configure Jigasi brewery if Jigasi is configured 80 | * 40c2920 build: add prepare command 81 | * 93ba770 prosody: fix installing prosody from the right repository 82 | * 3c07d76 doc: improve wording of README 83 | * ed410d9 doc: fix typo 84 | * fabfb2a doc: fix typo 85 | * 5e6face web: use PUBLIC_URL for etherpaad base and BOSH URLs 86 | * 264df04 jvb: switch to using Jitsi's STUN server by default 87 | * 655cf6b web,prosody,jvb: prepare for new stable release 88 | * ebb4536 doc: update CHANGELOG 89 | * 06c3a83 doc: fix references to running behind NAT in the README 90 | 91 | ## stable-4101-2 92 | 93 | Based on stable release 4101. 94 | 95 | * b15bb28 prosody: update to latest stable version 96 | * 75cb31b doc: add build instructions to README 97 | * 25dbde9 doc: fix typo 98 | * badc2d4 doc: add examples/README 99 | * f6f6ca6 Merge branch 'dev' 100 | * 52a1449 doc: clarify DOCKER_HOST_ADDRESS 101 | * f26c9e6 prosody: fix ldap config template 102 | * cd4a071 web: check for certbot's success and exit in case of a failure 103 | * dea8d6c doc: fix typo 104 | * 573c6fa doc: update diagrams 105 | * 29125fd examples: add minimal example to run jitsi behind traefik 106 | 107 | ## stable-4101-1 108 | 109 | Based on stable release 4101. 110 | 111 | * b0def9a prosody: use epoll backend 112 | * 8fa9f94 web: update nginx config from upstream 113 | * 2f17380 doc: clarify account registration command 114 | * edfd8f2 ldap: actually fix anonymous binds (Fixes #234) 115 | * f4ac7cc misc: remove bogus quotation marks 116 | * 0a68be1 jibri: start once jicofo has started 117 | * 76acc65 doc: add tip re. ports to open on firewall to README 118 | * e92a00c ldap: fix anonymous binds 119 | * df40447 ldap: add option for ldap starttls support 120 | * 1ebc535 doc: make localhost link in README clickable 121 | * 33abdf3 doc: add mkdir -p ~/.jitsi-meet-cfg/... to README 122 | * 2c93dce doc: fix typo in README 123 | * d7bb2e6 doc: clarify HTTP vs HTTPS in README 124 | * a1df1e0 Revert "prosody: fix restart loop on rolling deployment" 125 | * 986071b jigasi: add missing transcription volumes to dockerfile 126 | * 01eca74 jigasi: generate google cloud credentials from env vars 127 | * cc2c042 prosody: fix restart loop on rolling deployment 128 | * 5423a8a examples: adding simple kubernetes example 129 | * 6eebabd jicofo: set owner jicofo rights for /config directory 130 | * 69ba9ff jigasi: Updates jigasi client default options. 131 | * 2b9a13b jicofo: add support of reservation REST API 132 | * 8bfe7fb jicofo: add support of reservation REST API 133 | * 9b17c05 web: fix letsencrypt renewal 134 | * 6234a18 web: fix letsencrypt renewal 135 | -------------------------------------------------------------------------------- /examples/traefik-v2/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | # Frontend 5 | web: 6 | image: jitsi/web 7 | volumes: 8 | - ${CONFIG}/web:/config 9 | - ${CONFIG}/web/letsencrypt:/etc/letsencrypt 10 | - ${CONFIG}/transcripts:/usr/share/jitsi-meet/transcripts 11 | environment: 12 | - ENABLE_AUTH 13 | - ENABLE_GUESTS 14 | - ENABLE_LETSENCRYPT 15 | - ENABLE_HTTP_REDIRECT 16 | - ENABLE_TRANSCRIPTIONS 17 | - DISABLE_HTTPS 18 | - JICOFO_AUTH_USER 19 | - LETSENCRYPT_DOMAIN 20 | - LETSENCRYPT_EMAIL 21 | - PUBLIC_URL 22 | - XMPP_DOMAIN 23 | - XMPP_AUTH_DOMAIN 24 | - XMPP_BOSH_URL_BASE 25 | - XMPP_GUEST_DOMAIN 26 | - XMPP_MUC_DOMAIN 27 | - XMPP_RECORDER_DOMAIN 28 | - ETHERPAD_URL_BASE 29 | - TZ 30 | - JIBRI_BREWERY_MUC 31 | - JIBRI_PENDING_TIMEOUT 32 | - JIBRI_XMPP_USER 33 | - JIBRI_XMPP_PASSWORD 34 | - JIBRI_RECORDER_USER 35 | - JIBRI_RECORDER_PASSWORD 36 | - ENABLE_RECORDING 37 | networks: 38 | # traefik: change the following line to your external docker network 39 | web: 40 | meet.jitsi: 41 | aliases: 42 | - ${XMPP_DOMAIN} 43 | labels: 44 | traefik.http.middlewares.redirect.redirectscheme.scheme: https 45 | traefik.http.routers.app-http.entrypoints: web 46 | traefik.http.routers.app-http.middlewares: redirect 47 | traefik.http.routers.app-http.rule: 'Host(`your.host.name`)' 48 | traefik.http.routers.app.entrypoints: websecure 49 | traefik.http.routers.app.rule: 'Host(`your.host.name`)' 50 | traefik.http.routers.app.tls: 'true' 51 | traefik.http.routers.app.tls.certresolver: le 52 | traefik.http.services.app.loadbalancer.server.port: 80 53 | 54 | # XMPP server 55 | prosody: 56 | image: jitsi/prosody 57 | expose: 58 | - '5222' 59 | - '5347' 60 | - '5280' 61 | volumes: 62 | - ${CONFIG}/prosody:/config 63 | environment: 64 | - AUTH_TYPE 65 | - ENABLE_AUTH 66 | - ENABLE_GUESTS 67 | - GLOBAL_MODULES 68 | - GLOBAL_CONFIG 69 | - LDAP_URL 70 | - LDAP_BASE 71 | - LDAP_BINDDN 72 | - LDAP_BINDPW 73 | - LDAP_FILTER 74 | - LDAP_AUTH_METHOD 75 | - LDAP_VERSION 76 | - LDAP_USE_TLS 77 | - LDAP_TLS_CIPHERS 78 | - LDAP_TLS_CHECK_PEER 79 | - LDAP_TLS_CACERT_FILE 80 | - LDAP_TLS_CACERT_DIR 81 | - LDAP_START_TLS 82 | - XMPP_DOMAIN 83 | - XMPP_AUTH_DOMAIN 84 | - XMPP_GUEST_DOMAIN 85 | - XMPP_MUC_DOMAIN 86 | - XMPP_INTERNAL_MUC_DOMAIN 87 | - XMPP_MODULES 88 | - XMPP_MUC_MODULES 89 | - XMPP_INTERNAL_MUC_MODULES 90 | - XMPP_RECORDER_DOMAIN 91 | - JICOFO_COMPONENT_SECRET 92 | - JICOFO_AUTH_USER 93 | - JICOFO_AUTH_PASSWORD 94 | - JVB_AUTH_USER 95 | - JVB_AUTH_PASSWORD 96 | - JIGASI_XMPP_USER 97 | - JIGASI_XMPP_PASSWORD 98 | - JIBRI_XMPP_USER 99 | - JIBRI_XMPP_PASSWORD 100 | - JIBRI_RECORDER_USER 101 | - JIBRI_RECORDER_PASSWORD 102 | - JWT_APP_ID 103 | - JWT_APP_SECRET 104 | - JWT_ACCEPTED_ISSUERS 105 | - JWT_ACCEPTED_AUDIENCES 106 | - JWT_ASAP_KEYSERVER 107 | - JWT_ALLOW_EMPTY 108 | - JWT_AUTH_TYPE 109 | - JWT_TOKEN_AUTH_MODULE 110 | - LOG_LEVEL 111 | - TZ 112 | networks: 113 | meet.jitsi: 114 | aliases: 115 | - ${XMPP_SERVER} 116 | 117 | # Focus component 118 | jicofo: 119 | image: jitsi/jicofo 120 | volumes: 121 | - ${CONFIG}/jicofo:/config 122 | environment: 123 | - ENABLE_AUTH 124 | - XMPP_DOMAIN 125 | - XMPP_AUTH_DOMAIN 126 | - XMPP_INTERNAL_MUC_DOMAIN 127 | - XMPP_SERVER 128 | - JICOFO_COMPONENT_SECRET 129 | - JICOFO_AUTH_USER 130 | - JICOFO_AUTH_PASSWORD 131 | - JICOFO_RESERVATION_REST_BASE_URL 132 | - JVB_BREWERY_MUC 133 | - JIGASI_BREWERY_MUC 134 | - JIBRI_BREWERY_MUC 135 | - JIBRI_PENDING_TIMEOUT 136 | - TZ 137 | depends_on: 138 | - prosody 139 | networks: 140 | meet.jitsi: 141 | 142 | # Video bridge 143 | jvb: 144 | image: jitsi/jvb 145 | ports: 146 | - '${JVB_PORT}:${JVB_PORT}/udp' 147 | - '${JVB_TCP_MAPPED_PORT}:${JVB_TCP_PORT}' 148 | volumes: 149 | - ${CONFIG}/jvb:/config 150 | environment: 151 | - DOCKER_HOST_ADDRESS 152 | - XMPP_AUTH_DOMAIN 153 | - XMPP_INTERNAL_MUC_DOMAIN 154 | - XMPP_SERVER 155 | - JVB_AUTH_USER 156 | - JVB_AUTH_PASSWORD 157 | - JVB_BREWERY_MUC 158 | - JVB_PORT 159 | - JVB_TCP_HARVESTER_DISABLED 160 | - JVB_TCP_PORT 161 | - JVB_STUN_SERVERS 162 | - JVB_ENABLE_APIS 163 | - TZ 164 | depends_on: 165 | - prosody 166 | networks: 167 | meet.jitsi: 168 | labels: 169 | traefik.udp.routers.jvb.entrypoints: video 170 | traefik.udp.routers.jvb.service: jvb 171 | traefik.udp.services.jvb.loadbalancer.server.port: 10000 172 | 173 | # Custom network so all services can communicate using a FQDN 174 | networks: 175 | meet.jitsi: 176 | # traefik: change the following line to your external docker network 177 | web: 178 | external: true 179 | -------------------------------------------------------------------------------- /prosody/rootfs/defaults/prosody.cfg.lua: -------------------------------------------------------------------------------- 1 | {{ $LOG_LEVEL := .Env.LOG_LEVEL | default "info" }} 2 | 3 | -- Prosody Example Configuration File 4 | -- 5 | -- Information on configuring Prosody can be found on our 6 | -- website at http://prosody.im/doc/configure 7 | -- 8 | -- Tip: You can check that the syntax of this file is correct 9 | -- when you have finished by running: luac -p prosody.cfg.lua 10 | -- If there are any errors, it will let you know what and where 11 | -- they are, otherwise it will keep quiet. 12 | -- 13 | -- The only thing left to do is rename this file to remove the .dist ending, and fill in the 14 | -- blanks. Good luck, and happy Jabbering! 15 | 16 | 17 | ---------- Server-wide settings ---------- 18 | -- Settings in this section apply to the whole server and are the default settings 19 | -- for any virtual hosts 20 | 21 | -- This is a (by default, empty) list of accounts that are admins 22 | -- for the server. Note that you must create the accounts separately 23 | -- (see http://prosody.im/doc/creating_accounts for info) 24 | -- Example: admins = { "user1@example.com", "user2@example.net" } 25 | admins = { } 26 | 27 | -- Enable use of libevent for better performance under high load 28 | -- For more information see: http://prosody.im/doc/libevent 29 | --use_libevent = true; 30 | 31 | -- This is the list of modules Prosody will load on startup. 32 | -- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too. 33 | -- Documentation on modules can be found at: http://prosody.im/doc/modules 34 | modules_enabled = { 35 | 36 | -- Generally required 37 | "roster"; -- Allow users to have a roster. Recommended ;) 38 | "saslauth"; -- Authentication for clients and servers. Recommended if you want to log in. 39 | "tls"; -- Add support for secure TLS on c2s/s2s connections 40 | "dialback"; -- s2s dialback support 41 | "disco"; -- Service discovery 42 | 43 | -- Not essential, but recommended 44 | "private"; -- Private XML storage (for room bookmarks, etc.) 45 | "vcard"; -- Allow users to set vCards 46 | 47 | -- These are commented by default as they have a performance impact 48 | --"privacy"; -- Support privacy lists 49 | --"compression"; -- Stream compression (Debian: requires lua-zlib module to work) 50 | 51 | -- Nice to have 52 | "version"; -- Replies to server version requests 53 | "uptime"; -- Report how long server has been running 54 | "time"; -- Let others know the time here on this server 55 | "ping"; -- Replies to XMPP pings with pongs 56 | "pep"; -- Enables users to publish their mood, activity, playing music and more 57 | "register"; -- Allow users to register on this server using a client and change passwords 58 | 59 | -- Admin interfaces 60 | "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands 61 | --"admin_telnet"; -- Opens telnet console interface on localhost port 5582 62 | 63 | -- HTTP modules 64 | --"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP" 65 | --"http_files"; -- Serve static files from a directory over HTTP 66 | 67 | -- Other specific functionality 68 | "posix"; -- POSIX functionality, sends server to background, enables syslog, etc. 69 | --"groups"; -- Shared roster support 70 | --"announce"; -- Send announcement to all online users 71 | --"welcome"; -- Welcome users who register accounts 72 | --"watchregistrations"; -- Alert admins of registrations 73 | --"motd"; -- Send a message to users when they log in 74 | --"legacyauth"; -- Legacy authentication. Only used by some old clients and bots. 75 | {{ if .Env.GLOBAL_MODULES }} 76 | "{{ join "\";\n\"" (splitList "," .Env.GLOBAL_MODULES) }}"; 77 | {{ end }} 78 | }; 79 | 80 | https_ports = { } 81 | 82 | -- These modules are auto-loaded, but should you want 83 | -- to disable them then uncomment them here: 84 | modules_disabled = { 85 | -- "offline"; -- Store offline messages 86 | -- "c2s"; -- Handle client connections 87 | -- "s2s"; -- Handle server-to-server connections 88 | }; 89 | 90 | -- Disable account creation by default, for security 91 | -- For more information see http://prosody.im/doc/creating_accounts 92 | allow_registration = false; 93 | 94 | daemonize = false; 95 | 96 | pidfile = "/config/data/prosody.pid"; 97 | 98 | -- Force clients to use encrypted connections? This option will 99 | -- prevent clients from authenticating unless they are using encryption. 100 | 101 | c2s_require_encryption = false 102 | 103 | -- Force certificate authentication for server-to-server connections? 104 | -- This provides ideal security, but requires servers you communicate 105 | -- with to support encryption AND present valid, trusted certificates. 106 | -- NOTE: Your version of LuaSec must support certificate verification! 107 | -- For more information see http://prosody.im/doc/s2s#security 108 | 109 | s2s_secure_auth = false 110 | 111 | -- Many servers don't support encryption or have invalid or self-signed 112 | -- certificates. You can list domains here that will not be required to 113 | -- authenticate using certificates. They will be authenticated using DNS. 114 | 115 | --s2s_insecure_domains = { "gmail.com" } 116 | 117 | -- Even if you leave s2s_secure_auth disabled, you can still require valid 118 | -- certificates for some domains by specifying a list here. 119 | 120 | --s2s_secure_domains = { "jabber.org" } 121 | 122 | -- Select the authentication backend to use. The 'internal' providers 123 | -- use Prosody's configured data storage to store the authentication data. 124 | -- To allow Prosody to offer secure authentication mechanisms to clients, the 125 | -- default provider stores passwords in plaintext. If you do not trust your 126 | -- server please see http://prosody.im/doc/modules/mod_auth_internal_hashed 127 | -- for information about using the hashed backend. 128 | 129 | authentication = "internal_hashed" 130 | 131 | -- Select the storage backend to use. By default Prosody uses flat files 132 | -- in its configured data directory, but it also supports more backends 133 | -- through modules. An "sql" backend is included by default, but requires 134 | -- additional dependencies. See http://prosody.im/doc/storage for more info. 135 | 136 | --storage = "sql" -- Default is "internal" (Debian: "sql" requires one of the 137 | -- lua-dbi-sqlite3, lua-dbi-mysql or lua-dbi-postgresql packages to work) 138 | 139 | -- For the "sql" backend, you can uncomment *one* of the below to configure: 140 | --sql = { driver = "SQLite3", database = "prosody.sqlite" } -- Default. 'database' is the filename. 141 | --sql = { driver = "MySQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" } 142 | --sql = { driver = "PostgreSQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" } 143 | 144 | -- Logging configuration 145 | -- For advanced logging see http://prosody.im/doc/logging 146 | -- 147 | -- Debian: 148 | -- Logs info and higher to /var/log 149 | -- Logs errors to syslog also 150 | log = { 151 | { levels = {min = "{{ $LOG_LEVEL }}"}, to = "console"}; 152 | } 153 | 154 | {{ if .Env.GLOBAL_CONFIG }} 155 | {{ join "\n" (splitList "\\n" .Env.GLOBAL_CONFIG) }} 156 | {{ end }} 157 | 158 | -- Enable use of native prosody 0.11 support for epoll over select 159 | network_backend = "epoll"; 160 | -- Set the TCP backlog to 511 since the kernel rounds it up to the next power of 2: 512. 161 | network_settings = { 162 | tcp_backlog = 511; 163 | } 164 | 165 | component_interface = { "*" } 166 | 167 | data_path = "/config/data" 168 | 169 | Include "conf.d/*.cfg.lua" 170 | -------------------------------------------------------------------------------- /env.example: -------------------------------------------------------------------------------- 1 | # Security 2 | # 3 | # Set these to strong passwords to avoid intruders from impersonating a service account 4 | # The service(s) won't start unless these are specified 5 | # Running ./gen-passwords.sh will update .env with strong passwords 6 | # You may skip the Jigasi and Jibri passwords if you are not using those 7 | # DO NOT reuse passwords 8 | # 9 | 10 | # XMPP component password for Jicofo 11 | JICOFO_COMPONENT_SECRET= 12 | 13 | # XMPP password for Jicofo client connections 14 | JICOFO_AUTH_PASSWORD= 15 | 16 | # XMPP password for JVB client connections 17 | JVB_AUTH_PASSWORD= 18 | 19 | # XMPP password for Jigasi MUC client connections 20 | JIGASI_XMPP_PASSWORD= 21 | 22 | # XMPP recorder password for Jibri client connections 23 | JIBRI_RECORDER_PASSWORD= 24 | 25 | # XMPP password for Jibri client connections 26 | JIBRI_XMPP_PASSWORD= 27 | 28 | 29 | # 30 | # Basic configuration options 31 | # 32 | 33 | # Directory where all configuration will be stored 34 | CONFIG=~/.jitsi-meet-cfg 35 | 36 | # Exposed HTTP port 37 | HTTP_PORT=8000 38 | 39 | # Exposed HTTPS port 40 | HTTPS_PORT=8443 41 | 42 | # System time zone 43 | TZ=UTC 44 | 45 | # Public URL for the web service 46 | #PUBLIC_URL=https://meet.example.com 47 | 48 | # IP address of the Docker host 49 | # See the "Running behind NAT or on a LAN environment" section in the README 50 | #DOCKER_HOST_ADDRESS=192.168.1.1 51 | 52 | 53 | # 54 | # Let's Encrypt configuration 55 | # 56 | 57 | # Enable Let's Encrypt certificate generation 58 | #ENABLE_LETSENCRYPT=1 59 | 60 | # Domain for which to generate the certificate 61 | #LETSENCRYPT_DOMAIN=meet.example.com 62 | 63 | # E-Mail for receiving important account notifications (mandatory) 64 | #LETSENCRYPT_EMAIL=alice@atlanta.net 65 | 66 | 67 | # 68 | # Etherpad integration (for document sharing) 69 | # 70 | 71 | # Set etherpad-lite URL (uncomment to enable) 72 | #ETHERPAD_URL_BASE=http://etherpad.meet.jitsi:9001 73 | 74 | 75 | # 76 | # Basic Jigasi configuration options (needed for SIP gateway support) 77 | # 78 | 79 | # SIP URI for incoming / outgoing calls 80 | #JIGASI_SIP_URI=test@sip2sip.info 81 | 82 | # Password for the specified SIP account as a clear text 83 | #JIGASI_SIP_PASSWORD=passw0rd 84 | 85 | # SIP server (use the SIP account domain if in doubt) 86 | #JIGASI_SIP_SERVER=sip2sip.info 87 | 88 | # SIP server port 89 | #JIGASI_SIP_PORT=5060 90 | 91 | # SIP server transport 92 | #JIGASI_SIP_TRANSPORT=UDP 93 | 94 | # 95 | # Authentication configuration (see README for details) 96 | # 97 | 98 | # Enable authentication 99 | #ENABLE_AUTH=1 100 | 101 | # Enable guest access 102 | #ENABLE_GUESTS=1 103 | 104 | # Select authentication type: internal, jwt or ldap 105 | #AUTH_TYPE=internal 106 | 107 | # JWT authentication 108 | # 109 | 110 | # Application identifier 111 | #JWT_APP_ID=my_jitsi_app_id 112 | 113 | # Application secret known only to your token 114 | #JWT_APP_SECRET=my_jitsi_app_secret 115 | 116 | # (Optional) Set asap_accepted_issuers as a comma separated list 117 | #JWT_ACCEPTED_ISSUERS=my_web_client,my_app_client 118 | 119 | # (Optional) Set asap_accepted_audiences as a comma separated list 120 | #JWT_ACCEPTED_AUDIENCES=my_server1,my_server2 121 | 122 | 123 | # LDAP authentication (for more information see the Cyrus SASL saslauthd.conf man page) 124 | # 125 | 126 | # LDAP url for connection 127 | #LDAP_URL=ldaps://ldap.domain.com/ 128 | 129 | # LDAP base DN. Can be empty 130 | #LDAP_BASE=DC=example,DC=domain,DC=com 131 | 132 | # LDAP user DN. Do not specify this parameter for the anonymous bind 133 | #LDAP_BINDDN=CN=binduser,OU=users,DC=example,DC=domain,DC=com 134 | 135 | # LDAP user password. Do not specify this parameter for the anonymous bind 136 | #LDAP_BINDPW=LdapUserPassw0rd 137 | 138 | # LDAP filter. Tokens example: 139 | # %1-9 - if the input key is user@mail.domain.com, then %1 is com, %2 is domain and %3 is mail 140 | # %s - %s is replaced by the complete service string 141 | # %r - %r is replaced by the complete realm string 142 | #LDAP_FILTER=(sAMAccountName=%u) 143 | 144 | # LDAP authentication method 145 | #LDAP_AUTH_METHOD=bind 146 | 147 | # LDAP version 148 | #LDAP_VERSION=3 149 | 150 | # LDAP TLS using 151 | #LDAP_USE_TLS=1 152 | 153 | # List of SSL/TLS ciphers to allow 154 | #LDAP_TLS_CIPHERS=SECURE256:SECURE128:!AES-128-CBC:!ARCFOUR-128:!CAMELLIA-128-CBC:!3DES-CBC:!CAMELLIA-128-CBC 155 | 156 | # Require and verify server certificate 157 | #LDAP_TLS_CHECK_PEER=1 158 | 159 | # Path to CA cert file. Used when server certificate verify is enabled 160 | #LDAP_TLS_CACERT_FILE=/etc/ssl/certs/ca-certificates.crt 161 | 162 | # Path to CA certs directory. Used when server certificate verify is enabled 163 | #LDAP_TLS_CACERT_DIR=/etc/ssl/certs 164 | 165 | # Wether to use starttls, implies LDAPv3 and requires ldap:// instead of ldaps:// 166 | # LDAP_START_TLS=1 167 | 168 | 169 | # 170 | # Advanced configuration options (you generally don't need to change these) 171 | # 172 | 173 | # Internal XMPP domain 174 | XMPP_DOMAIN=meet.jitsi 175 | 176 | # Internal XMPP server 177 | XMPP_SERVER=xmpp.meet.jitsi 178 | 179 | # Internal XMPP server URL 180 | XMPP_BOSH_URL_BASE=http://xmpp.meet.jitsi:5280 181 | 182 | # Internal XMPP domain for authenticated services 183 | XMPP_AUTH_DOMAIN=auth.meet.jitsi 184 | 185 | # XMPP domain for the MUC 186 | XMPP_MUC_DOMAIN=muc.meet.jitsi 187 | 188 | # XMPP domain for the internal MUC used for jibri, jigasi and jvb pools 189 | XMPP_INTERNAL_MUC_DOMAIN=internal-muc.meet.jitsi 190 | 191 | # XMPP domain for unauthenticated users 192 | XMPP_GUEST_DOMAIN=guest.meet.jitsi 193 | 194 | # Custom Prosody modules for XMPP_DOMAIN (comma separated) 195 | XMPP_MODULES= 196 | 197 | # Custom Prosody modules for MUC component (comma separated) 198 | XMPP_MUC_MODULES= 199 | 200 | # Custom Prosody modules for internal MUC component (comma separated) 201 | XMPP_INTERNAL_MUC_MODULES= 202 | 203 | # MUC for the JVB pool 204 | JVB_BREWERY_MUC=jvbbrewery 205 | 206 | # XMPP user for JVB client connections 207 | JVB_AUTH_USER=jvb 208 | 209 | # STUN servers used to discover the server's public IP 210 | JVB_STUN_SERVERS=meet-jit-si-turnrelay.jitsi.net:443 211 | 212 | # Media port for the Jitsi Videobridge 213 | JVB_PORT=10000 214 | 215 | # TCP Fallback for Jitsi Videobridge for when UDP isn't available 216 | JVB_TCP_HARVESTER_DISABLED=true 217 | JVB_TCP_PORT=4443 218 | JVB_TCP_MAPPED_PORT=4443 219 | 220 | # A comma separated list of APIs to enable when the JVB is started [default: none] 221 | # See https://github.com/jitsi/jitsi-videobridge/blob/master/doc/rest.md for more information 222 | #JVB_ENABLE_APIS=rest,colibri 223 | 224 | # XMPP user for Jicofo client connections. 225 | # NOTE: this option doesn't currently work due to a bug 226 | JICOFO_AUTH_USER=focus 227 | 228 | # Base URL of Jicofo's reservation REST API 229 | #JICOFO_RESERVATION_REST_BASE_URL=http://reservation.example.com 230 | 231 | # Enable Jicofo's health check REST API (http://:8888/about/health) 232 | #JICOFO_ENABLE_HEALTH_CHECKS=true 233 | 234 | # XMPP user for Jigasi MUC client connections 235 | JIGASI_XMPP_USER=jigasi 236 | 237 | # MUC name for the Jigasi pool 238 | JIGASI_BREWERY_MUC=jigasibrewery 239 | 240 | # Minimum port for media used by Jigasi 241 | JIGASI_PORT_MIN=20000 242 | 243 | # Maximum port for media used by Jigasi 244 | JIGASI_PORT_MAX=20050 245 | 246 | # Enable SDES srtp 247 | #JIGASI_ENABLE_SDES_SRTP=1 248 | 249 | # Keepalive method 250 | #JIGASI_SIP_KEEP_ALIVE_METHOD=OPTIONS 251 | 252 | # Health-check extension 253 | #JIGASI_HEALTH_CHECK_SIP_URI=keepalive 254 | 255 | # Health-check interval 256 | #JIGASI_HEALTH_CHECK_INTERVAL=300000 257 | # 258 | # Enable Jigasi transcription 259 | #ENABLE_TRANSCRIPTIONS=1 260 | 261 | # Jigasi will record audio when transcriber is on [default: false] 262 | #JIGASI_TRANSCRIBER_RECORD_AUDIO=true 263 | 264 | # Jigasi will send transcribed text to the chat when transcriber is on [default: false] 265 | #JIGASI_TRANSCRIBER_SEND_TXT=true 266 | 267 | # Jigasi will post an url to the chat with transcription file [default: false] 268 | #JIGASI_TRANSCRIBER_ADVERTISE_URL=true 269 | 270 | # Credentials for connect to Cloud Google API from Jigasi 271 | # Please read https://cloud.google.com/text-to-speech/docs/quickstart-protocol 272 | # section "Before you begin" paragraph 1 to 5 273 | # Copy the values from the json to the related env vars 274 | #GC_PROJECT_ID= 275 | #GC_PRIVATE_KEY_ID= 276 | #GC_PRIVATE_KEY= 277 | #GC_CLIENT_EMAIL= 278 | #GC_CLIENT_ID= 279 | #GC_CLIENT_CERT_URL= 280 | 281 | # Enable recording 282 | #ENABLE_RECORDING=1 283 | 284 | # XMPP domain for the jibri recorder 285 | XMPP_RECORDER_DOMAIN=recorder.meet.jitsi 286 | 287 | # XMPP recorder user for Jibri client connections 288 | JIBRI_RECORDER_USER=recorder 289 | 290 | # Directory for recordings inside Jibri container 291 | JIBRI_RECORDING_DIR=/config/recordings 292 | 293 | # The finalizing script. Will run after recording is complete 294 | JIBRI_FINALIZE_RECORDING_SCRIPT_PATH=/config/finalize.sh 295 | 296 | # XMPP user for Jibri client connections 297 | JIBRI_XMPP_USER=jibri 298 | 299 | # MUC name for the Jibri pool 300 | JIBRI_BREWERY_MUC=jibribrewery 301 | 302 | # MUC connection timeout 303 | JIBRI_PENDING_TIMEOUT=90 304 | 305 | # When jibri gets a request to start a service for a room, the room 306 | # jid will look like: roomName@optional.prefixes.subdomain.xmpp_domain 307 | # We'll build the url for the call by transforming that into: 308 | # https://xmpp_domain/subdomain/roomName 309 | # So if there are any prefixes in the jid (like jitsi meet, which 310 | # has its participants join a muc at conference.xmpp_domain) then 311 | # list that prefix here so it can be stripped out to generate 312 | # the call url correctly 313 | JIBRI_STRIP_DOMAIN_JID=muc 314 | 315 | # Directory for logs inside Jibri container 316 | JIBRI_LOGS_DIR=/config/logs 317 | 318 | # Disable HTTPS: handle TLS connections outside of this setup 319 | #DISABLE_HTTPS=1 320 | 321 | # Redirect HTTP traffic to HTTPS 322 | # Necessary for Let's Encrypt, relies on standard HTTPS port (443) 323 | #ENABLE_HTTP_REDIRECT=1 324 | 325 | # Container restart policy 326 | # Defaults to unless-stopped 327 | RESTART_POLICY=unless-stopped 328 | -------------------------------------------------------------------------------- /jigasi/rootfs/defaults/sip-communicator.properties: -------------------------------------------------------------------------------- 1 | net.java.sip.communicator.impl.protocol.SingleCallInProgressPolicy.enabled=false 2 | 3 | # Adjust opus encoder complexity 4 | net.java.sip.communicator.impl.neomedia.codec.audio.opus.encoder.COMPLEXITY=10 5 | 6 | # Disables packet logging 7 | net.java.sip.communicator.packetlogging.PACKET_LOGGING_ENABLED=false 8 | 9 | # SIP account 10 | net.java.sip.communicator.impl.protocol.sip.acc1=acc1 11 | {{ if and .Env.JIGASI_SIP_PORT .Env.JIGASI_SIP_TRANSPORT }} 12 | net.java.sip.communicator.impl.protocol.sip.acc1.PROXY_ADDRESS={{ .Env.JIGASI_SIP_SERVER }} 13 | net.java.sip.communicator.impl.protocol.sip.acc1.PROXY_AUTO_CONFIG=false 14 | net.java.sip.communicator.impl.protocol.sip.acc1.PROXY_PORT={{ .Env.JIGASI_SIP_PORT | default "5060" }} 15 | net.java.sip.communicator.impl.protocol.sip.acc1.PREFERRED_TRANSPORT={{ .Env.JIGASI_SIP_TRANSPORT | default "UDP" }} 16 | {{ end }} 17 | {{ if .Env.JIGASI_ENABLE_SDES_SRTP | default "0" | toBool }} 18 | net.java.sip.communicator.impl.protocol.sip.acc1.SAVP_OPTION=1 19 | net.java.sip.communicator.impl.protocol.sip.acc1.DEFAULT_ENCRYPTION=true 20 | net.java.sip.communicator.impl.protocol.sip.acc1.DEFAULT_SIPZRTP_ATTRIBUTE=false 21 | net.java.sip.communicator.impl.protocol.sip.acc1.ENCRYPTION_PROTOCOL.ZRTP=0 22 | net.java.sip.communicator.impl.protocol.sip.acc1.ENCRYPTION_PROTOCOL.SDES=1 23 | net.java.sip.communicator.impl.protocol.sip.acc1.ENCRYPTION_PROTOCOL.DTLS-SRTP=0 24 | net.java.sip.communicator.impl.protocol.sip.acc1.ENCRYPTION_PROTOCOL_STATUS.ZRTP=false 25 | net.java.sip.communicator.impl.protocol.sip.acc1.ENCRYPTION_PROTOCOL_STATUS.SDES=true 26 | net.java.sip.communicator.impl.protocol.sip.acc1.ENCRYPTION_PROTOCOL_STATUS.DTLS-SRTP=false 27 | net.java.sip.communicator.impl.protocol.sip.acc1.SDES_CIPHER_SUITES=AES_CM_128_HMAC_SHA1_80,AES_CM_128_HMAC_SHA1_32 28 | {{ end }} 29 | net.java.sip.communicator.impl.protocol.sip.acc1.ACCOUNT_UID=SIP\:{{ .Env.JIGASI_SIP_URI }} 30 | net.java.sip.communicator.impl.protocol.sip.acc1.PASSWORD={{ .Env.JIGASI_SIP_PASSWORD | b64enc }} 31 | net.java.sip.communicator.impl.protocol.sip.acc1.PROTOCOL_NAME=SIP 32 | net.java.sip.communicator.impl.protocol.sip.acc1.SERVER_ADDRESS={{ .Env.JIGASI_SIP_SERVER }} 33 | net.java.sip.communicator.impl.protocol.sip.acc1.USER_ID={{ .Env.JIGASI_SIP_URI }} 34 | net.java.sip.communicator.impl.protocol.sip.acc1.KEEP_ALIVE_INTERVAL=25 35 | net.java.sip.communicator.impl.protocol.sip.acc1.KEEP_ALIVE_METHOD={{ .Env.JIGASI_SIP_KEEP_ALIVE_METHOD | default "OPTIONS" }} 36 | net.java.sip.communicator.impl.protocol.sip.acc1.VOICEMAIL_ENABLED=false 37 | net.java.sip.communicator.impl.protocol.sip.acc1.JITSI_MEET_ROOM_HEADER_NAME=X-Room-Name 38 | net.java.sip.communicator.impl.protocol.sip.acc1.JITSI_MEET_DOMAIN_BASE_HEADER_NAME=X-Domain-Base 39 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.AMR-WB/16000=750 40 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.G722/8000=700 41 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.GSM/8000=0 42 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.H263-1998/90000=0 43 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.H264/90000=0 44 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.PCMA/8000=600 45 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.PCMU/8000=650 46 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.SILK/12000=0 47 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.SILK/16000=0 48 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.SILK/24000=0 49 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.SILK/8000=0 50 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.VP8/90000=0 51 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.iLBC/8000=10 52 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.opus/48000=1000 53 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.red/90000=0 54 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.speex/16000=0 55 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.speex/32000=0 56 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.speex/8000=0 57 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.telephone-event/8000=1 58 | net.java.sip.communicator.impl.protocol.sip.acc1.Encodings.ulpfec/90000=0 59 | net.java.sip.communicator.impl.protocol.sip.acc1.OVERRIDE_ENCODINGS=true 60 | net.java.sip.communicator.impl.protocol.sip.acc1.DOMAIN_BASE={{ .Env.XMPP_DOMAIN }} 61 | 62 | # XMPP account used for control 63 | net.java.sip.communicator.impl.protocol.jabber.acc1=acc1 64 | net.java.sip.communicator.impl.protocol.jabber.acc1.ACCOUNT_UID=Jabber:{{ .Env.JIGASI_XMPP_USER }}@{{ .Env.XMPP_AUTH_DOMAIN }} 65 | net.java.sip.communicator.impl.protocol.jabber.acc1.USER_ID={{ .Env.JIGASI_XMPP_USER }}@{{ .Env.XMPP_AUTH_DOMAIN }} 66 | net.java.sip.communicator.impl.protocol.jabber.acc1.IS_SERVER_OVERRIDDEN=true 67 | net.java.sip.communicator.impl.protocol.jabber.acc1.SERVER_ADDRESS={{ .Env.XMPP_SERVER }} 68 | net.java.sip.communicator.impl.protocol.jabber.acc1.PASSWORD={{ .Env.JIGASI_XMPP_PASSWORD | b64enc }} 69 | net.java.sip.communicator.impl.protocol.jabber.acc1.AUTO_GENERATE_RESOURCE=true 70 | net.java.sip.communicator.impl.protocol.jabber.acc1.RESOURCE_PRIORITY=30 71 | net.java.sip.communicator.impl.protocol.jabber.acc1.IS_CARBON_DISABLED=true 72 | net.java.sip.communicator.impl.protocol.jabber.acc1.DEFAULT_ENCRYPTION=true 73 | net.java.sip.communicator.impl.protocol.jabber.acc1.IS_USE_ICE=true 74 | net.java.sip.communicator.impl.protocol.jabber.acc1.IS_ACCOUNT_DISABLED=false 75 | net.java.sip.communicator.impl.protocol.jabber.acc1.IS_PREFERRED_PROTOCOL=false 76 | net.java.sip.communicator.impl.protocol.jabber.acc1.AUTO_DISCOVER_JINGLE_NODES=false 77 | net.java.sip.communicator.impl.protocol.jabber.acc1.PROTOCOL=Jabber 78 | net.java.sip.communicator.impl.protocol.jabber.acc1.IS_USE_UPNP=false 79 | net.java.sip.communicator.impl.protocol.jabber.acc1.USE_DEFAULT_STUN_SERVER=true 80 | net.java.sip.communicator.impl.protocol.jabber.acc1.ENCRYPTION_PROTOCOL.DTLS-SRTP=0 81 | net.java.sip.communicator.impl.protocol.jabber.acc1.ENCRYPTION_PROTOCOL_STATUS.DTLS-SRTP=true 82 | net.java.sip.communicator.impl.protocol.jabber.acc1.VIDEO_CALLING_DISABLED=true 83 | net.java.sip.communicator.impl.protocol.jabber.acc1.OVERRIDE_ENCODINGS=true 84 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.G722/8000=705 85 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.GSM/8000=0 86 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.H263-1998/90000=0 87 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.H264/90000=0 88 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.PCMA/8000=0 89 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.PCMU/8000=0 90 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.SILK/12000=0 91 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.SILK/16000=0 92 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.SILK/24000=0 93 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.SILK/8000=0 94 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.VP8/90000=0 95 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.iLBC/8000=0 96 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.opus/48000=750 97 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.speex/16000=0 98 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.speex/32000=0 99 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.speex/8000=0 100 | net.java.sip.communicator.impl.protocol.jabber.acc1.Encodings.telephone-event/8000=0 101 | net.java.sip.communicator.impl.protocol.jabber.acc1.BREWERY={{ .Env.JIGASI_BREWERY_MUC }}@{{ .Env.XMPP_INTERNAL_MUC_DOMAIN }} 102 | net.java.sip.communicator.impl.protocol.jabber.acc1.DOMAIN_BASE={{ .Env.XMPP_DOMAIN }} 103 | 104 | org.jitsi.jigasi.BREWERY_ENABLED=true 105 | 106 | org.jitsi.jigasi.HEALTH_CHECK_SIP_URI={{ .Env.JIGASI_HEALTH_CHECK_SIP_URI | default "" }} 107 | org.jitsi.jigasi.HEALTH_CHECK_INTERVAL={{ .Env.JIGASI_HEALTH_CHECK_INTERVAL | default "300000" }} 108 | org.jitsi.jigasi.HEALTH_CHECK_TIMEOUT=600000 109 | 110 | org.jitsi.jigasi.xmpp.acc.IS_SERVER_OVERRIDDEN=true 111 | org.jitsi.jigasi.xmpp.acc.SERVER_ADDRESS={{ .Env.XMPP_SERVER }} 112 | org.jitsi.jigasi.xmpp.acc.VIDEO_CALLING_DISABLED=true 113 | org.jitsi.jigasi.xmpp.acc.JINGLE_NODES_ENABLED=false 114 | org.jitsi.jigasi.xmpp.acc.AUTO_DISCOVER_STUN=false 115 | org.jitsi.jigasi.xmpp.acc.IM_DISABLED=true 116 | org.jitsi.jigasi.xmpp.acc.SERVER_STORED_INFO_DISABLED=true 117 | org.jitsi.jigasi.xmpp.acc.IS_FILE_TRANSFER_DISABLED=true 118 | {{ if .Env.ENABLE_AUTH | default "0" | toBool }} 119 | org.jitsi.jigasi.xmpp.acc.USER_ID={{ .Env.JIGASI_XMPP_USER }}@{{ .Env.XMPP_AUTH_DOMAIN }} 120 | org.jitsi.jigasi.xmpp.acc.PASS={{ .Env.JIGASI_XMPP_PASSWORD }} 121 | org.jitsi.jigasi.xmpp.acc.ANONYMOUS_AUTH=false 122 | org.jitsi.jigasi.xmpp.acc.ALLOW_NON_SECURE=true 123 | {{ end }} 124 | 125 | # Activate this property if you are using self-signed certificates or other 126 | # type of non-trusted certicates. In this mode your service trust in the 127 | # remote certificates always. 128 | net.java.sip.communicator.service.gui.ALWAYS_TRUST_MODE_ENABLED=true 129 | 130 | {{ if .Env.ENABLE_TRANSCRIPTIONS | default "0" | toBool }} 131 | # Transcription config 132 | org.jitsi.jigasi.ENABLE_TRANSCRIPTION=true 133 | org.jitsi.jigasi.transcription.ENABLE_TRANSLATION=true 134 | org.jitsi.jigasi.transcription.DIRECTORY=/tmp/transcripts 135 | org.jitsi.jigasi.transcription.BASE_URL={{ .Env.PUBLIC_URL }}/transcripts 136 | org.jitsi.jigasi.transcription.jetty.port=-1 137 | org.jitsi.jigasi.transcription.ADVERTISE_URL={{ .Env.JIGASI_TRANSCRIBER_ADVERTISE_URL | default "false"}} 138 | org.jitsi.jigasi.transcription.SAVE_JSON=false 139 | org.jitsi.jigasi.transcription.SEND_JSON=true 140 | org.jitsi.jigasi.transcription.SAVE_TXT=true 141 | org.jitsi.jigasi.transcription.SEND_TXT={{ .Env.JIGASI_TRANSCRIBER_SEND_TXT | default "false"}} 142 | org.jitsi.jigasi.transcription.RECORD_AUDIO={{ .Env.JIGASI_TRANSCRIBER_RECORD_AUDIO | default "false"}} 143 | org.jitsi.jigasi.transcription.RECORD_AUDIO_FORMAT=wav 144 | {{end}} 145 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | 204 | -------------------------------------------------------------------------------- /etherpad/rootfs/defaults/settings.json: -------------------------------------------------------------------------------- 1 | /* 2 | * This file must be valid JSON. But comments are allowed 3 | * 4 | * Please edit settings.json, not settings.json.template 5 | * 6 | * Please note that since Etherpad 1.6.0 you can store DB credentials in a 7 | * separate file (credentials.json). 8 | */ 9 | { 10 | /* 11 | * Name your instance! 12 | */ 13 | "title": "Video Chat", 14 | 15 | /* 16 | * favicon default name 17 | * alternatively, set up a fully specified Url to your own favicon 18 | */ 19 | "favicon": "favicon.ico", 20 | 21 | /* 22 | * IP and port which etherpad should bind at 23 | */ 24 | "ip": "0.0.0.0", 25 | "port" : 9001, 26 | 27 | /* 28 | * Option to hide/show the settings.json in admin page. 29 | * 30 | * Default option is set to true 31 | */ 32 | "showSettingsInAdminPage" : true, 33 | 34 | /* 35 | * Node native SSL support 36 | * 37 | * This is disabled by default. 38 | * Make sure to have the minimum and correct file access permissions set so 39 | * that the Etherpad server can access them 40 | */ 41 | 42 | /* 43 | "ssl" : { 44 | "key" : "/path-to-your/epl-server.key", 45 | "cert" : "/path-to-your/epl-server.crt", 46 | "ca": ["/path-to-your/epl-intermediate-cert1.crt", "/path-to-your/epl-intermediate-cert2.crt"] 47 | }, 48 | */ 49 | 50 | /* 51 | * The type of the database. 52 | * 53 | * You can choose between many DB drivers, for example: dirty, postgres, 54 | * sqlite, mysql. 55 | * 56 | * You shouldn't use "dirty" for for anything else than testing or 57 | * development. 58 | * 59 | * For a complete list of the supported drivers, please consult: 60 | * https://www.npmjs.com/package/ueberdb2 61 | */ 62 | 63 | "dbType" : "dirty", 64 | 65 | /* 66 | * Database specific settings (dependent on dbType). 67 | * 68 | * Remember that since Etherpad 1.6.0 you can also store these informations in 69 | * credentials.json. 70 | */ 71 | "dbSettings" : { 72 | "filename" : "var/dirty.db" 73 | }, 74 | 75 | /* 76 | * An Example of MySQL Configuration (commented out). 77 | * 78 | * See: https://github.com/ether/etherpad-lite/wiki/How-to-use-Etherpad-Lite-with-MySQL 79 | */ 80 | 81 | /* 82 | "dbType" : "mysql", 83 | "dbSettings" : { 84 | "user" : "etherpaduser", 85 | "host" : "localhost", 86 | "port" : 3306, 87 | "password": "PASSWORD", 88 | "database": "etherpad_lite_db", 89 | "charset" : "utf8mb4" 90 | }, 91 | */ 92 | 93 | /* 94 | * The default text of a pad 95 | */ 96 | "defaultPadText" : "Welcome to Web Chat!\n\n", 97 | 98 | /* 99 | * Default Pad behavior. 100 | * 101 | * Change them if you want to override. 102 | */ 103 | "padOptions": { 104 | "noColors": false, 105 | "showControls": true, 106 | "showChat": true, 107 | "showLineNumbers": true, 108 | "useMonospaceFont": false, 109 | "userName": false, 110 | "userColor": false, 111 | "rtl": false, 112 | "alwaysShowChat": false, 113 | "chatAndUsers": false, 114 | "lang": "en-gb" 115 | }, 116 | 117 | /* 118 | * Pad Shortcut Keys 119 | */ 120 | "padShortcutEnabled" : { 121 | "altF9" : true, /* focus on the File Menu and/or editbar */ 122 | "altC" : true, /* focus on the Chat window */ 123 | "cmdShift2" : true, /* shows a gritter popup showing a line author */ 124 | "delete" : true, 125 | "return" : true, 126 | "esc" : true, /* in mozilla versions 14-19 avoid reconnecting pad */ 127 | "cmdS" : true, /* save a revision */ 128 | "tab" : true, /* indent */ 129 | "cmdZ" : true, /* undo/redo */ 130 | "cmdY" : true, /* redo */ 131 | "cmdI" : true, /* italic */ 132 | "cmdB" : true, /* bold */ 133 | "cmdU" : true, /* underline */ 134 | "cmd5" : true, /* strike through */ 135 | "cmdShiftL" : true, /* unordered list */ 136 | "cmdShiftN" : true, /* ordered list */ 137 | "cmdShift1" : true, /* ordered list */ 138 | "cmdShiftC" : true, /* clear authorship */ 139 | "cmdH" : true, /* backspace */ 140 | "ctrlHome" : true, /* scroll to top of pad */ 141 | "pageUp" : true, 142 | "pageDown" : true 143 | }, 144 | 145 | /* 146 | * Should we suppress errors from being visible in the default Pad Text? 147 | */ 148 | "suppressErrorsInPadText" : true, 149 | 150 | /* 151 | * If this option is enabled, a user must have a session to access pads. 152 | * This effectively allows only group pads to be accessed. 153 | */ 154 | "requireSession" : false, 155 | 156 | /* 157 | * Users may edit pads but not create new ones. 158 | * 159 | * Pad creation is only via the API. 160 | * This applies both to group pads and regular pads. 161 | */ 162 | "editOnly" : false, 163 | 164 | /* 165 | * If set to true, those users who have a valid session will automatically be 166 | * granted access to password protected pads. 167 | */ 168 | "sessionNoPassword" : false, 169 | 170 | /* 171 | * If true, all css & js will be minified before sending to the client. 172 | * 173 | * This will improve the loading performance massively, but makes it difficult 174 | * to debug the javascript/css 175 | */ 176 | "minify" : true, 177 | 178 | /* 179 | * How long may clients use served javascript code (in seconds)? 180 | * 181 | * Not setting this may cause problems during deployment. 182 | * Set to 0 to disable caching. 183 | */ 184 | "maxAge" : 21600, // 60 * 60 * 6 = 6 hours 185 | 186 | /* 187 | * Absolute path to the Abiword executable. 188 | * 189 | * Abiword is needed to get advanced import/export features of pads. Setting 190 | * it to null disables Abiword and will only allow plain text and HTML 191 | * import/exports. 192 | */ 193 | "abiword" : null, 194 | 195 | /* 196 | * This is the absolute path to the soffice executable. 197 | * 198 | * LibreOffice can be used in lieu of Abiword to export pads. 199 | * Setting it to null disables LibreOffice exporting. 200 | */ 201 | "soffice" : null, 202 | 203 | /* 204 | * Path to the Tidy executable. 205 | * 206 | * Tidy is used to improve the quality of exported pads. 207 | * Setting it to null disables Tidy. 208 | */ 209 | "tidyHtml" : null, 210 | 211 | /* 212 | * Allow import of file types other than the supported ones: 213 | * txt, doc, docx, rtf, odt, html & htm 214 | */ 215 | "allowUnknownFileEnds" : true, 216 | 217 | /* 218 | * This setting is used if you require authentication of all users. 219 | * 220 | * Note: "/admin" always requires authentication. 221 | */ 222 | "requireAuthentication" : false, 223 | 224 | /* 225 | * Require authorization by a module, or a user with is_admin set, see below. 226 | */ 227 | "requireAuthorization" : false, 228 | 229 | /* 230 | * When you use NGINX or another proxy/load-balancer set this to true. 231 | */ 232 | "trustProxy" : false, 233 | 234 | /* 235 | * Privacy: disable IP logging 236 | */ 237 | "disableIPlogging" : false, 238 | 239 | /* 240 | * Time (in seconds) to automatically reconnect pad when a "Force reconnect" 241 | * message is shown to user. 242 | * 243 | * Set to 0 to disable automatic reconnection. 244 | */ 245 | "automaticReconnectionTimeout" : 0, 246 | 247 | /* 248 | * By default, when caret is moved out of viewport, it scrolls the minimum 249 | * height needed to make this line visible. 250 | */ 251 | "scrollWhenFocusLineIsOutOfViewport": { 252 | 253 | /* 254 | * Percentage of viewport height to be additionally scrolled. 255 | * 256 | * E.g.: use "percentage.editionAboveViewport": 0.5, to place caret line in 257 | * the middle of viewport, when user edits a line above of the 258 | * viewport 259 | * 260 | * Set to 0 to disable extra scrolling 261 | */ 262 | "percentage": { 263 | "editionAboveViewport": 0, 264 | "editionBelowViewport": 0 265 | }, 266 | 267 | /* 268 | * Time (in milliseconds) used to animate the scroll transition. 269 | * Set to 0 to disable animation 270 | */ 271 | "duration": 0, 272 | 273 | /* 274 | * Flag to control if it should scroll when user places the caret in the 275 | * last line of the viewport 276 | */ 277 | "scrollWhenCaretIsInTheLastLineOfViewport": false, 278 | 279 | /* 280 | * Percentage of viewport height to be additionally scrolled when user 281 | * presses arrow up in the line of the top of the viewport. 282 | * 283 | * Set to 0 to let the scroll to be handled as default by Etherpad 284 | */ 285 | "percentageToScrollWhenUserPressesArrowUp": 0 286 | }, 287 | 288 | /* 289 | * Users for basic authentication. 290 | * 291 | * is_admin = true gives access to /admin. 292 | * If you do not uncomment this, /admin will not be available! 293 | * 294 | * WARNING: passwords should not be stored in plaintext in this file. 295 | * If you want to mitigate this, please install ep_hash_auth and 296 | * follow the section "secure your installation" in README.md 297 | */ 298 | 299 | /* 300 | "users": { 301 | "admin": { 302 | // "password" can be replaced with "hash" if you install ep_hash_auth 303 | "password": "changeme1", 304 | "is_admin": true 305 | }, 306 | "user": { 307 | // "password" can be replaced with "hash" if you install ep_hash_auth 308 | "password": "changeme1", 309 | "is_admin": false 310 | } 311 | }, 312 | */ 313 | 314 | /* 315 | * Restrict socket.io transport methods 316 | */ 317 | "socketTransportProtocols" : ["xhr-polling", "jsonp-polling", "htmlfile"], 318 | 319 | /* 320 | * Allow Load Testing tools to hit the Etherpad Instance. 321 | * 322 | * WARNING: this will disable security on the instance. 323 | */ 324 | "loadTest": false, 325 | 326 | /* 327 | * Disable indentation on new line when previous line ends with some special 328 | * chars (':', '[', '(', '{') 329 | */ 330 | 331 | /* 332 | "indentationOnNewLine": false, 333 | */ 334 | 335 | /* 336 | * Toolbar buttons configuration. 337 | * 338 | * Uncomment to customize. 339 | */ 340 | 341 | /* 342 | "toolbar": { 343 | "left": [ 344 | ["bold", "italic", "underline", "strikethrough"], 345 | ["orderedlist", "unorderedlist", "indent", "outdent"], 346 | ["undo", "redo"], 347 | ["clearauthorship"] 348 | ], 349 | "right": [ 350 | ["importexport", "timeslider", "savedrevision"], 351 | ["settings", "embed"], 352 | ["showusers"] 353 | ], 354 | "timeslider": [ 355 | ["timeslider_export", "timeslider_returnToPad"] 356 | ] 357 | }, 358 | */ 359 | 360 | /* 361 | * The log level we are using. 362 | * 363 | * Valid values: DEBUG, INFO, WARN, ERROR 364 | */ 365 | "loglevel": "INFO", 366 | 367 | /* 368 | * Logging configuration. See log4js documentation for further information: 369 | * https://github.com/nomiddlename/log4js-node 370 | * 371 | * You can add as many appenders as you want here. 372 | */ 373 | "logconfig" : 374 | { "appenders": [ 375 | { "type": "console" 376 | //, "category": "access"// only logs pad access 377 | } 378 | 379 | /* 380 | , { "type": "file" 381 | , "filename": "your-log-file-here.log" 382 | , "maxLogSize": 1024 383 | , "backups": 3 // how many log files there're gonna be at max 384 | //, "category": "test" // only log a specific category 385 | } 386 | */ 387 | 388 | /* 389 | , { "type": "logLevelFilter" 390 | , "level": "warn" // filters out all log messages that have a lower level than "error" 391 | , "appender": 392 | { Use whatever appender you want here } 393 | } 394 | */ 395 | 396 | /* 397 | , { "type": "logLevelFilter" 398 | , "level": "error" // filters out all log messages that have a lower level than "error" 399 | , "appender": 400 | { "type": "smtp" 401 | , "subject": "An error occurred in your EPL instance!" 402 | , "recipients": "bar@blurdybloop.com, baz@blurdybloop.com" 403 | , "sendInterval": 300 // 60 * 5 = 5 minutes -- will buffer log messages; set to 0 to send a mail for every message 404 | , "transport": "SMTP", "SMTP": { // see https://github.com/andris9/Nodemailer#possible-transport-methods 405 | "host": "smtp.example.com", "port": 465, 406 | "secureConnection": true, 407 | "auth": { 408 | "user": "foo@example.com", 409 | "pass": "bar_foo" 410 | } 411 | } 412 | } 413 | } 414 | */ 415 | 416 | ] 417 | } // logconfig 418 | } 419 | -------------------------------------------------------------------------------- /resources/docker-jitsi-meet.xml: -------------------------------------------------------------------------------- 1 | 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 --------------------------------------------------------------------------------