diff --git a/Makefile b/Makefile index b4e973f4ba..e6e95fbb17 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ FORCE_REBUILD ?= 0 JITSI_RELEASE ?= stable JITSI_BUILD ?= latest JITSI_REPO ?= jitsi -JITSI_SERVICES ?= base base-java web prosody jicofo jvb jigasi etherpad jibri +JITSI_SERVICES ?= base base-java web prosody jicofo jvb jigasi etherpad jibri coturn BUILD_ARGS := --build-arg JITSI_REPO=$(JITSI_REPO) ifeq ($(FORCE_REBUILD), 1) diff --git a/README.md b/README.md index 7c07d2c25a..0b892583dd 100644 --- a/README.md +++ b/README.md @@ -15,5 +15,5 @@ The installation manual is available [here](https://jitsi.github.io/handbook/doc ## TODO * Support container replicas (where applicable). -* TURN server. + diff --git a/coturn.yml b/coturn.yml new file mode 100644 index 0000000000..a639af09a3 --- /dev/null +++ b/coturn.yml @@ -0,0 +1,30 @@ +version: '3' + +services: + # coturn TURN server project + turn: + image: jitsi/coturn + restart: always + volumes: + - ${CONFIG}/turn:/config + ports: + - '${TURN_PORT}:${TURN_PORT}/tcp' + - '${TURN_PORT}:${TURN_PORT}/udp' + - '${TURN_RTP_MIN}-${TURN_RTP_MAX}:${TURN_RTP_MIN}-${TURN_RTP_MAX}/udp' + - '${TURN_ADMIN_PORT}:${TURN_ADMIN_PORT}/tcp' + environment: + - DOCKER_HOST_ADDRESS + - TURN_SECRET + - TURN_REALM + - TURN_HOST + - TURN_PORT + - TURN_TRANSPORT + - TURN_RTP_MIN + - TURN_RTP_MAX + - TURN_ADMIN_ENABLE + - TURN_ADMIN_USER + - TURN_ADMIN_SECRET + - TURN_ADMIN_PORT + networks: + meet.jitsi: + diff --git a/coturn/Dockerfile b/coturn/Dockerfile new file mode 100644 index 0000000000..da62b7148a --- /dev/null +++ b/coturn/Dockerfile @@ -0,0 +1,13 @@ +ARG VERSION +FROM instrumentisto/coturn:${VERSION:-latest} + +RUN apk add --no-cache openssl + +ADD ./rootfs/defaults/docker-entrypoint.sh /docker-entrypoint.sh + +ENTRYPOINT ["/docker-entrypoint.sh"] + +VOLUME ["/config"] + +EXPOSE 5349 8443 10000:11000/udp + diff --git a/coturn/Makefile b/coturn/Makefile new file mode 100644 index 0000000000..204a7559f3 --- /dev/null +++ b/coturn/Makefile @@ -0,0 +1,5 @@ +build: + docker build $(BUILD_ARGS) -t $(JITSI_REPO)/coturn . + +.PHONY: build + diff --git a/coturn/rootfs/defaults/docker-entrypoint.sh b/coturn/rootfs/defaults/docker-entrypoint.sh new file mode 100755 index 0000000000..28e397fb5a --- /dev/null +++ b/coturn/rootfs/defaults/docker-entrypoint.sh @@ -0,0 +1,42 @@ +#!/bin/ash + +# make certs if not exist +if [[ ! -f /config/cert.crt || ! -f /config/cert.key ]]; then + openssl req -newkey rsa:2048 -nodes -keyout /config/cert.key -x509 -days 3650 -out /config/cert.crt -subj "/C=US/ST=NY/L=NY/O=IT/CN=${TURN_HOST}" +fi + +# use non empty TURN_PUBLIC_IP variable, othervise set it dynamically. +[ -z "${TURN_PUBLIC_IP}" ] && export TURN_PUBLIC_IP=$(curl -4ks https://icanhazip.com) +[ -z "${TURN_PUBLIC_IP}" ] && echo "ERROR: variable TURN_PUBLIC_IP is not set and can not be set dynamically!" && kill 1 + +# set coturn web-admin access +if [[ "${TURN_ADMIN_ENABLE}" == "1" || "${TURN_ADMIN_ENABLE}" == "true" ]]; then + turnadmin -A -u ${TURN_ADMIN_USER:-admin} -p ${TURN_ADMIN_SECRET:-changeme} + export TURN_ADMIN_OPTIONS="--web-admin --web-admin-ip=$(hostname -i) --web-admin-port=${TURN_ADMIN_PORT:-8443}" +fi + +# run coturn server with API auth method enabled. +turnserver -n ${TURN_ADMIN_OPTIONS} \ +--verbose \ +--prod \ +--no-tlsv1 \ +--no-tlsv1_1 \ +--log-file=stdout \ +--listening-port=${TURN_PORT:-5349} \ +--tls-listening-port=${TURN_PORT:-5349} \ +--alt-listening-port=${TURN_PORT:-5349} \ +--alt-tls-listening-port=${TURN_PORT:-5349} \ +--cert=/config/cert.crt \ +--pkey=/config/cert.key \ +--min-port=${TURN_RTP_MIN:-10000} \ +--max-port=${TURN_RTP_MAX:-11000} \ +--no-stun \ +--use-auth-secret \ +--static-auth-secret=${TURN_SECRET:-keepthissecret} \ +--no-multicast-peers \ +--realm=${TURN_REALM:-realm} \ +--listening-ip=$(hostname -i) \ +--external-ip=${TURN_PUBLIC_IP} \ +--cli-password=NotReallyCliUs3d \ +--no-cli + diff --git a/docker-compose.yml b/docker-compose.yml index bab3938541..0992a0dc26 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -39,6 +39,7 @@ services: - JIBRI_RECORDER_USER - JIBRI_RECORDER_PASSWORD - ENABLE_RECORDING + - TURN_ENABLE networks: meet.jitsi: aliases: @@ -104,6 +105,11 @@ services: - JWT_TOKEN_AUTH_MODULE - LOG_LEVEL - TZ + - TURN_ENABLE + - TURN_SECRET + - TURN_HOST + - TURN_PORT + - TURN_TRANSPORT networks: meet.jitsi: aliases: diff --git a/env.example b/env.example index 961822e128..6f8590ef6c 100644 --- a/env.example +++ b/env.example @@ -327,3 +327,43 @@ JIBRI_LOGS_DIR=/config/logs # Container restart policy # Defaults to unless-stopped RESTART_POLICY=unless-stopped +# Use TURN for P2P and JVB (bridge mode) connections +#TURN_ENABLE=0 + +# Realm to be used for the users with long-term credentials mechanism or with TURN REST API +#TURN_REALM=realm + +# Secret for connect to TURN server +#TURN_SECRET=keepthissecret + +# Annonce FQDN/IP address of the turn server via XMPP server (XEP-0215). +# If empty or not set, variable DOCKER_HOST_ADDRESS will be used by default. +#TURN_HOST=turn.example.com + +# Public IP address for an instance of turn server. +# If empty or not set, will be detected and set dynamically when a container start. +#TURN_PUBLIC_IP=144.144.144.144 + +# TLS/TCP/UDP turn port for connection +#TURN_PORT=5349 + +# Transport for stun/turn connection. Can be tcp or udp. +#TURN_TRANSPORT=tcp + +# RTP start port for turn/turns connections +#TURN_RTP_MIN=16000 + +# RTP end port for turn/turns connections +#TURN_RTP_MAX=17000 + +# Enable admin web access. If enabled, please set variables below. +#TURN_ADMIN_ENABLE=0 + +# Username for admin panel +#TURN_ADMIN_USER=admin + +# Password for admin panel +#TURN_ADMIN_SECRET=changeme + +# HTTP(s) port for acess to admin panel +#TURN_ADMIN_PORT=8443 diff --git a/prosody/Dockerfile b/prosody/Dockerfile index e6a37bc189..c41f2a7ff7 100644 --- a/prosody/Dockerfile +++ b/prosody/Dockerfile @@ -47,13 +47,18 @@ RUN \ && apt-cleanup \ && rm -rf /tmp/pkg /var/cache/apt -RUN patch -d /usr/lib/prosody/modules/muc -p0 < /prosody-plugins/muc_owner_allow_kick.patch COPY rootfs/ / COPY --from=builder /usr/local/lib/lua /usr/local/lib/lua COPY --from=builder /usr/local/share/lua /usr/local/share/lua +ADD https://raw.githubusercontent.com/netaskd/mod_turncredentials/master/mod_turncredentials.lua /prosody-plugins/mod_turncredentials.lua + +RUN \ + sed -i s/hook/hook_global/g /prosody-plugins/mod_auth_token.lua \ + && patch -d /usr/lib/prosody/modules/muc -p0 < /prosody-plugins/muc_owner_allow_kick.patch + EXPOSE 5222 5347 5280 VOLUME ["/config", "/prosody-plugins-custom"] diff --git a/prosody/rootfs/defaults/conf.d/jitsi-meet.cfg.lua b/prosody/rootfs/defaults/conf.d/jitsi-meet.cfg.lua index f88cc66e52..cf9932f0b8 100644 --- a/prosody/rootfs/defaults/conf.d/jitsi-meet.cfg.lua +++ b/prosody/rootfs/defaults/conf.d/jitsi-meet.cfg.lua @@ -52,12 +52,16 @@ VirtualHost "{{ .Env.XMPP_DOMAIN }}" "ping"; "speakerstats"; "conference_duration"; + {{ if .Env.TURN_ENABLE | default "0" | toBool }} + "turncredentials"; + {{end}} {{ if .Env.XMPP_MODULES }} "{{ join "\";\n\"" (splitList "," .Env.XMPP_MODULES) }}"; {{ end }} {{ if and $ENABLE_AUTH (eq $AUTH_TYPE "ldap") }} "auth_cyrus"; {{end}} + } speakerstats_component = "speakerstats.{{ .Env.XMPP_DOMAIN }}" diff --git a/web/rootfs/etc/cont-init.d/10-config b/web/rootfs/etc/cont-init.d/10-config index 58788de21e..7a4a5969bb 100644 --- a/web/rootfs/etc/cont-init.d/10-config +++ b/web/rootfs/etc/cont-init.d/10-config @@ -114,6 +114,13 @@ if [[ ! -f /config/config.js ]]; then -e "s#// transcribingEnabled:.*#transcribingEnabled: true,#" \ /config/config.js fi + + if [[ $TURN_ENABLE -eq 1 || "$TURN_ENABLE" == "true" ]]; then + sed -i \ + -e "s#// useStunTurn:.*,#useStunTurn: true,#" \ + /config/config.js + fi + fi if [[ ! -f /config/interface_config.js ]]; then