Jitsi and Jibri on AWS - Very easy comprehensive guide for dummies

Jitsi and Jibri on AWS for dummies

In this article, I will share a solution for using Jitsi and Jibri on a full AWS solution. Full AWS means that everything will be done using AWS, including DNS configuration. This will be a step by step installation, so you can stop whenever you want.

I relied a lot on How-to to setup integrated Jitsi and Jibri for dummies, my comprehensive tutorial for the beginner to write this guide. I just applied a lot of things which are specific to AWS on top of it (like How to change default kernel in Ubuntu (AWS) (Jibri)), and also applied the Jibri configuration migration guide.

Architecture

Running a server in the cloud will cost you money. So it is very important to think about the architecture and about the solution you want before starting.

In this architecture, we will have two servers :

  • One server for Jitsi, which will be running 24 hours a day
  • One server for Jibri, which will be running on demand

The reason for this is pretty simple. It’s easy to run Jitsi on a very small unexpensive server. So the cost of that server will be less than $5.

But Jibri has to run on powerful servers, which means expensive one. As it will be expensive, I want this server to run only when needed, and to switch it down when we don’t need it.

My personal use case is pretty simple: I’m doing only one to one conferences, and there is never more than one conference at a time.
So the Jibri server should start when a conference starts, and should stop when we both have no conference running and no operation to do.
Of course, if the server is stopped, it means that the recordings are not accessible anymore. In order to solve this issue, everytime a video have been recorded, it needs to be saved in a not referenced video on YouTube.

That is the configuration we will achieve here.

Prerequisite

For this tutorial, we will assume that you are able to connect to the AWS console. That’s all you need to know

DNS

Domain registration

First, you will need a domain name to run your servers. In order to do so, we will need to use Route 53 service of AWS. Just type Route 53 in the search bar of the console, and choose the Route 53 option.

Then, in the register domain section, type the domain name you want to register, and then click on the Check button.

If the domain is available, it will automatically be added to your cart. Otherwise, you should retry this process until you find an available domain.

You can click on the Continue button at the bottom of the list of suggested domain names. After that, you have to complete the form about the registrant contact.

Fill in the form and click on the Continue button at the bottom of the form.

On the confirmation screen, just accept the terms and conditions and click on Complete Order.

Once registration process is completed, you may have to validate your email address, and domain validation may take some time (it depends on the domain name extension that you chose).

Feel free to continue the next steps of DNS section before the end of registration. But you will need the registration process to be completed before going to the Next section (Jitsi).

Allocate Elastic IP addresses

When using your server you ~may~ will reboot them sometimes. You also may want to reset everything and recreate some instance from scratch. This is an issue because everytime you reboot a machine, its public IP address will change by default.

In order to avoid this, we need to allocate IP addresses to our machines.

To do so, type elastic ips in the search bar of the console, and select the first item of the Features section (the only item which is exactly named Elastic IPs).

Now, before doing anything, be sure to double check the region on the top right corner of the console. It must match the region where you want to deploy your server.

Once done, just click on Allocate Elastic IP address button, and then on Allocate button. Do the process two times (one for Jitsi server, one for Jibri server).

Once done, feel free to assign a name to the IP addresses, so you can easily identify them.

Adding DNS records

In the search bar of the console, type Hoted Zones.

Choose the first item of the Features section, which has the same exact name. You should find a hosted zone associated to the domain name you just created:

Click on your domain name. You then arrive on a screen with the details of your hosted zone. Click on the Create record button.


If you don’t see this Wizard, just click on the Switch to Wizard link.

Choose Simple routing and click on Next.

In the new screen, click on the button Define simple record.

  • For the record name, put the prefix of the address you want for accessing to Jitsi (Here I put meet because I want to access Jitsi with the URL meet.gahfy.io).
  • For the record type, choose A.
  • Value/Route traffic to: choose IP address and then write down the IP address you want to associate to Jitsi
  • TTL (seconds): I recommend you to put 172800. A high value will help you saving costs on your hosted zone, a low value will help you debug and change fast values. If you put 172800, please be sure to ~double~ triple check that the IP address is the correct one

Once done, click on Define simple record. Click again on the Define simple record at the top, and do the exact same process with recording prefix and the IP address you want to associate to Jibri.

Once done, please check again that the IP address you associated are correct, and click on the Create records button.

DNS registration is now done.

Jitsi

It is now time to install Jitsi on a server.

AWS instance

Creating Key Pairs

We will run the Jitsi server on Linux. In order to connect through SSH to your server, you will need a key pair. In order to create one, just type Key Pairs in the search bar of the console, and select the first item of the Features section.

Click on the Create key pair button and give it a name. In order to keep it clear, I usually name it AWSEC2[Region]KeyPair.

IMPORTANT
I’m a macOS user, so I will choose the .pem type, and you choose same type for Linux. I don’t know how PuTTY works on Windows, but I guess you should choose the ppk type. If you chose the wrong type, you always have the option to convert one to another:

How do I convert a .pem file into a .ppk, and vice versa, on Windows and Linux?

Click on Create key pair, and your browser should download the pem file. Keep this file as safe and secure as possible. You should never loose it (otherwise, you won’t be able to access your server anymore) and never make it accessible (otherwise anybody would be able to access your server). As an example, I keep the content of the file in my password manager.

Creating instance

In the search bar of the console, type ec2 and then, select the first result.

Find the launch instance panel, and then, click on the Launch instance button, and select Launch instance option :

Then you will choose the image on which you want to run Jitsi. It is strongly recommended to choose an Ubuntu or a Debian image. As we want our server to be as low consuming as possible, we will choose the debian instance.

Type debian in the search bar, then Enter, and choose the Debian 10 image by clicking on the Select button on the right.

Then you’ll have to choose an instance type. This is a tricky question, as Jitsi can run on any kind of instance. For example, I’m choosing a t3.nano which allows me to have a certain bandwith at a limited price for the instance. But this choice is made because of my use : never more than one conference at a time, each conference are made by two people only. I would strongly advice you to check about performances requested by Jitsi before making a choice. The good news about it is that it is a cloud server, so you may feel free to underestimate your needs, and then adjust the performance if you reach the limits.

You can now click on Review and Launch button, then on Launch button. Choose the Key pair you’ve created and click on the Launch instances button.

Once done, please wait until the load is complete, and click on the View Instances button on the bottom right.

You should see your instance running. Same as before, feel free to rename it:

Associating instance to IP address

On the search console, type elastic ips and select the first item of the Features section in order to go back to Elastic IPs address.

Click on the checkbox of your Jitsi IP address, then on Actions and choose Associate Elastic IP address.

Now, you can select your instance for associating your IP address with:

Just click then on Associate button.

Connecting through SSH

I’m sorry for Windows users, I won’t cover how to connect to your instance through SSH here. Please refer to Connect to your Linux instance from Windows using PuTTY

Explanation in the “Connecting through SSH” section are valid for macOS and Linux only

First, change the permissions to your key file:

chmod 400 /path/to/your/keypair/file.pem

For example, in my case, it is :

chmod 400 ~/Downloads/AWSEC2ParisKeyPair.pem

Open a terminal, and type the following command to connect to your instance :

ssh -i /path/to/your/keypair/file.pem admin@meet.yourdomain.com

For example, in my case it is :

ssh -i ~/Downloads/AWSEC2ParisKeyPair.pem admin@meet.gahfy.io

It is very important that you use the domain name you just created. This will allow you to be sure that all Hosted Zones and IP assignation is working fine.

Just type yes when asking about adding it to known hosts, and you should be fine.

Updates

In the console, write the following command to update your system:

sudo apt update && sudo apt -y upgrade

Installing required packages

Now, we have to install the packages that will be required for the installation process:

sudo apt -y install gnupg2 nginx-full apt-transport-https

Setup domain and DNS

We now need to setup the domain name of the machine and redirect the domain name to localhost to
save bandwith and increase speed:

Don’t forget to replace gahfy.io by your domain name

sudo hostnamectl set-hostname meet.gahfy.io

And then, edit your /etc/hosts file to add your domain name:

sudo nano /etc/hosts

You need to add your domain name after localhost, so the line looks like this:

Don’t forget to replace gahfy.io by your domain name

127.0.0.1 localhost meet.gahfy.io

Then, type Ctrl+O (it’s Ctrl key even on macOS) to save the file, and then Ctrl+X to exit the file.

You can check by running the command ping "$(hostname)" and the result should look like:

PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.387 ms

Add the Jitsi package repository

We will install Jitsi by using package manager. You can try the following command:

sudo apt -y install jitsi-meet

You will get the following error:

Reading package lists... Done
Building dependency tree       
Reading state information... Done
E: Unable to locate package jitsi-meet

In order to be able to install Jitsi, we need to add the repository containing the Jitsi packages to the apt tool. Just copy paste the following commands to do so:

curl 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 > /dev/null
sudo apt update

Install Jitsi

You can now safely run the command we tried earlier:

sudo apt -y install jitsi-meet

When running this command, you will be first asked for the domain name. Just type the DNS address of your server:

Then you will be asked about certificate. Choose the self signed certificate for now:

Configure access (optional)

To know if you need to do those steps, just follow this:

  • Will your jitsi server be accessible worldwide (it means, will anybody from anywhere be able to access https://meet.yourdomain.com)?
    • Yes: Do you want to compete with jit.si? :wink:
      • Yes: Skip this part (spoiler alert: a t3.nano instance won’t be enough :wink: )
      • No: Follow the steps below
    • No: Do you want to restrict ability to create conferences ?
      • Yes: Follow the steps below
      • No : Skip this part

If you decide to follow this part, of course, you need to do this before firewall configuration for security reason:

First, let’s edit the prosody configuration:

Replace meet.gahfy.io by your domain name.

sudo nano /etc/prosody/conf.avail/meet.gahfy.io.cfg.lua

Just type Ctrl+W to find a part of the document, and write VirtualHost "meet.gahfy.io" (once again, replace with your domain name).

Two lines below, you should find a line like this:

authentication = "anonymous"

Just replace anonymous by internal_hashed

If you keep things like this, only authenticated users will be able to join a conference. If you want to allow guests to join a conference (they won’t be able to create a conference, but they will be able to join an existing one), just add the following lines at the end of the file (If you type Ctrl+V it will allow you to go one page down, if you keep them pressed, it will allow you to reach the end of the file faster) :

Don’t forget to replace gahfy.io by your domain name

VirtualHost "guest.meet.gahfy.io"
    authentication = "anonymous"
    c2s_require_encryption = false

Once done, just save (Ctrl+O) and exit the file (Ctrl+X).

If you allow guests to join existing conferences, you need to edit the /etc/jitsi/meet/meet.gahfy.io-config.js (once again, replace meet.gahfy.io by your domain name):

Replace meet.gahfy.io by your domain name

sudo nano /etc/jitsi/meet/meet.gahfy.io-config.js

Just add the following line for adding the anonymous domain:

We now need to edit Jicofo configuration :

sudo nano /etc/jitsi/jicofo/sip-communicator.properties

Add a new line at the end of the file with the following content:

Replace meet.gahfy.io by your domain name.

org.jitsi.jicofo.auth.URL=XMPP:meet.gahfy.io

Just exit and save the file (I guess you remember the shortcuts now).

Last but not least, we need to add the user which will be able to create conferences with the following command:

Replace meet.gahfy.io by your domain name.

sudo prosodyctl register <username> meet.gahfy.io <password>

Finally, just restart all the services to be able to apply the new configuration:

sudo systemctl restart prosody
sudo systemctl restart jicofo
sudo systemctl restart jitsi-videobridge2

Firewall configuration

For now, your server is only accessible worldwide on port 22 (that’s because this port is open that you can access your server through SSH). This means that jitsi is not accessible by anybody.
At this stage, we have three opions:

  • Open every ports worldwide on AWS and configure the firewall on the machine
  • Configure the firewall on both AWS and the machine
  • Configure the firewall on AWS only

We will choose the third option because it’s the safest and it is secure enough (configuring a wrong permission on the machine may make it inaccessible forever).

Just go on the details of your instance on the AWS console (just type ec2 instances in the search bar, and click on the first item of the Features section).

Then click on the link of the instance id of the Jitsi instance.

On the bottom part, click on the Security tab, and then, on the link of the security group:

On the bottom part, click on Edit inbound rules button.

In this part, I will not cover any specific configuration. I will open all the jitsi services worldwide. Please check some tutorials on how to be more specific.

Just add the following rules, and click on the Save rules button at the very bottom of the page.

Type Protocol Port range Source ___
HTTP TCP 80 Custom 0.0.0.0/0
HTTPS TCP 443 Custom 0.0.0.0/0
Custom TCP TCP 5222 Custom [IP address of Jibri]/32
Custom UDP UDP 10000 Custom 0.0.0.0/0
Custom UDP UDP 3478 Custom 0.0.0.0/0
Custom TCP TCP 5349 Custom 0.0.0.0/0
  • If you follow this tutorial only, and you are sure that you will never use stun server, then the 3478 UDP rule can be ignored
  • If you are sure that UDP 10,000 will never be blocked for any of the users, then the last TCP rule can be safely removed
  • If you don’t want to use Jibri, then the TCP 5222 rule can be safely ignored

That’s it, your server is now accessible worldwide.

SSL registration

We strongly encourage you to register a valid SSL certificate with Let’s Encrypt service. It’s free and well implemented in Jitsi tools. Just run the following command on your server through SSH:

sudo /usr/share/jitsi-meet/scripts/install-letsencrypt-cert.sh

Just enter your email address when prompted and … that’s it.

You can now access https://meet.yourdomain.com through your browser and start some meetings. Unfortunately, you are not able to record them or to livestream them.

Jibri

Jibri will allow you to record and/or livestream your conferences. One important thing to remember is that you need one Jibri instance per concurrent recording or stream. This means, you cannot record two conferences at same time with one server.
With the architecture we described above, we don’t have to care about concurrency, as we won’t have two conferences at the same time.

IMPORTANT NOTE : Running a Jitsi server is quite easy and at very low risks. The reason for writing this tutorial is about installation of Jibri with a running Jitsi. We strongly encourage you to follow the steps exactly as described, and to take care of the important notes I will write.

Create AWS instance

We need to create an instance for Jibri. Go to EC2 home screen (as explained above for Jitsi), and select Launch Instances.

Choose an Ubuntu 18.04 LTS image (the second in the below image) :

IMPORTANT NOTE : Be carefull by choosing your image, and choose specifically the Ubuntu Server 18.04. If you’re not sure about the right version, type the following in search bar ami-06602da18c878f98d and choose the only result. I couldn’t succeed in installing Jibri on any other version of Ubuntu on AWS, so I won’t be able to answer if there is any question about an other version

Click on the Select button.

You need a powerful server to run Jibri, here comes a second important note :wink:

IMPORTANT NOTE : For the Jitsi server, we can have fun, it’s a server which will cost you less than $5 a month. Here, we’re dealing with a server which will cost at least $0.08 per hour when running, meaning that it will be at least $60 per month if you run it 24 hours a day without saving offer. Don’t underestimate that cost.

I will choose a t3.xlarge instance, which is around $0.17 per month, or $120 per month if running non stop without saving plan. Once again, please choose the instance carefully, depending on what you want to do.

You can now click on Review and Launch button, and then select your Key pair to launch your instance.

Associate Elastic IP address

We strongly encourage you to rename your instance with Jibri name to make everything more clear, and then associate the Jibri Elastic IP address to this instance (details on the procedure above).

SSH connection

Now, connect to your instance using SSH, and using ubuntu@recording.yourdomain.com to be sure that IP address association and DNS routing are well done.

Note: Please keep in mind that username is now ubuntu instead of admin, this is because we use an Ubuntu image instead of a Debian one.

Changing the kernel

With the default AWS kernel, you won’t be able to run Jibri. First, let’s update and upgrade packages that needs to be upgraded:

sudo apt update && sudo apt -y upgrade

Then, install the linux-image-extra-virtual to be able to switch to a generic kernel:

sudo apt -y install linux-image-extra-virtual

Now, let’s check the GRUB options we have to choose the kernel we will run on:

grep -A100 submenu /boot/grub/grub.cfg |grep menuentry

You will then get a result which looks like this :


submenu ‘Advanced options for Ubuntu’ $menuentry_id_option ‘gnulinux-advanced-db937f23-4ed7-4c4b-8058-b23a860fae08’ {

menuentry ‘Ubuntu, with Linux 5.4.0-1051-aws’ --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option ‘gnulinux-5.4.0-1051-aws-advanced-db937f23-4ed7-4c4b-8058-b23a860fae08’ {

menuentry ‘Ubuntu, with Linux 5.4.0-1051-aws (recovery mode)’ --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option ‘gnulinux-5.4.0-1051-aws-recovery-db937f23-4ed7-4c4b-8058-b23a860fae08’ {

menuentry ‘Ubuntu, with Linux 5.4.0-1045-aws’ --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option ‘gnulinux-5.4.0-1045-aws-advanced-db937f23-4ed7-4c4b-8058-b23a860fae08’ {
menuentry ‘Ubuntu, with Linux 5.4.0-1045-aws (recovery mode)’ --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option ‘gnulinux-5.4.0-1045-aws-recovery-db937f23-4ed7-4c4b-8058-b23a860fae08’ {

menuentry ‘Ubuntu, with Linux 4.15.0-147-generic’ --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option ‘gnulinux-4.15.0-147-generic-advanced-db937f23-4ed7-4c4b-8058-b23a860fae08’ {

menuentry ‘Ubuntu, with Linux 4.15.0-147-generic (recovery mode)’ --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option ‘gnulinux-4.15.0-147-generic-recovery-db937f23-4ed7-4c4b-8058-b23a860fae08’ {


VERY IMPORTANT NOTE : This step is the most dangerous one of this tutorial, but also a step that cannot be skipped. Please read carefully.

  • FROM YOUR RESULT take the part matching the one in bold in the example above
  • Then, in the list of lines, check for the line which contains Ubuntu, … -generic and which does not contain recovery mode. There should be only one line
  • FROM YOUR RESULT take the part matching the last bold part in example above from the line you isolated in second step

Put the > sign between the first and second string you isolated. In my case, it will be gnulinux-advanced-db937f23-4ed7-4c4b-8058-b23a860fae08>gnulinux-4.15.0-147-generic-advanced-db937f23-4ed7-4c4b-8058-b23a860fae08. Keep that string somewhere you can easily access it (out of the SSH console).

Now, type the following command :

sudo nano /etc/default/grub

You should fine a first line containing:

GRUB_DEFAULT=0

Replace the 0 by the string of the previous step, in double quotes:

Then, save with Ctrl+O and exit with Ctrl+X. Then run the following command to let GRUB be aware of your changes:

sudo update-grub

Now, just reboot the server :

sudo reboot

After two minutes, you should be able to access your instance in ssh.

I have wait for 5 minutes but still cannot access my instance through SSH

That’s great, you make me being right in putting this part first :wink: Actually, there’s no way to solve this. The only way is to restart from scratch. In your instance Dashboard, select your Jibri instance (check the left checkbox), click on the Instance state button on the top and click on Terminate instance. Click on Terminate button to confirm, and start again from start (from the beginning of the Jibri section)

Once you can access your instance through SSH, run the following command to check if what you have done is correct:

uname -r

The result should be something like 4.15.0-147-generic. The version number does not matter, but it should end with -generic. If it ends with -aws then you should try again all the steps of “Changing the Kernel” section.

If you arrived here successfully, then you can take a deep breathe, the most dangerous part is over.

Hostname configuration

It’s now time to do the hostname configuration on the server. To do so, run the following command first:

Replace recording.gahfy.io by your domain name.

sudo hostnamectl set-hostname recording.gahfy.io

Then, edit the /etc/hosts file:

sudo nano /etc/hosts

On the first line, after localhost, write your domain name, so the first line should look like this:

Replace recording.gahfy.io by your domain name

127.0.0.1 localhost recording.gahfy.io

Just save (Ctrl+O) and exit (Ctrl+X). Now, run the following command to check that everything is working fine:

ping "$(hostname)"

The result should look like this:

PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.092 ms

Java installation

Jibri requires Java 8 to work. Let’s then install the openjdk-8-jre-headless package to let it work:

sudo apt -y install openjdk-8-jre-headless

Jibri also requires that the JAVA_HOME environment variable is set :

echo "export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java" >> ~/.bashrc

Yeah! We run our first command without sudo. And to be more happy, let’s run a second one:

source ~/.bashrc

Some required packages

Jibri needs some packages to be able to extract audio, encode video, … Let’s install them

sudo apt -y install unzip ffmpeg curl alsa-utils icewm xdotool xserver-xorg-input-void xserver-xorg-video-dummy

ALSA and loopback devices

Let’s now require snd-aloop module to be run on boot:

echo "snd-aloop" | sudo tee -a /etc/modules

Let’s now add it to the running kernel:

sudo modprobe snd-aloop

The above command should have no result. If you got an error, please check again from the beginning that all steps have been followed from the beginning.

Now, let’s check that snd-aloop module is running :

lsmod | grep snd_aloop

The result should look like this:

Google Chrome and its drivers

Jibri uses Google Chrome to access your Jitsi server and record the conference. That’s why we need to install it. First, we need to add the Google Chrome package repository, and then install the stable version of Google Chrome.

curl -sS -o - https://dl-ssl.google.com/linux/linux_signing_key.pub |sudo apt-key add
echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" | sudo tee -a /etc/apt/sources.list.d/google-chrome.list
sudo apt update && sudo apt -y install google-chrome-stable

Then, let’s hide the warning in Chrome with the following command :

sudo mkdir -p /etc/opt/chrome/policies/managed
echo '{ "CommandLineFlagSecurityWarningsEnabled": false }' | sudo tee -a /etc/opt/chrome/policies/managed/managed_policies.json

Finally, let’s install the Google Chrome drivers:

CHROME_DRIVER_VERSION=`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE`
wget -N http://chromedriver.storage.googleapis.com/$CHROME_DRIVER_VERSION/chromedriver_linux64.zip -P ~/
unzip ~/chromedriver_linux64.zip -d ~/
rm ~/chromedriver_linux64.zip
sudo mv -f ~/chromedriver /usr/local/bin/chromedriver
sudo chown root:root /usr/local/bin/chromedriver
sudo chmod 0755 /usr/local/bin/chromedriver

Install Jibri

Before installing Jibri, we need to add the Jitsi package repository (same as we did on Debian for Jitsi):

wget -qO - https://download.jitsi.org/jitsi-key.gpg.key | sudo apt-key add -
echo 'deb https://download.jitsi.org stable/' | sudo tee -a /etc/apt/sources.list.d/jitsi-stable.list
sudo apt update && sudo apt -y install jibri

User configuration

Let’s now add the Jibri user to the required groups:

sudo usermod -aG adm,audio,video,plugdev jibri

Jitsi configuration

We now need to configure Jitsi in order to enable recording and livestreaming. Just close your ssh session, and connect to your jitsi server through SSH.

Replace meet.gahfy.io by your domain name

ssh -i /path/to/key/pair/file.pem admin@meet.gahfy.io

For macOS and Linux only

Prosody

Let’s edit the configuration of Prosody first:

sudo nano /etc/prosody/conf.avail/meet.gahfy.io.cfg.lua

Then add the following part at the bottom of the file (Once again, keeping Ctrl+V pressed will allow you to reach the end faster):

Replace meet.gahfy.io by your domain name

-- internal muc component, meant to enable pools of jibri and jigasi clients
Component "internal.auth.meet.gahfy.io" "muc"
    modules_enabled = {
	    "ping";
    }
    storage = "memory"
    muc_room_cache_size = 1000
	
VirtualHost "recorder.meet.gahfy.io"
    modules_enabled = {
        "ping";
    }
    authentication = "internal_plain"

Then, reload prosody:

sudo systemctl reload prosody

Finally, we can add the users for jibri and the recorder:

Replace meet.gahfy.io by your domain and replace the passwords by some passwords you will keep

sudo prosodyctl register jibri auth.meet.gahfy.io <password_for_jibri>
sudo prosodyctl register recorder recorder.meet.gahfy.io <password_for_recorder>

Jicofo

It’s now time to configure jicofo:

sudo nano /etc/jitsi/jicofo/sip-communicator.properties

Add those two lines at the end of the file:

Replace meet.gahfy.io by your domain name

org.jitsi.jicofo.jibri.BREWERY=JibriBrewery@internal.auth.meet.gahfy.io
org.jitsi.jicofo.jibri.PENDING_TIMEOUT=90

Then save and exit, I guess you know the shortcuts now :slight_smile:

Finally, don’t forget to reload jicofo:

sudo systemctl reload jicofo

Jitsi meet

Let’s configure Jitsi meet:

Replace meet.gahfy.io by your domain name

sudo nano /etc/jitsi/meet/meet.gahfy.io-config.js

Now find the fileRecordingsEnabled property (Hit Ctrl+W to find, then type fileRecordingsEnabled, then hit Enter).

Uncomment this line by removing the two slashes, and switch its value from false to true if you want to allow file recording.

Around 20 lines below, you should find liveStreamingEnabled property. Once again, uncomment it, and switch its value to true if you want to allow live streaming, or false otherwise.

Finally, below the liveStreamingEnabled line, add the following line:

Replace meet.gahfy.io by your domain name

hiddenDomain: 'recorder.meet.gahfy.io',

Here is what my configuration looks like (I want to allow file recording, but not livestreaming):

Save and exit the file.

Jibri configuration

It’s now time to go back to Jibri server. Close the Jitsi SSH connection and open a new one to your recording instance:

Replace recording.gahfy.io by your domain name

ssh -i /path/to/key/pair/file.pem ubuntu@recording.gahfy.io

For macOS and Linux only

Then, edit the jitsi configuration file:

sudo nano /etc/jitsi/jibri/jibri.conf

Replace the content of the file by the following (be sure to replace domain names and passwords everywhere):

jibri {
    recording {
        recordings-directory = "/srv/recordings"
        finalize-script = "/path/to/finalize_recording.sh"
    }

    chrome {
        flags = [
            "--use-fake-ui-for-media-stream",
            "--start-maximized",
            "--kiosk",
            "--enabled",
            "--disable-infobars",
            "--autoplay-policy=no-user-gesture-required",
            "--ignore-certificate-errors"
        ]
    }

    api {
        xmpp {
            environments = [
                {
                    name = "prod environment"
                    xmpp-server-hosts = ["meet.gahfy.io"]
                    xmpp-domain = "meet.gahfy.io"

                    control-muc {
                        domain = "internal.auth.meet.gahfy.io"
                        room-name = "JibriBrewery"
                        nickname = "jibri-nickname"
                    }

                    control-login {
                        domain = "auth.meet.gahfy.io"
                        username = "jibri"
                        password = "<password_for_jibri>"
                    }

                    call-login {
                        domain = "recorder.meet.gahfy.io"
                        username = "recorder"
                        password = "<password_for_recorder>"
                    }

                    strip-from-room-domain = "conference."
                    usage-timeout = "0"

                    trust-all-xmpp-certs = true
                }
            ]
        }
    }
}

Just save and exit the file.

Now we need to create the directory where the recordings will be stored, and set jibri user as owner of those:

sudo mkdir /srv/recordings
sudo chown jibri:jitsi /srv/recordings

Finally, all we need to do is to restart jibri service:

sudo systemctl restart jibri

Restarting jitsi

Finally, we need to restart all the services on the Jitsi server. Just close the current SSH connection, and connect to Jitsi through SSH:

Replace meet.gahfy.io by your domain name

ssh -i /path/to/key/pair/file.pem admin@meet.gahfy.io

For macOS and Linux only

Then run the following command:

sudo /etc/init.d/prosody restart
sudo /etc/init.d/jicofo restart
sudo /etc/init.d/jitsi-videobridge2 restart

That’s all. You can now register video and you can find them in the /srv/recordings folder of your Jibri server.

Auto upload to YouTube

Please give me some more time to write this part

Auto switch on and off Jibri server

Please give me some more time to write this part

9 Likes

Change of architecture

I actually faced problems when trying to auto-upload on YouTube. It requires a validated app, and has quota limitating uploads. Everything going through Google Verification process with is quite long and uncertain. After many fails, I decided to find an other solution.

I decided then to switch to Dropbox (as it was a shared solution here, I expected it to be more simple and actually it is). The name of the session will be the name of the folder in which the video will be uploaded. And because I know the name of the participants from the name of the session, I just have to share with them the shared folder on Dropbox.

Finally, it made things easier also for removing video safely. I just have to download the uploaded video, check md5sum of both the original and downloaded one, and if there are same, then we can safely remove the folder.

Auto-upload on Dropbox

I will not go through developer interface of Dropbox. All you need to do is to create an app, and from that app, create a permanent access token (No expiration).
For the scopes, as I am the only one user of the app, I selected them all.

Then, I created a folder named /etc/gahfy-app and put a script named upload_video.sh with the following content :

Don’t forget to edit the values of PERMANENT_ACCESS_TOKEN and DESTINATION_FILENAME variables.

#!/bin/bash

########################## INITIALIZATION

#!/bin/bash

PERMANENT_ACCESS_TOKEN="<your_permanent_access_token>"
VIDEO_FILE=$(ls $1/*.mp4)
VIDEO_NAME=$(ls $1/*.mp4 | perl -pe 's#/([a-z0-9A-Z]+/)+([^/]+).mp4#$2#')
FOLDER_NAME=$(ls $1/*.mp4 | perl -pe 's#/([a-z0-9A-Z]+/)+([^/]+)_[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}.mp4#$2#')
CHUNK_PREFIX="/tmp/videos_chunks"
DESTINATION_FILENAME="/OpenClassrooms/${FOLDER_NAME}/${VIDEO_NAME}.mp4"

mkdir -p $CHUNK_PREFIX

SUFFIXES=("aa" "ab" "ac" "ad" "ae" "af" "ag" "ah" "ai" "aj" "ak" "al" "am" "an" "ao" "ap" "aq" "ar" "as" "at" "au" "av" "aw" "ax" "ay" "az" "ba" "bb" "bc" "bd" "be" "bf" "bg" "bh" "bi" "bj" "bk" "bl" "bm" "bn" "bo" "bp" "bq" "br" "bs" "bt" "bu" "bv" "bw" "bx" "by" "bz" "ca" "cb" "cc" "cd" "ce" "cf" "cg" "ch" "ci" "cj" "ck" "cl" "cm" "cn" "co" "cp" "cq" "cr" "cs" "ct" "cu" "cv" "cw" "cx" "cy" "cz" "da" "db" "dc" "dd" "de" "df" "dg" "dh" "di" "dj" "dk" "dl" "dm" "dn" "do" "dp" "dq" "dr" "ds" "dt" "du" "dv" "dw" "dx" "dy" "dz" "ea" "eb" "ec" "ed" "ee" "ef" "eg" "eh" "ei" "ej" "ek" "el" "em" "en" "eo" "ep" "eq" "er" "es" "et" "eu" "ev" "ew" "ex" "ey" "ez" "fa" "fb" "fc" "fd" "fe" "ff" "fg" "fh" "fi" "fj" "fk" "fl" "fm" "fn" "fo" "fp" "fq" "fr" "fs" "ft" "fu" "fv" "fw" "fx" "fy" "fz" "ga" "gb" "gc" "gd" "ge" "gf" "gg" "gh" "gi" "gj" "gk" "gl" "gm" "gn" "go" "gp" "gq" "gr" "gs" "gt" "gu" "gv" "gw" "gx" "gy" "gz" "ha" "hb" "hc" "hd" "he" "hf" "hg" "hh" "hi" "hj" "hk" "hl" "hm" "hn" "ho" "hp" "hq" "hr" "hs" "ht" "hu" "hv" "hw" "hx" "hy" "hz" "ia" "ib" "ic" "id" "ie" "if" "ig" "ih" "ii" "ij" "ik" "il" "im" "in" "io" "ip" "iq" "ir" "is" "it" "iu" "iv" "iw" "ix" "iy" "iz" "ja" "jb" "jc" "jd" "je" "jf" "jg" "jh" "ji" "jj" "jk" "jl" "jm" "jn" "jo" "jp" "jq" "jr" "js" "jt" "ju" "jv" "jw" "jx" "jy" "jz" "ka" "kb" "kc" "kd" "ke" "kf" "kg" "kh" "ki" "kj" "kk" "kl" "km" "kn" "ko" "kp" "kq" "kr" "ks" "kt" "ku" "kv" "kw" "kx" "ky" "kz" "la" "lb" "lc" "ld" "le" "lf" "lg" "lh" "li" "lj" "lk" "ll" "lm" "ln" "lo" "lp" "lq" "lr" "ls" "lt" "lu" "lv" "lw" "lx" "ly" "lz" "ma" "mb" "mc" "md" "me" "mf" "mg" "mh" "mi" "mj" "mk" "ml" "mm" "mn" "mo" "mp" "mq" "mr" "ms" "mt" "mu" "mv" "mw" "mx" "my" "mz" "na" "nb" "nc" "nd" "ne" "nf" "ng" "nh" "ni" "nj" "nk" "nl" "nm" "nn" "no" "np" "nq" "nr" "ns" "nt" "nu" "nv" "nw" "nx" "ny" "nz" "oa" "ob" "oc" "od" "oe" "of" "og" "oh" "oi" "oj" "ok" "ol" "om" "on" "oo" "op" "oq" "or" "os" "ot" "ou" "ov" "ow" "ox" "oy" "oz" "pa" "pb" "pc" "pd" "pe" "pf" "pg" "ph" "pi" "pj" "pk" "pl" "pm" "pn" "po" "pp" "pq" "pr" "ps" "pt" "pu" "pv" "pw" "px" "py" "pz" "qa" "qb" "qc" "qd" "qe" "qf" "qg" "qh" "qi" "qj" "qk" "ql" "qm" "qn" "qo" "qp" "qq" "qr" "qs" "qt" "qu" "qv" "qw" "qx" "qy" "qz" "ra" "rb" "rc" "rd" "re" "rf" "rg" "rh" "ri" "rj" "rk" "rl" "rm" "rn" "ro" "rp" "rq" "rr" "rs" "rt" "ru" "rv" "rw" "rx" "ry" "rz" "sa" "sb" "sc" "sd" "se" "sf" "sg" "sh" "si" "sj" "sk" "sl" "sm" "sn" "so" "sp" "sq" "sr" "ss" "st" "su" "sv" "sw" "sx" "sy" "sz" "ta" "tb" "tc" "td" "te" "tf" "tg" "th" "ti" "tj" "tk" "tl" "tm" "tn" "to" "tp" "tq" "tr" "ts" "tt" "tu" "tv" "tw" "tx" "ty" "tz" "ua" "ub" "uc" "ud" "ue" "uf" "ug" "uh" "ui" "uj" "uk" "ul" "um" "un" "uo" "up" "uq" "ur" "us" "ut" "uu" "uv" "uw" "ux" "uy" "uz" "va" "vb" "vc" "vd" "ve" "vf" "vg" "vh" "vi" "vj" "vk" "vl" "vm" "vn" "vo" "vp" "vq" "vr" "vs" "vt" "vu" "vv" "vw" "vx" "vy" "vz" "wa" "wb" "wc" "wd" "we" "wf" "wg" "wh" "wi" "wj" "wk" "wl" "wm" "wn" "wo" "wp" "wq" "wr" "ws" "wt" "wu" "wv" "ww" "wx" "wy" "wz" "xa" "xb" "xc" "xd" "xe" "xf" "xg" "xh" "xi" "xj" "xk" "xl" "xm" "xn" "xo" "xp" "xq" "xr" "xs" "xt" "xu" "xv" "xw" "xx" "xy" "xz" "ya" "yb" "yc" "yd" "ye" "yf" "yg" "yh" "yi" "yj" "yk" "yl" "ym" "yn" "yo" "yp" "yq" "yr" "ys" "yt" "yu" "yv" "yw" "yx" "yy" "yz" "za" "zb" "zc" "zd" "ze" "zf" "zg" "zh" "zi" "zj" "zk" "zl" "zm" "zn" "zo" "zp" "zq" "zr" "zs" "zt" "zu" "zv" "zw" "zx" "zy" "zz" )

# Splitting the video file into 50MB chunks
split -b 52428800 ${VIDEO_FILE} ${CHUNK_PREFIX}/

upload () {
  curl -sX POST https://content.dropboxapi.com/2/files/upload \
      --header "Authorization: Bearer ${PERMANENT_ACCESS_TOKEN}" \
      --header "Dropbox-API-Arg: {\"path\": \"${DESTINATION_FILENAME}\",\"mode\": \"add\",\"autorename\": true,\"mute\": false,\"strict_conflict\": false}" \
      --header "Content-Type: application/octet-stream" \
      --data-binary "@$1" >/dev/null 2>&1
}

start_upload() {
  curl -sX POST https://content.dropboxapi.com/2/files/upload_session/start \
  --header "Authorization: Bearer ${PERMANENT_ACCESS_TOKEN}" \
  --header "Dropbox-API-Arg: {\"close\": false}" \
  --header "Content-Type: application/octet-stream" \
  --data-binary "@$1"  | perl -pe 's/.+"session_id": "([^"]+)".+/$1/'
}

append_upload() {
  curl -sX POST https://content.dropboxapi.com/2/files/upload_session/append_v2 \
    --header "Authorization: Bearer ${PERMANENT_ACCESS_TOKEN}" \
    --header "Dropbox-API-Arg: {\"cursor\": {\"session_id\": \"$1\",\"offset\": $2},\"close\": false}" \
    --header "Content-Type: application/octet-stream" \
    --data-binary "@$3" >/dev/null 2>&1
}

finish_upload() {
  curl -sX POST https://content.dropboxapi.com/2/files/upload_session/finish \
      --header "Authorization: Bearer ${PERMANENT_ACCESS_TOKEN}" \
      --header "Dropbox-API-Arg: {\"cursor\": {\"session_id\": \"$1\",\"offset\": $2},\"commit\": {\"path\": \"${DESTINATION_FILENAME}\",\"mode\": \"add\",\"autorename\": true,\"mute\": false,\"strict_conflict\": false}}" \
      --header "Content-Type: application/octet-stream" \
      --data-binary "@$3" >/dev/null 2>&1
}

NUMBER_OF_FILES=$(find ${CHUNK_PREFIX}/ -type f -name "*" | wc -l | sed 's/^[ \t]*//;s/[ \t]*$//')

if [ "${NUMBER_OF_FILES}" = "1" ]
then
  upload "${CHUNK_PREFIX}/aa"
else
  SESSION_ID=$(start_upload "${CHUNK_PREFIX}/aa")
  CURRENT_FILE="ab"
  NEXT_FILE="ac"
  CURRENT_INDEX=1
  CURRENT_OFFSET=52428800
  NEXT_FILE_COMPLETE=$(find ${CHUNK_PREFIX}/ -type f -name "${NEXT_FILE}" | wc -l | sed 's/^[ \t]*//;s/[ \t]*$//')
  while [ "${NEXT_FILE_COMPLETE}" = "1" ]
  do
    append_upload $SESSION_ID $CURRENT_OFFSET "${CHUNK_PREFIX}/${CURRENT_FILE}"
    CURRENT_INDEX=$((CURRENT_INDEX+1))
    CURRENT_FILE=${SUFFIXES[$CURRENT_INDEX]}
    NEXT_FILE=${SUFFIXES[$((CURRENT_INDEX+1))]}
    CURRENT_OFFSET=$((CURRENT_OFFSET+52428800))
    NEXT_FILE_COMPLETE=$(find ${CHUNK_PREFIX}/ -type f -name "${NEXT_FILE}" | wc -l | sed 's/^[ \t]*//;s/[ \t]*$//')
  done
  finish_upload $SESSION_ID $CURRENT_OFFSET "${CHUNK_PREFIX}/${CURRENT_FILE}"
fi

########################## VERIFICATION (if check OK)

curl -sX POST https://content.dropboxapi.com/2/files/download \
    --header "Authorization: Bearer ${PERMANENT_ACCESS_TOKEN}" \
    --header "Dropbox-API-Arg: {\"path\": \"${DESTINATION_FILENAME}\"}" > /tmp/videos_chunks/test.mp4

ORIGINAL_SUM=$(md5sum $VIDEO_FILE | awk '{ print $1 }')
DOWNLOADED_SUM=$(md5sum /tmp/videos_chunks/test.mp4 | awk '{ print $1 }')

if [ "${ORIGINAL_SUM}" = "${DOWNLOADED_SUM}" ]
then
  rm -r $1
fi

########################## REMOVE ALL CREATED FILES

rm ${CHUNK_PREFIX}/*

Make sure everybody can execute the script:

sudo chmod 755 /etc/gahfy-app/upload_video.sh

All we have to do now is to change the configuration of Jibri:

sudo nano /etc/jitsi/jibri/jibri.conf

Replace the line with finalize-script with the path to our file:

finalize-script = "/etc/gahfy-app/upload_video.sh"

Finally, all we have to do is to restart Jibri:

sudo systemctl restart jibri

And that’s all. The /srv/recordings folder will be clean automatically, and you can find the files for which the verification ended with an issue.

The way the script is done is safe (MD5 sum is a safe algorithm, not secure but safe) so you are sure that there is no way that this script deletes by accident a video file.

1 Like
1 Like

Definitely, this tool I knew already is great.
Actually, this includes downloading the tool, managing the debian dependencies (such as jq), take care about updates…
As this guide is for dummies, I found it more easy to just add a few lines script that does not have any option (no need to care about whether we have to clean or not, we know we have to, no need to care about all the other stuffs, I found it too much overkill and complicated to explain about installation rather than just writing a script.
Btw, thank a lot for sharing this option.

Appreciate the detailed writeup! Looking forward to the server state auto switching section.

works like a charm :partying_face: :partying_face: :partying_face:

Would love to read about the auto switch of Jibri server

Nice tutorial. For me using small instance (t2.small) was sometimes crashing. You should include these steps in tutorial.

Full discussion.