(((•)))
tech.interfluidity.com
a notebook by steve randy waldman
→ See also top, archive, subscribe, drafts blog, interfluidity main
2023-08-21 ⇒

# Getting started with Jitsi

## TL;DR

Jitsi is a complicated system! It was surprisingly easy to set up, though.

I'd feel better if I understood it better so I'd know that I can do what I want and fix whatever breaks.

Nevertheless, it works, and it's very cool to be able to embed a teleconference in straight HTML/CSS!

## Introduction

A few weeks ago there was a bit of a kerfuffle as Zoom updated their terms of service in ways that would apparently permit training AIs with surveillance of our interactions in Zoom teleconferences. Zoom has since clarified this, or walked it back, depending upon how generously you want to interpret their original intentions.

I've been a paying Zoom subscriber for years, and I'm willing to take the more generous interpretation. But regardless of Zoom's intentions, the incident was another reminder that large, centralized tech platforms are just a dangerous architecture, under which again and again firms and people I used to admire have succumbed to temptations of "enshittification".

Plus, I want to be able to play with the technology I use. I don't want to tether my own skills and habits to some company's propriety plug-ins and APIs if I can help it. I want to use open, freely available tools to experiment with how my teleconferences work and integrate any extras I might wish to bring to them.

There are a few self-hostable, open source teleconferencing platforms, such as Jitsi and Edumeet. Then there are lower level libraries like Mediasoup and Janus.

I don't have a clue about any of this stuff. (I am very open to advice!) So I'm playing.

My first attempt has been with Jitsi. On the one-hand, I like that it has been easy to set up, and easy to embed into HTML and mess with with ordinary css and javascript. I am tentatively very happy!

On the other hand, I am very aware that it's a complicated stack full of components I am still struggling to understand. When (due to my own error!) the cookbook set-up seemed to fail, I was really at a loss about how I might debug the thing. (See below on the details of how I made my own life complicated.)

## What (little) I understand about the Jitsi stack

Ultimately, Jitsi requires the collaboration of several services, which can be run on a single or multiple machines, in order to function. On my setup, I have

- prosody
- jicofo
- jitsi-videobridge
- coturn

Then I configure and serve (via nginx) `jitsi-meet`, which is a client-side application that hits these services. You can see a diagram here. Let's steal that, straight from `jitsi.org`:

As I understand (or perhaps misunderstand)

- `prosody` is an XMPP server, the standard invented and used by open-source instant messaging platform Jabber, which was eventually embraced, then eclipsed and support discontinued, by Google. Of course `Jabber` lives on, albeit more quietly. Importantly, the XMPP protocol its developers invented was extended far beyond organizing text-based "MUCs" (multiuser conferences) into the realm of audio and videoconferencing via "Jingle". Jitsi uses prosody for establishing conferences and authentication of participants, as far as I can tell.
- `jicofo`, as I understand it, is a service that intermediates between clients (ie web browsers) and the XMPP server `prosody`, and via that XMPP server, the "videobridge" that actually serves audiovideo data, using the aforementioned Jingle protocol with clients and a distinct protocol called `colibri v2` with the videobridge component.
- `jitsi-videobridge` is — I think! — the component that actually serves audiovideo data to clients.
- `coturn` is relatively straightforward. It helps clients behind NAT (network address translation, ie using fake IP addresses) find and reach their outward-facing IP addresses (STUN protocol), and if necessary proxies audiovisual data to circumvent nettlesome layers of NAT and firewalls (TURN protocol). `coturn` makes it possible for the significant share of the internet that can't reach the network without translation or proxying to participate in teleconferences.

There is so much I don't understand about all this. Are `jicofo`/`prosody` only involved in establishing and terminating sessions, or do they have a role throughout a "MUC"? Via `nginx`, clients seem to have access both to audiovisual data (as BOSH), and to XMPP via `prosody`, and to the `videobridge` service via directly. Who hits `jicofo` when?

I don't know. Again, if something in this complex collaboration broke, how would I figure out how to debug and fix it? That so far is my main issue with `Jitsi`.

There are two components in the Jitsi stack that I am not yet using. Jigasi would be a bridge from `Jitsi` to and from standard VoIP "Session Initiation Protocol (SIP)" sessions, allowing telephone dial-in and piping of audio into external transcription services. Jibri is a very resource intensive service that basically runs a headless chrome browser which silently joins a conference to receive video and audio and translate it into MP4 data for recording and streaming.

It's a lot!

## An interesting note about prosody configuration

The host on which I've (perhaps only temporarily!) deployed `Jitsi` is called `loiter.interfluidity.com`. My prosody configuration contains lines like

    VirtualHost "loiter.interfluidity.com"
      ...
    VirtualHost "auth.loiter.interfluidity.com"
      ...
    Component "focus.loiter.interfluidity.com" "client_proxy"
      ...

None of these subdomains are configured, or are required to be configured, in DNS.

The installation created a self-signed certificate for the "virtual host" `auth.loiter.interfluidity.com`, as well as for parent domain `loiter.interfluidity.com`.

I am guessing that services make secure connections internally, via `localhost`, to `auth.loiter.interfluidity.com`, using that "virtual host" name in a `Host:` header. I think this configuration scheme is intended for at least `auth` (not necessarily "component" `focus`) to be a separate host, but when we want to host it all in one place, rather than having us go to the trouble of `CNAME`-ing our server `auth.loiter.interfluidity.com`, it is configured to just pretend internally. It feels like a cell absorbing some precambrian bacteria to invent the mirochondrion.

## Installation

I basically followed the developers' Ubuntu deployment docs.

I created a digitalocean Ubuntu 22.04 (LTS) "basic" "regular" 4GB/2CPU/80GB for $24/month.

Then, simplifying just a bit...

    # apt update
    # apt upgrade
    # apt install emacs-nox
    # apt-add-repository universe
    # hostnamectl set-hostname loiter.interfluidity.com
    emacs /etc/hosts

I fill in my server's IP address for `loiter.interfluidity.com loiter`.

Then I just paste in the following from Jitsu's cookbook instructions, which trusts prosody's developers to maintain a repository from which I can install and update via `apt`:

    sudo curl -sL https://prosody.im/files/prosody-debian-packages.key -o /etc/apt/keyrings/prosody-debian-packages.key
    echo "deb [signed-by=/etc/apt/keyrings/prosody-debian-packages.key] http://packages.prosody.im/debian $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/prosody-debian-packages.list
    sudo apt install lua5.2

Then I do the same for `jitsi.org` (pasting another short script):

    curl -sL https://download.jitsi.org/jitsi-key.gpg.key | sudo sh -c 'gpg --dearmor > /usr/share/keyrings/jitsi-keyring.gpg'
    echo "deb [signed-by=/usr/share/keyrings/jitsi-keyring.gpg] https://download.jitsi.org stable/" | sudo tee /etc/apt/sources.list.d/jitsi-stable.list

Then

    # apt update
    # apt upgrade

Here I deviate a bit from the canned instructions. I know I want nginx and certbot certs...

    # apt install nginx
    # apt install certbot

I manually fetch my certificates (I've already configured a DNS `A` record for `loiter.interfluidity.com`.):

    # certbot certonly -d loiter.interfluidity.com

During the later installation of `Jitsi` components, I'll have to supply a path to my `fullchain.pem` and `privkey.pem` files. The installation has the option of running certbot for you, but if you do it yourself, you'll want to note these paths.

There were some differences in recommended firewall config between the written instructions and a video tutorial. I went with the following hybrid. So far, it seems fine.

    # ufw allow in ssh
    # ufw allow in 80/tcp
    # ufw allow in 443/tcp
    # ufw allow in 10000:20000/udp
    # ufw allow in 3478/udp
    # ufw allow in 5349/tcp
    # ufw enable

Then I did something stupid. More about that below.

The next thing I should have done was...

    # apt install jitsi-meet

It prompts for a bunch of stuff, like certificate paths. It prompts whether you want to support dial-in participants, by making an account on their hosted Jitsu-as-a-service. I said no. It prints the following banner in case I change my mind:

           ;dOocd;
         .dNMM0dKO.
         lNMMMKd0K,
        .xMMMMNxkNc
         dMMMMMkxXc
         cNMMMNl..
         .kMMMX;             Interested in adding telephony to your Jitsi meetings?
          ;XMMMO'
           lNMMWO'           Sign up on https://jaas.8x8.vc/components?host=loiter.interfluidity.com
            lNMMM0,                        and follow the guide in the dev console.
             lXMMMK:.
              ;KMMMNKd.  'oo,
               'xNMMMMXkkkkOKOl'
                 :0WMMMMMMNOkk0Kk,
                  .cdOWMMMMMWXOkOl
                     .;dKWMMMMMXc.
                        .,:cll:'

Then it just works!

### Something stupid

Well it should have worked. I did something stupid. I manually installed `nginx` (because reading the docs I saw that serving via nginx was optional, I knew I wanted it, and the docs said it'd be installed if nginx was), and then I set up my usual config for host `loiter.interfluidity.com` right in `/etc/nginx/nginx.conf`.

That occluded the Jitsi installer's very elaborate config in `/etc/nginx/sites-available/loiter.interfluidity.com.conf`, then symlinked into `/etc/nginx/sites-enabled`.

### It works!

After removing my occluding configuration from `/etc/nginx/nginx.conf` and

    # systemctl restart nginx

I could go to `https://loiter.interfluidity.com/` and see the default Jitsu webapp.

You can see that default app at https://meet.jit.si/. I'll soon disable that at the base of my site, and in general try to add a bit of authentication to my installation!

## Using the iframe API to embed conferences in HTML

Once I got the default page working, it was easy to make an HTML page that would embed a "conference room".

## Appendix: Relevant config files, etc

### Config files

- /etc/prosody/conf.avail/jitsi.example.com.cfg.lua
- /etc/prosody/prosody.cfg.lua
- /etc/jitsi/jicofo/config
- /etc/jitsi/jicofo/jicofo.conf
- /etc/jitsi/jicofo/logging.properties
- /etc/jitsi/meet/loiter.interfluidity.com-config.js
- /etc/jitsi/videobridge/config
- /etc/jitsi/videobridge/jvb.conf
- /etc/jitsi/videobridge/logging.properties
- /etc/jitsi/videobridge/sip-communicator.properties
- /etc/nginx/nginx.conf

### Log files

- /var/log/jitsi/jvb.log
- /var/log/jitsi/jicofo.log
- /var/log/prosody/prosody.log

### Unit Files

- coturn.service (`/lib/systemd/system/coturn.service`)
- jicofo.service (`/etc/init.d/jicofo; generated`)
- jitsi-videobridge2.service (`/lib/systemd/system/jitsi-videobridge2.service`)
- prosody.service (`/lib/systemd/system/prosody.service`)

Update 2023-08-22: Following the instructions here, enabling simple authentication worked without a hitch. Registering a user is a command-line operation:

    # prosodyctl register <username> loiter.interfluidity.com <password>

`loiter.interfluidity.com` is the authenticated domain in `/etc/prosody/prosody.cfg.lua`.

I think it's possible to set up web registration, but for my purposes I don't want to. Only meeting hosts must authenticate. Anyone who knows the URL can join a conference.

← Building an authenticated web service in Scala with tapir and JWT
↑↑↑
Getting started with HedgeDoc →