#!/bin/bash set -e # ----------------------------------------------------------------------------- # globals # ----------------------------------------------------------------------------- JITSI_TMPL=https://raw.githubusercontent.com/jitsi-contrib/installers/main/templates/jitsi JITSI_MEET_CONFIG=/etc/jitsi/meet/$JITSI_HOST-config.js PROSODY_CONFIG=/etc/prosody/conf.avail/$JITSI_HOST.cfg.lua NGINX_CONFIG=/etc/nginx/sites-available/$JITSI_HOST.conf PROSODY_PLUGINS_VERSION=20250923 PROSODY_PLUGINS_ARCHIVE=https://github.com/jitsi-contrib/prosody-plugins/archive/refs/tags/v$PROSODY_PLUGINS_VERSION.tar.gz CHECKMYPORT=https://checkmyport.emrah.com TCP=(80 443 4444 5222 5280 5269 5347 5349 8080 8888 9090) UDP=(5000 5349 10000) # ----------------------------------------------------------------------------- # globals (extra) # ----------------------------------------------------------------------------- JIBRI_TMPL=https://raw.githubusercontent.com/jitsi-contrib/installers/main/templates/jibri # ----------------------------------------------------------------------------- # output format # ----------------------------------------------------------------------------- out() { printf "\n" while IFS= read -r line; do printf "\033[0;31m>>>\033[0m \033[0;33m%s\033[0m\n" "$line" done } # ----------------------------------------------------------------------------- # trap on exit # ----------------------------------------------------------------------------- function on_exit { if [[ "$COMPLETED" != true ]]; then out <<< "Something went wrong. Not completed!" exit 1 else out </dev/null || true if [[ -z "$(grep snd_aloop /proc/modules)" ]]; then out < $IP Recommendation: Set $EXTERNAL_IP as DNS A record for $JITSI_HOST If this is a test setup and you don't have a reachable address, export the public IP by setting JITSI_IP and disable LetsEncrypt certificate by setting DONT_SET_LETSENCRYPT. e.g. export JITSI_IP=$EXTERNAL_IP export DONT_SET_LETSENCRYPT=true EOF exit 1 fi # turn host A record out <<< "checking DNS record for $TURN_HOST..." if [[ -n "$JITSI_IP" ]]; then IP=$JITSI_IP else IP=$(dig -4 +short $TURN_HOST @resolver1.opendns.com | tail -1) || true fi if [[ -z "$IP" ]]; then out < $IP Recommendation: Set $EXTERNAL_IP as DNS A record for $TURN_HOST EOF exit 1 fi # ----------------------------------------------------------------------------- # port availability check # ----------------------------------------------------------------------------- out <<< "checking the availability of TCP ports..." netstat -ltnp | egrep '^tcp' | while read -r l; do port=$(echo $l | awk '{print $4}' | rev | cut -d: -f1 | rev) for p in ${TCP[*]}; do if [[ "$p" = "$port" ]]; then prog=$(echo $l | cut -d/ -f2) proto=$(echo $l | awk '{print $1}') out </dev/null 2>&1 || true) & RES=$(timeout 8 ncat -l 0.0.0.0 80 | tr -d '\0' || true) if [[ "$RES" != "$TEXT" ]]; then out </dev/null 2>&1 || true) & RES=$(timeout 8 ncat -l 0.0.0.0 443 | tr -d '\0' || true) if [[ "$RES" != "$TEXT" ]]; then out </dev/null 2>&1 || true) & RES=$(timeout 8 ncat -u -l 0.0.0.0 10000 | tr -d '\0' || true) if [[ "$RES" != "$TEXT" ]]; then out </dev/null || true # ----------------------------------------------------------------------------- # packages # ----------------------------------------------------------------------------- out <<< "installing Jitsi..." # openjdk-xx-jre-headless apt-get $APT_PROXY -y install openjdk-$JDK-jre-headless # lua apt-get $APT_PROXY -y install lua$LUA # nodesource.list wget -T 10 -qO /tmp/nodesource.gpg.key \ https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key cat /tmp/nodesource.gpg.key | gpg --dearmor \ >/usr/share/keyrings/nodesource.gpg if [[ "$DISTRO" = "jammy" ]] || \ [[ "$DISTRO" = "bookworm" ]]; then wget -T 10 -O /etc/apt/sources.list.d/nodesource.list \ $JITSI_TMPL/etc/apt/sources.list.d/nodesource.list else wget -T 10 -O /etc/apt/sources.list.d/nodesource.sources \ $JITSI_TMPL/etc/apt/sources.list.d/nodesource.sources fi # prosody sources.list wget -T 10 -qO /tmp/prosody.gpg.key \ https://prosody.im/files/prosody-debian-packages.key cat /tmp/prosody.gpg.key | gpg --dearmor > /usr/share/keyrings/prosody.gpg if [[ "$DISTRO" = "jammy" ]] || \ [[ "$DISTRO" = "bookworm" ]]; then wget -T 10 -O /etc/apt/sources.list.d/prosody.list \ $JITSI_TMPL/etc/apt/sources.list.d/prosody.list.$DISTRO else wget -T 10 -O /etc/apt/sources.list.d/prosody.sources \ $JITSI_TMPL/etc/apt/sources.list.d/prosody.sources.$DISTRO fi # jitsi-meet wget -T 10 -qO /tmp/jitsi.gpg.key https://download.jitsi.org/jitsi-key.gpg.key cat /tmp/jitsi.gpg.key | gpg --dearmor > /usr/share/keyrings/jitsi.gpg if [[ "$DISTRO" = "jammy" ]] || \ [[ "$DISTRO" = "bookworm" ]]; then wget -T 10 -O /etc/apt/sources.list.d/jitsi-stable.list \ $JITSI_TMPL/etc/apt/sources.list.d/jitsi-stable.list else wget -T 10 -O /etc/apt/sources.list.d/jitsi.sources \ $JITSI_TMPL/etc/apt/sources.list.d/jitsi.sources fi apt-get update debconf-set-selections <<< \ "jicofo jitsi-videobridge/jvb-hostname string $JITSI_HOST" debconf-set-selections <<< \ "jitsi-meet-web-config jitsi-meet/cert-choice select Generate a new self-signed certificate" apt-get $APT_PROXY -y --install-recommends install jitsi-meet prosody apt-get $APT_PROXY -y install libnginx-mod-stream apt-get $APT_PROXY -y install nodejs apt-mark hold 'jitsi-*' jicofo # packages are ok timeout 8 curl -s "$CHECKMYPORT?proto=udp&port=60000&text=ok-package" \ >/dev/null || true # ----------------------------------------------------------------------------- # packages (extra) # ----------------------------------------------------------------------------- out <<< "installing jibri packages..." wget -T 10 -qO /tmp/google-chrome.gpg.key \ https://dl.google.com/linux/linux_signing_key.pub apt-key add /tmp/google-chrome.gpg.key wget -T 10 -O /etc/apt/sources.list.d/google-chrome.list \ $JIBRI_TMPL/etc/apt/sources.list.d/google-chrome.list apt-get -y --allow-releaseinfo-change update apt-get $APT_PROXY -y install kmod alsa-utils apt-get $APT_PROXY -y install libnss3-tools unzip unclutter apt-get $APT_PROXY -y install va-driver-all vdpau-driver-all apt-get $APT_PROXY -y --install-recommends install ffmpeg apt-get $APT_PROXY -y --install-recommends install google-chrome-stable apt-mark hold google-chrome-stable CHROME_VER=$(dpkg -s google-chrome-stable | egrep "^Version" | \ cut -d " " -f2 | cut -d "-" -f1) CHROME_STORE="https://storage.googleapis.com/chrome-for-testing-public" CHROMEDRIVER="$CHROME_STORE/${CHROME_VER}/linux64/chromedriver-linux64.zip" wget -T 30 -qO /tmp/chromedriver-linux64.zip $CHROMEDRIVER rm -rf /tmp/chromedriver-linux64 unzip -o /tmp/chromedriver-linux64.zip -d /tmp mv /tmp/chromedriver-linux64/chromedriver /usr/local/bin/ chmod 755 /usr/local/bin/chromedriver apt-get $APT_PROXY -y install x11vnc apt-get $APT_PROXY -y install sudo apt-get $APT_PROXY -y install jibri apt-mark hold jibri apt-get -y purge upower apt-get -y --purge autoremove # jibri packages are ok timeout 8 curl -s "$CHECKMYPORT?proto=udp&port=60000&text=ok-package-jibri" \ >/dev/null || true # ----------------------------------------------------------------------------- # backup # ----------------------------------------------------------------------------- out <<< "backups..." # jitsi-meet cp $JITSI_MEET_CONFIG $JITSI_MEET_CONFIG.org # coturn cp /etc/turnserver.conf /etc/turnserver.conf.org # prosody cp /etc/prosody/prosody.cfg.lua /etc/prosody/prosody.cfg.lua.org cp $PROSODY_CONFIG $PROSODY_CONFIG.org # jicofo cp /etc/jitsi/jicofo/config /etc/jitsi/jicofo/config.org cp /etc/jitsi/jicofo/jicofo.conf /etc/jitsi/jicofo/jicofo.conf.org # jvb cp /etc/jitsi/videobridge/config /etc/jitsi/videobridge/config.org cp /etc/jitsi/videobridge/jvb.conf /etc/jitsi/videobridge/jvb.conf.org # nginx cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.org cp $NGINX_CONFIG $NGINX_CONFIG.org # ----------------------------------------------------------------------------- # backup (extra) # ----------------------------------------------------------------------------- cp /etc/modules /etc/modules.org cp /etc/hosts /etc/hosts.org cp /usr/share/jitsi-meet/body.html /usr/share/jitsi-meet/body.html.org # ----------------------------------------------------------------------------- # configuration (extra) # ----------------------------------------------------------------------------- out <<< "jibri related configuration..." # snd_aloop [[ -z "$(egrep '^snd_aloop' /etc/modules)" ]] && echo snd_aloop >>/etc/modules # hosts sed -i -E "s/(\s)$JITSI_HOST/\1/" /etc/hosts sed -i -E "/^[0-9.]+\s*$/d" /etc/hosts sed -i "/127.0.2.1\s/d" /etc/hosts sed -i "$ a 127.0.2.1 $JITSI_HOST" /etc/hosts # google chrome mkdir -p /etc/opt/chrome/policies/managed wget -T 10 -O /etc/opt/chrome/policies/managed/jibri_policies.json \ $JIBRI_TMPL/etc/opt/chrome/policies/managed/jibri_policies.json # ----------------------------------------------------------------------------- # self-signed certificates # ----------------------------------------------------------------------------- out <<< "self-signed certificates..." ln -sf /etc/jitsi/meet/*.crt /usr/local/share/ca-certificates/ update-ca-certificates -f # self-signed certificates is ok timeout 8 curl -s "$CHECKMYPORT?proto=udp&port=60000&text=ok-conf-selfcerts" \ >/dev/null || true # ----------------------------------------------------------------------------- # certbot # ----------------------------------------------------------------------------- out <<< "configuring Certbot..." mkdir -p /etc/systemd/system/certbot.service.d wget -T 10 -O /etc/systemd/system/certbot.service.d/override.conf \ $JITSI_TMPL/etc/systemd/system/certbot.service.d/override.conf systemctl daemon-reload # certbot config is ok timeout 8 curl -s "$CHECKMYPORT?proto=udp&port=60000&text=ok-conf-certbot" \ >/dev/null || true # ----------------------------------------------------------------------------- # coturn # ----------------------------------------------------------------------------- out <<< "configuring Coturn..." cat >>/etc/turnserver.conf </dev/null || true # ----------------------------------------------------------------------------- # prosody # ----------------------------------------------------------------------------- out <<< "configuring Prosody..." mkdir -p /etc/systemd/system/prosody.service.d wget -T 10 -O /etc/systemd/system/prosody.service.d/override.conf \ $JITSI_TMPL/etc/systemd/system/prosody.service.d/override.conf wget -T 10 -O /etc/prosody/conf.avail/network.cfg.lua \ $JITSI_TMPL/etc/prosody/conf.avail/network.cfg.lua ln -s ../conf.avail/network.cfg.lua /etc/prosody/conf.d/ sed -i "/rate *=.*kb.s/ s/[0-9]*kb/1024kb/" /etc/prosody/prosody.cfg.lua sed -i "s/^-- \(https_ports = { };\)/\1/" $PROSODY_CONFIG sed -i "/turns.*tcp/ s/host\s*=[^,]*/host = \"$TURN_HOST\"/" $PROSODY_CONFIG sed -i "/turns.*tcp/ s/5349/443/" $PROSODY_CONFIG sed -i '/^plugin_paths/ s~ }~, "/usr/share/jitsi-meet/prosody-plugins-contrib/" }~' \ $PROSODY_CONFIG # jitsi-contrib-prosody-plugins wget -T 10 -O /tmp/v$PROSODY_PLUGINS_VERSION.tar.gz $PROSODY_PLUGINS_ARCHIVE tar -xf /tmp/v$PROSODY_PLUGINS_VERSION.tar.gz mv prosody-plugins-$PROSODY_PLUGINS_VERSION \ /usr/share/jitsi-meet/prosody-plugins-contrib # extra sed -i 's/-- muc_lobby_whitelist/muc_lobby_whitelist/' $PROSODY_CONFIG sed -i "/muc_password_whitelist =/a \ \ \"recorder@recorder.$JITSI_HOST\"," $PROSODY_CONFIG # prosody restart systemctl daemon-reload systemctl restart prosody.service sleep 3 # prosody accounts (extra) PASSWD1=$(openssl rand -hex 20) PASSWD2=$(openssl rand -hex 20) prosodyctl unregister jibri auth.$JITSI_HOST || true prosodyctl register jibri auth.$JITSI_HOST $PASSWD1 prosodyctl unregister recorder recorder.$JITSI_HOST || true prosodyctl register recorder recorder.$JITSI_HOST $PASSWD2 # prosody config is ok timeout 8 curl -s "$CHECKMYPORT?proto=udp&port=60000&text=ok-conf-prosody" \ >/dev/null || true # ----------------------------------------------------------------------------- # jicofo # ----------------------------------------------------------------------------- out <<< "configuring Jicofo..." # add the custom config cat >>/etc/jitsi/jicofo/config </dev/null || true # ----------------------------------------------------------------------------- # jitsi-meet (extra) # ----------------------------------------------------------------------------- out <<< "configuring jitsi-meet..." wget -T 10 -O /usr/share/jitsi-meet/static/branding.json \ $JITSI_TMPL/usr/share/jitsi-meet/static/branding.json wget -T 10 -O /tmp/config.branding.js \ $JITSI_TMPL/etc/jitsi/meet/config.branding.js cat /tmp/config.branding.js >>$JITSI_MEET_CONFIG wget -T 10 -O /tmp/config.whiteboard.js \ $JITSI_TMPL/etc/jitsi/meet/config.whiteboard.js cat /tmp/config.whiteboard.js >>$JITSI_MEET_CONFIG wget -T 10 -O /tmp/config.recording.js \ $JITSI_TMPL/etc/jitsi/meet/config.recording.js cat /tmp/config.recording.js >>$JITSI_MEET_CONFIG wget -T 10 -O /tmp/config.livestreaming.js \ $JITSI_TMPL/etc/jitsi/meet/config.livestreaming.js cat /tmp/config.livestreaming.js >>$JITSI_MEET_CONFIG wget -T 10 -O /tmp/config.hiddendomain.js \ $JITSI_TMPL/etc/jitsi/meet/config.hiddendomain.js cat /tmp/config.hiddendomain.js >>$JITSI_MEET_CONFIG sed -i "s/___JITSI_FQDN___/$JITSI_HOST/" $JITSI_MEET_CONFIG # jitsi-meet config is ok timeout 8 curl -s "$CHECKMYPORT?proto=udp&port=60000&text=ok-conf-jitsi-meet" \ >/dev/null || true # ----------------------------------------------------------------------------- # nginx # ----------------------------------------------------------------------------- out <<< "configuring Nginx..." mkdir -p /etc/systemd/system/nginx.service.d wget -T 10 -O /etc/systemd/system/nginx.service.d/override.conf \ $JITSI_TMPL/etc/systemd/system/nginx.service.d/override.conf sed -i "/worker_connections/ s/\\S*;/8192;/" \ /etc/nginx/nginx.conf mkdir -p /usr/local/share/nginx/modules-available wget -T 10 -O /usr/local/share/nginx/modules-available/jitsi-meet.conf \ $JITSI_TMPL/usr/local/share/nginx/modules-available/jitsi-meet.conf sed -i "s/___LOCAL_IP___/$PUBLIC_IP/" \ /usr/local/share/nginx/modules-available/jitsi-meet.conf sed -i "s/___TURN_HOST___/$TURN_HOST/" \ /usr/local/share/nginx/modules-available/jitsi-meet.conf wget -T 10 -O /etc/nginx/sites-available/$JITSI_HOST.conf \ $JITSI_TMPL/etc/nginx/sites-available/jms.conf sed -i "s/___JITSI_HOST___/$JITSI_HOST/" $NGINX_CONFIG sed -i "s/___TURN_HOST___/$TURN_HOST/" $NGINX_CONFIG ln -s /usr/local/share/nginx/modules-available/jitsi-meet.conf \ /etc/nginx/modules-enabled/99-jitsi-meet-custom.conf rm /etc/nginx/sites-enabled/default mkdir -p /etc/jitsi/meet/jaas wget -T 10 -O /etc/jitsi/meet/jaas/excalidraw.conf \ $JITSI_TMPL/etc/jitsi/meet/jaas/excalidraw.conf wget -T 10 -O /etc/jitsi/meet/jaas/recording.conf \ $JITSI_TMPL/etc/jitsi/meet/jaas/recording.conf systemctl daemon-reload systemctl stop nginx.service systemctl start nginx.service # nginx config is ok timeout 8 curl -s "$CHECKMYPORT?proto=udp&port=60000&text=ok-conf-nginx" \ >/dev/null || true # ----------------------------------------------------------------------------- # jvb # ----------------------------------------------------------------------------- out <<< "configuring JVB..." # add the custom config cat >>/etc/jitsi/videobridge/config <>/etc/jitsi/videobridge/sip-communicator.properties </dev/null || true # ----------------------------------------------------------------------------- # excalidraw # ----------------------------------------------------------------------------- out <<< "installing excalidraw..." # excalidraw user adduser excalidraw --system --group --disabled-password --shell /bin/bash \ --home /home/excalidraw # excalidraw-backend app su -l excalidraw <.env.production sed -i '/collectDefaultMetrics/ i \ createServer: false,' src/index.ts npm install npm run build EOF # excalidraw service wget -T 10 -O /etc/systemd/system/excalidraw.service \ $JITSI_TMPL/etc/systemd/system/excalidraw.service systemctl enable excalidraw.service systemctl start excalidraw.service # excalidraw is ok timeout 8 curl -s "$CHECKMYPORT?proto=udp&port=60000&text=ok-excalidraw" \ >/dev/null || true # ----------------------------------------------------------------------------- # lets encrypt # ----------------------------------------------------------------------------- if [[ "$DONT_SET_LETSENCRYPT" != true ]]; then out <<< "setting Let's Encrypt certificates..." certbot certonly --dry-run --non-interactive -m info@$JITSI_HOST \ --agree-tos --duplicate --webroot -w /usr/share/jitsi-meet \ -d $JITSI_HOST,$TURN_HOST || true sleep 3 certbot certonly --non-interactive -m info@$JITSI_HOST \ --agree-tos --duplicate --webroot -w /usr/share/jitsi-meet \ -d $JITSI_HOST,$TURN_HOST rm -f /etc/jitsi/meet/$JITSI_HOST.crt rm -f /etc/jitsi/meet/$JITSI_HOST.key ln -s /etc/letsencrypt/live/$JITSI_HOST/fullchain.pem \ /etc/jitsi/meet/$JITSI_HOST.crt ln -s /etc/letsencrypt/live/$JITSI_HOST/privkey.pem \ /etc/jitsi/meet/$JITSI_HOST.key out <<< "restarting Certbot..." systemctl restart certbot.service out <<< "restarting Coturn..." systemctl restart coturn.service out <<< "restarting Nginx..." systemctl restart nginx.service # tls is ok timeout 8 curl -s "$CHECKMYPORT?proto=udp&port=60000&text=ok-tls" \ >/dev/null || true fi # ----------------------------------------------------------------------------- # jibri related (extra) # ----------------------------------------------------------------------------- # icewm mkdir -p /home/jibri/.icewm wget -T 10 -O /home/jibri/.icewm/startup $JIBRI_TMPL/home/jibri/.icewm/startup chmod 755 /home/jibri/.icewm/startup # jibri chsh -s /bin/bash jibri usermod -aG adm,audio,video,plugdev jibri chown jibri:jibri /home/jibri mkdir -p /usr/local/recordings chown jibri:jibri /usr/local/recordings -R wget -T 10 -O /etc/jitsi/jibri/jibri.conf $JIBRI_TMPL/etc/jitsi/jibri/jibri.conf sed -i "s/___JITSI_HOST___/$JITSI_HOST/" /etc/jitsi/jibri/jibri.conf sed -i "s/___PASSWD1___/$PASSWD1/" /etc/jitsi/jibri/jibri.conf sed -i "s/___PASSWD2___/$PASSWD2/" /etc/jitsi/jibri/jibri.conf wget -T 10 -O /usr/local/bin/finalize_recording.sh \ $JIBRI_TMPL/usr/local/bin/finalize_recording.sh chmod 755 /usr/local/bin/finalize_recording.sh wget -T 10 -O /usr/local/bin/ffmpeg $JIBRI_TMPL/usr/local/bin/ffmpeg chmod 755 /usr/local/bin/ffmpeg systemctl daemon-reload systemctl enable jibri.service systemctl start jibri.service # jibri, recorded file link as a private message wget -T 10 -O /usr/share/jitsi-meet/body.html \ $JIBRI_TMPL/usr/share/jitsi-meet/body.html sed -i "s/___JITSI_HOST___/$JITSI_HOST/" /usr/share/jitsi-meet/body.html # jibri, vnc mkdir -p /home/jibri/.vnc x11vnc -storepasswd jibri /home/jibri/.vnc/passwd chown jibri:jibri /home/jibri/.vnc -R # jibri, Xdefaults wget -T 10 -O /home/jibri/.Xdefaults $JIBRI_TMPL/home/jibri/.Xdefaults # jibri configuration is ok timeout 8 curl -s "$CHECKMYPORT?proto=udp&port=60000&text=ok-conf-jibri" \ >/dev/null || true # ----------------------------------------------------------------------------- # completed (extra) # ----------------------------------------------------------------------------- timeout 8 curl -s "$CHECKMYPORT?proto=udp&port=60000&text=ok-jibri" \ >/dev/null || true # ----------------------------------------------------------------------------- # completed # ----------------------------------------------------------------------------- timeout 8 curl -s "$CHECKMYPORT?proto=udp&port=60000&text=ok-completed" \ >/dev/null || true END_TIME=$(date +%s) DURATION=$(date -u -d "0 $END_TIME seconds - $START_TIME seconds" +"%H:%M:%S") COMPLETED=true