How to Set up Cascaded Jitsi Videobridges
Tags: jitsi, videocall, videobridges
Published: 2023-11-01 21:56:12

### **INTRODUCTION**

After self-hosting a Jitsi server, one will soon be required to add multiple videobridges to support the load.
I take you through a manual step in adding multiple videobridges. The understanding of this can help you write your ansible playbook for automating this process.

This article assumes the following:
1. Ability to create and configure droplets on DigitalOcean.
2. Set up a Jitsi server by following the [self-hosting guide](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-quickstart/).
3. Configured a subdomain for hosting your Jitsi server. I’ll use [meet.kofimupati.com](http://meet.kofimupati.com) (*At the time of reading the article I would have shut down the servers*)

We’ll create and configure 2 additional video bridge servers: 
**jvb1** and **jvb2** which will then be connected to our existing Jitsi server.

### **UPDATING JITSI SERVER CONFIGURATION**

**Modify the Videobridge Connected to the Jitsi Server
“**Jitsi Videobridge is a WebRTC compatible video router or SFU that lets build highly scalable video conferencing infrastructure (i.e., up to hundreds of conferences per server).”

Allow the following ports as well:

    9090/tcp
    9090/udp
    5222/tcp
    5222/udp

Update the **config**: ***/etc/jitsi/videobridge/config***

    -- JVB_HOST=
    ++ JVB_HOST=meet.kofimupati.com
    ++ JVB_OPTS="--apis=rest,xmpp --subdomain=jitsi-videobridge"
    ++ AUTHBIND=yes

Update **jvb.conf**: ***/etc/jitsi/videobridge/jvb.conf***

The **xmpp-client.configs.xmpp-server-1** values can be found in the default ***/etc/jitsi/videobridge/sip-communicator.properties***

The **region** and **relay-id** under **relay** are defined to distinguish each video bridge in the cascaded videobridge setup.

    videobridge {
      stats {
        enabled = true
        transports = [
          { type = "muc" }
        ]
      }
    
      apis {
        rest {
          enabled = true
        }
        xmpp-client {
          configs {
            xmpp-server-1 {
            hostname="meet.kofimupati.com"
            domain = "auth.meet.kofimupati.com"
            username = "jvb"
            password = "18YlmYSH"
            muc_jids = "JvbBrewery@internal.auth.kofimupati.com"
            muc_nickname = "08a74380-a3d3-4763-adf4-545c55743b3e"
          }
        }
       }
      }
    
      cc {
        max-time-between-calculations = 5 seconds
        bwe-change-threshold = 0.1
        padding-period = 10ms
        jvb-last-n = -1
        trust-bwe = false
      }
    
      http-servers {
        public {
        port = 9090
       }
     }
    
      websockets {
        enabled = true
        domain = "meet.kofimupati.com:443"
        tls = true
      }
    
      relay {
        enabled=true
        region="region1"
        relay-id="jitsi-videobridge"
      }
    
    }

Note: The use of sip-communicator.properties is currently deprecated.
Update the **sip-communicator.properties: /etc/jitsi/videobridge/sip-communicator.properties**

    org.ice4j.ice.harvest.DISABLE_AWS_HARVESTER=true
    org.ice4j.ice.harvest.STUN_MAPPING_HARVESTER_ADDRESSES=meet-jit-si-turnrelay.jitsi.net:443
    
    ++org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS=10.106.0.3 #Private IP of the Server
    ++org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS=178.62.18.4. #Public IP of the Server
    
    org.jitsi.videobridge.ENABLE_STATISTICS=true
    
    --org.jitsi.videobridge.STATISTICS_TRANSPORT=muc
    ++org.jitsi.videobridge.STATISTICS_TRANSPORT=muc,colibri
    
    ++org.jitsi.videobridge.STATISTICS_INTERVAL=2000
    
    --org.jitsi.videobridge.xmpp.user.shard.HOSTNAME=localhost
    ++org.jitsi.videobridge.xmpp.user.shard.HOSTNAME=meet.kofimupati.com
    
    org.jitsi.videobridge.xmpp.user.shard.DOMAIN=auth.meet.kofimupati.com
    org.jitsi.videobridge.xmpp.user.shard.USERNAME=jvb
    org.jitsi.videobridge.xmpp.user.shard.PASSWORD=18YlmYSH
    org.jitsi.videobridge.xmpp.user.shard.MUC_JIDS=JvbBrewery@internal.auth.meet.virtualcp.app
    org.jitsi.videobridge.xmpp.user.shard.MUC_NICKNAME=be350741-2b3d-4829-95ee-a60c4fbae28b
    
    ++org.jitsi.videobridge.SINGLE_PORT_HARVESTER_PORT=10000
    ++org.jitsi.videobridge.TCP_HARVESTER_PORT=443
    ++org.jitsi.videobridge.octo.BIND_ADDRESS=10.106.0.3 #Private IP of the Server
    ++org.jitsi.videobridge.octo.PUBLIC_ADDRESS=178.62.18.4 #Public IP of the Server
    ++org.jitsi.videobridge.octo.BIND_PORT=4096
    +++org.jitsi.videobridge.REGION=region1

**Modify the Jicofo Configuration on the Jitsi Server
**It is responsible for managing media sessions between each of the participants and the video bridge. [Link to repository](https://github.com/jitsi/jicofo)

Update the **config**: ***/etc/jitsi/jicofo/config***

    --JICOFO_HOST=localhost
    ++JICOFO_HOST=meet.kofimupati.com

Update the **jicofo.conf**: ***/etc/jitsi/jicofo/jicofo.conf***

**selection-strategy**: This is used to define how “participants” on a call are assigned to videobridges.
**octo**: Enabling octo is what causes Jicofo to assign “participants” in a single conference across multiple videobridges.

    jicofo {
      xmpp: {
        client: {
        client-proxy: focus.meet.kofimupati.com
       }  
        trusted-domains: [ "recorder.meet.kofimupati.com" ]
      }
    
      bridge {
        brewery-jid: "JvbBrewery@internal.auth.meet.kofimupati.com"
        selection-strategy = SplitBridgeSelectionStrategy
      }
    
      octo {
        enabled = true
        id = "1"
      }
    }

* **Modify the Jicofo Configuration on the Jitsi Server**

Configure the **app-config.js** i.e **/etc/jitsi/meet/meet.kofimupati.com-config.js **to enable WebSocket and any configuration needed for your use case.
This might not be necessary for you.

    --// websocket: 'wss://meet.kofimupati.com/' + subdir + 'xmpp-websocket',
    ++websocket: 'wss://meet.kofimupati.com/' + subdir + 'xmpp-websocket',
    
    // Add the following line just before the section which begins with the comment // UI
    openBridgeChannel: 'websocket',

**Modify the Prosody Configuration on the Jitsi Server**

Prosody is the XMPP component of Jitsi that handles the messaging. 
We also enable communication via **WebSocket** instead of **BOSH** which happens to be the default on a fresh installation.

Enable ports and allow all IPs to reach the prosody server by adding the following to **/etc/prosody/prosody.cfg.lua**

    admin = {}
    component_ports = { 5347 }
    component_interface = "0.0.0.0"
    
    --use_libevent = true
    use_libevent = true
    
    -- Uncomment websocket under HTTP modules
    --"websocket"
    "websocket"
    
    -- Comment out VirtualHost "localhost" under the Virtual hosts section
    
    VirtualHost "localhost"
    --VirtualHost "localhost"

Configure the domain-specific prosody settings by modifying **/etc/prosody/conf.d/meet.virtualcp.app.cfg.lua**

    -- Add the following to allow the use of websocket with the low-level library.
    cross_domain_bosh = false;
    consider_bosh_secure = true;
    cross_domain_websocket = true;
    consider_websocket_secure = true;
    
    
    -- Add smacks and websocket to modules enabled and configurations for smacks
    modules_enables = {
      "smacks";
      "websocket";
    }
    
    smacks_max_unacked_stanzas = 5;
    smacks_hibernation_time = 60;
    smacks_max_hibernated_sessions = 1;
    smacks_max_old_sessions = 1;

**Modify the Nginx Configuration on the Jitsi Server
**Add the following to enable WebSocket connection between external video bridges which will be configured later. The following nginx location blocks are needed for the cascaded videobridges to work.

Add them after the **location ~ ^/colibri-ws/default-id/(.*)** block.

    location ~ ^/colibri-ws/([0-9.]*)/(.*) {
      proxy_pass http://$1:9090/colibri-ws/$1/$2$is_args$args;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      tcp_nodelay on;
    }
    
    # colibri secure-octo relay websockets for jvb1
    
    location ~ ^/colibri-relay-ws/default-id/(.*) {
      proxy_pass http://jvb1/colibri-relay-ws/default-id/$1$is_args$args;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      tcp_nodelay on;
    }
    
    
    location ~ ^/colibri-relay-ws/([0-9.]*)/(.*) {
      proxy_pass http://$1:9090/colibri-relay-ws/$1/$2$is_args$args;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_set_header Host meet.virtualcp.app;
      tcp_nodelay on;
    }

**CONFIGURING EXTERNAL VIDEO BRIDGES**

 1. Install just the **jitsi-videobridge2** component on each of the external JVBs.

**add jitsi package repository**

```
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
    
sudo apt install jitsi-videobridge2
```

2. During installation enter the domain of the Jitsi Server in the prompt that shows up i.e. **meet.kofimupati.com** in my case.

3. Allow access to the following ports on the firewall.

```   
    ufw allow 9090/tcp
    ufw allow 9090/udp
    ufw allow 5347/tcp
    ufw allow 5347/udp
    ufw allow 5222/tcp
    ufw allow 5222/udp
    ufw allow 10000/tcp
    ufw allow 10000/udp
    ufw allow 4096/tcp
    ufw allow 4096/udp
    ufw enable
```

4. Configure the VideoBridge
Replace ***jvb.conf***, ***sip-communicator.properties,*** and ***config ***on the external video bridge with what was configured on the Jitsi Server.

Using **jvb1** as an example:

Changes to ***/etc/jitsi/videobridge/config
*JVB_SECRET** should have the same value for the main and external video bridges.

    JVB_HOST=
    JVB_SECRET=18YlmYSH
    JVB_OPTS="--apis=rest,xmpp --subdomain=jvb1"

Changes to ***/etc/jitsi/videobridge/jvb.conf
* ***Add **disable_certificate_verification = true** to **xmpp-client.configs.xmpp-server-1
* **Set the **muc_nickname** with the value found in **sip-communicator.properties** of the current external videobridge (jvb1) being configured.
* Set a different **region** and **relay-id** for each external videobridge.
* Add a **server-id** option to the WebSocket block of only the external videobridges. This value should be the Public IP of the videobridge server.

```
    videobridge {
      stats {
        enabled = true
        transports = [
          { type = "muc" }
        ]
      }
    
      apis {
        rest {
          enabled = true
        }
        xmpp-client {
          configs {
            xmpp-server-1 {
            hostname="meet.kofimupati.com"
            domain = "auth.meet.kofimupati.com"
            username = "jvb"
            password = "18YlmYSH"
            muc_jids = "JvbBrewery@internal.auth.kofimupati.com"
            muc_nickname = "44643c18-e111-4bfc-9fcc-29f57bb415d8"
            disable_certificate_verification = true
          }
        }
       }
      }
    
      cc {
        max-time-between-calculations = 5 seconds
        bwe-change-threshold = 0.1
        padding-period = 10ms
        jvb-last-n = -1
        trust-bwe = false
      }
    
      http-servers {
        public {
        port = 9090
       }
     }
    
      websockets {
        server-id = "203.500.130.37"
        enabled = true
        domain = "meet.kofimupati.com:443"
        tls = true
      }
    
      relay {
        enabled=true
        region="region2"
        relay-id="jvb1"
      }
    
    }
  ```  

Changes to ***/etc/jitsi/videobridge/sip-communicator.properties***

    --org.jitsi.videobridge.xmpp.user.shard
    ++org.jitsi.videobridge.xmpp.user.jvb1

    org.ice4j.ice.harvest.DISABLE_AWS_HARVESTER=true
    org.ice4j.ice.harvest.STUN_MAPPING_HARVESTER_ADDRESSES=meet-jit-si-turnrelay.jitsi.net:443
    
    ++org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS=10.106.0.3 #Private IP of the jvb1
    ++org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS=178.62.18.4. #Public IP of the jvb1
    
    org.jitsi.videobridge.ENABLE_STATISTICS=true
    
    --org.jitsi.videobridge.STATISTICS_TRANSPORT=muc
    ++org.jitsi.videobridge.STATISTICS_TRANSPORT=muc,colibri
    
    ++org.jitsi.videobridge.STATISTICS_INTERVAL=2000
    
    --org.jitsi.videobridge.xmpp.user.shard.HOSTNAME=localhost
    ++org.jitsi.videobridge.xmpp.user.shard.HOSTNAME=meet.kofimupati.com
    
    org.jitsi.videobridge.xmpp.user.jvb1.DOMAIN=auth.meet.kofimupati.com
    org.jitsi.videobridge.xmpp.user.jvb1.USERNAME=jvb
    org.jitsi.videobridge.xmpp.user.jvb1.PASSWORD=18YlmYSH
    org.jitsi.videobridge.xmpp.user.jvb1.MUC_JIDS=JvbBrewery@internal.auth.meet.virtualcp.app
    org.jitsi.videobridge.xmpp.user.jvb1.MUC_NICKNAME=44643c18-e111-4bfc-9fcc-29f57bb415d8
    ++org.jitsi.videobridge.xmpp.user.jvb1.DISABLE_CERTIFICATE_VERIFICATION=true
    
    ++org.jitsi.videobridge.SINGLE_PORT_HARVESTER_PORT=10000
    ++org.jitsi.videobridge.TCP_HARVESTER_PORT=443
    ++org.jitsi.videobridge.octo.BIND_ADDRESS=10.106.0.3 #Private IP of the jvb1
    ++org.jitsi.videobridge.octo.PUBLIC_ADDRESS=178.62.18.4 #Public IP of the jvb1
    ++org.jitsi.videobridge.octo.BIND_PORT=4096
    +++org.jitsi.videobridge.REGION=region2

Repeat the above external video bridge configuration steps for all the videobridges you want to use.

## Conclusion

Jitsi is an open-source video conferencing solution that can serve most of your needs. You can self-host and use the [**lib-meet-jitsi](https://github.com/jitsi/lib-jitsi-meet) **to build whichever experience you want.

If you need help building your custom application on top of Jitsi, you know what to do 😉