Jibri setup and configuration - here’s how! FULL GUIDE

Hi all,
Jibri is the component that is used for recording, streaming and SIP video gateway.

I’ve spent a whole day trying to get the latest version of Jibri to work with a Jitsi meet instance. Even with some good guides out there I found it challenging as things changed in the latest version of Jibri. Eventually I had to combine knowledge from several guides so I decided to put forth all I found in one guide in the hopes it’ll help others figure out Jibri faster.
Same happened to me before with setting up region routing via OCTO which made write my previous guide (link in the first comment).

So… let’s get to it.
Writing this guide I’m assuming you already have a working instance of Jitsi that includes Jitsi meet, Jicofo, JVB.

In this guide we’ll create a separate server for Jibri and connect it to the Jitsi shard so we won’t infringe on one server’s resources.
With this topology (Jibri on a separate server) you can scale and add as many Jibri servers you need and scale your system up.

Before we begin
Please make sure your Jitsi meet instance has a SSL certificate from a SSL authority like ZeroSSL or Let’sencrypt. Self-signed certificate will not work.

Step 1 setting up servers and domain
Get your servers. Get a Debian 10 machine with 2GB of RAM at least. Through trial an error I tried using a 1 gig machine for recording and the service crashed after half a sec.

Get your domain A record for your Jibri server and point it to your server’s IP. You’ll need it to connect the Jitsi meet servers and Jibri.
In this example I’ll use “mydomain.com” as my domain.
The A record I set up for my Jibri server is “recording.mydomain.com”.

Step 2 installing Jibri and dependencies
First update your server

apt update -y
apt upgrade -y

Set your servers host name to match your domain’s A record.

hostnamectl set-hostname recording.mydomain.com

Configure your hosts file

nano /etc/hosts

Add your domain A record to your hosts file

127.0.1.1 recording.mydomain.com {your machine’s name}
127.0.0.1 localhost recording.mydomain.com

Get JAVA 8 (you have to get JAVA 8. Version 11 and probably higher will not work)
Make sure JAVA is not installed on your machine. Run

java -version

You should get

-bash: java: command not found

Install JAVA 8 and dependencies from AdoptOpenJDK Repo.

apt install wget gnupg software-properties-common -y

wget -qO - https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public | sudo apt-key add -

add-apt-repository --yes https://adoptopenjdk.jfrog.io/adoptopenjdk/deb

apt install adoptopenjdk-8-hotspot -y

Verify JAVA 8 is installed

java -version

You should get
> Openjdk version “1.8.0_242”
> OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_242-b08)
> OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.242-b08, mixed mode)

Now you’ll need to verify the path of your JAVA 8 using

update-alternatives --config java

You should get

There is only one alternative in link group java (providing /usr/bin/java): /usr/lib/jvm/adoptopenjdk-8-hotspot-amd64/bin/java
Nothing to configure.

Now we’ll need to set the JAVA Home Environment Variable by running

nano ~/.bash_profile

Paste this line into the file - (verify the path below is the same as the one shown in the output of the command update-alternatives --config java)

export JAVA_HOME=/usr/lib/jvm/adoptopenjdk-8-hotspot-amd64/bin/java

Save and exit the file. Now source the file.

source ~/.bash_profile

Run

echo $JAVA_HOME

You should get

/usr/lib/jvm/adoptopenjdk-8-hotspot-amd64/bin/java

Now we’ll install packages we’ll need to make changes to the kernel, in case you’re using a cloud provider like DigitalOcean. They install cloud kernel by default which we’ll need to remove.
Run

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

when prompt for Keyboard layout choose the one you use and press enter .

Once done, run the following command to see your installed kernels

apt list --installed | grep linux-image-

You should get something similar to this output with your machine’s kernel.

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

linux-image-4.19.0-10-cloud-amd64/now 4.19.132-1 amd64 [installed,local]
linux-image-4.19.0-13-amd64/stable,now 4.19.160-2 amd64 [installed,automatic]
linux-image-4.19.0-13-cloud-amd64/stable,now 4.19.160-2 amd64 [installed,automatic]
linux-image-amd64/stable,now 4.19+105+deb10u8 amd64 [installed]
linux-image-cloud-amd64/stable,now 4.19+105+deb10u8 amd64 [installed]

Remove all the cloud kernels (type in the version of your kernel as shown in previous output.

apt remove linux-image-cloud-amd64 linux-image-4.19.0-10-cloud-amd64 linux-image-4.19.0-13-cloud-amd64

When prompt choose Yes then (pay attention - the question is if to abort or not) choose No
Kernels have been removed, You can verify by running the following command again.

apt list --installed | grep linux-image-

Reboot system.

systemctl reboot

Configure Alsa and loopback device to start on boot

echo “snd_aloop” >> /etc/modules

modprobe snd_aloop

Verify the module is loaded

lsmod | grep snd_aloop

You should get

snd_aloop 28672 1
snd_pcm 114688 1 snd_aloop
snd 94208 5 snd_timer,snd_aloop,snd_pcm

Get Google Chrome on your server. This will allow Jibri to join your conference as an invisible user and record it.

curl -o - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add

echo deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main > /etc/apt/sources.list.d/google-chrome.list

apt update

apt install google-chrome-stable -y

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 chmod 0755 /usr/local/bin/chromedriver

Turn off warnings about scripted control in Chrome:

mkdir -p /etc/opt/chrome/policies/managed

echo ‘{ “CommandLineFlagSecurityWarningsEnabled”: false }’ >>/etc/opt/chrome/policies/managed/managed_policies.json

Install Jibri

wget -qO - https://download.jitsi.org/jitsi-key.gpg.key | sudo apt-key add -

sh -c “echo ‘deb https://download.jitsi.org stable/’ > /etc/apt/sources.list.d/jitsi-stable.list”

apt update
apt install jibri -y

Add Jibri’s user account to the necessary groups

usermod -aG adm,audio,video,plugdev jibri

That’s it, Jibri is all set. Now let’s connect the servers.

Step 3 connect the servers
On your Jicofo server we’ll need to make changes to the Prosody config file. We’ll add a MUC (Multi User Component) and the Jibri’s domain A record we created earlier.

cd into the folder

cd /etc/prosody/conf.avail/

Run

ls

and see what’s the name of your lua configuration file.

Open the configuration file

nano /etc/prosody/conf.avail/meet.mydomain.com.cfg.lua

Please note:

meet.mydomain.com → is your Jicofo server.
recording.mydomain.com → is your Jibri server.

You’ll get the config file with all Prosody’s configurations. Go to the end of that file and past the two parts one under the other.
(Please note the first line needs to be commented out using two dashes “–”)

– internal muc component, meant to enable pools of jibri and jigasi clients
Component “internal.auth.meet.mydomain.com” “muc”
modules_enabled = {
“ping”;
}
storage = “memory”
muc_room_cache_size = 1000

VirtualHost “recording.mydomain.com
modules_enabled = {
“ping”;
}
authentication = “internal_plain”

Save and exit. Go back into the file using

nano /etc/prosody/conf.avail/meet.mydomain.com.cfg.lua

Check if the quotation marks are shown properly and the values are in order. like “ping” at the bottom. If not mantually correct the file and save.

Reload Prosody

/etc/init.d/prosody reload

Create the necessary users for Jibri on Prosody. Make sure you write down the passwords you set for the users. Change the passwords below as you see fit.

prosodyctl register jibri auth.meet.mydomain.com {JibriPassword}
prosodyctl register recorder recording.mydomain.com {RecorderPassword}

Configuring Jicofo, open

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

Add the following lines

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

Reload Jicofo

/etc/init.d/jicofo reload

Configure Jitsi Meet, open

nano /etc/jitsi/meet/meet.mydomain.com-config.js

Search with Ctrl+w for the following options - uncomment and set to ‘true’

If you want to enable file recording
fileRecordingsEnabled: true,
If you want to enable live streaming
liveStreamingEnabled: true,

Add this line under one of the mentioned above options

hiddenDomain: ‘recording.mydomain.com’,

Save and exit the file.

Now let’s verify the options to record and stream are shown in the Jitsi menu.
For that open

nano /usr/share/jitsi-meet/interface_config.js

Under TOOLBAR_BUTTONS (run a search for it using Ctrl+w) locate ‘recording’ and ‘livestreaming’.
If they’re there you’re all set.

Configure your servers’ firewall to allow TCP 5222. Run

ufw allow 5222/tcp

And open the port on your external firewall as well.

Jibri’s configuration -
On your Jibri server we need to create the folder to store the recordings

mkdir /recordings
chown jibri:jitsi /recordings

Now configure Jibri’s configuration file, open

nano /etc/jitsi/jibri/config.json

You’ll see the file is empty - that’s because this type of config is considered legacy but Jibri still check for it and run it.

Paste this file content - make sure to change the passwords below with the passwords we previously set for Prosody:

{
    "recording_directory":"/recordings",
    "finalize_recording_script_path": "/path/to/finalize_recording.sh",
    "xmpp_environments": [
        {
            "name": "prod environment",
            "xmpp_server_hosts": [
                "meet.mydomain.com"
            ],
            "xmpp_domain": "meet.mydomain.com",
            "control_login": {
                // The domain to use for logging in
                "domain": "auth.meet.mydomain.com",
                // The credentials for logging in
                "username": "jibri",
                "password": "{JibrisPassword}"
            },
            "control_muc": {
                "domain": "internal.auth.meet.mydomain.com",
                "room_name": "JibriBrewery",
                "nickname": "jibri-nickname"
            },
            "call_login": {
                "domain": "recording.mydomain.com",
                "username": "recorder",
                "password": "{RecordersPassword}"
            },
            "room_jid_domain_string_to_strip_from_start": "conference.",
            "usage_timeout": "0"
        }
    ]
}

Restart Jibri

service jibri restart

Check Jibri connected to your instance of Jitsi.

nano /var/log/jitsi/jibri/log.0.txt

Look for the line
2021-01-13 17:09:23.002 INFO: [25] org.jitsi.xmpp.mucclient.MucClient.log() Joined MUC: jibribrewery@internal.auth.meet.mydomain.com

Success!

If not:

  1. Circle back make sure all the characters saved properly.
  2. Verify no firewalls blocking your way.
  3. Restart all servers

service prosody restart
service jicofo resraet
service jibri restart

I wrote this guide then followed it myself. The only issue I noticed is weird characters when copying from the forum. Always verify your files changes.

That’s it - and very exciting. Open a Jitsi conference and click on start recording on the menu. Recordings will be saved in the recording folder we created before.

1 Like

My OCTO FULL GUIDE for regional scaling

No, no, noooooo. This is not advisable. Config.json is being deprecated - Support for Jibri legacy config file (config.json) going away soon-ish - #4 by bbaldino Everybody should be moving to Jbri.conf - ESPECIALLY for those installing Jibri for the first time. And it’s actually untrue that you’ll see a config.json file after a new installation now; you don’t, you see a jibri.conf instead.

I appreciate the thoughts and time you put into this, but it’s just not current.

2 Likes

Thanks @Freddie
So the content of config.json should be in jibri.conf?

As is, jibri.conf is empty

You’re welcome, buddy.

Kind of, but not exactly. The values will be the same, but the field names are different (and this is very important to note because it’s the cause of problems for many people moving from the old Jibri). Jibri.conf will be empty with a new installation and you have to populate the file. Not trying to self-promote, but check out this post on how to configure the new Jibri - TUTORIAL - How to Install the NEW JIBRI

UPDATE:
Thanks to @Freddie for pointing out the configuration of the new Jibri.conf. You can find it in /etc/jitsi/jibri

I’m using a deployment from July so this guide works well and to this date works well also with today’s latest versions but for future developments Use this configuration file

Jibri.conf

jibri {
// A unique identifier for this Jibri
// TODO: eventually this will be required with no default
id = “”
// Whether or not Jibri should return to idle state after handling
// (successfully or unsuccessfully) a request. A value of ‘true’
// here means that a Jibri will NOT return back to the IDLE state
// and will need to be restarted in order to be used again.
single-use-mode = false
api {
http {
external-api-port = 2222
internal-api-port = 3333
}
xmpp {
// See example_xmpp_envs.conf for an example of what is expected here
environments = [
{
name = “prod environment”
xmpp-server-hosts = [“your.domain.com”]
xmpp-domain = “your.domain.com

            control-muc {
                domain = "internal.auth.your.domain.com"
                room-name = "JibriBrewery"
                nickname = "jibri-nickname"
            }

            control-login {
                domain = "auth.your.domain.com"
                username = "jibri"
                password = "JPwd"
            }

            call-login {
                domain = "recorder.your.domain.com"
                username = "recorder"
                password = "RPwd"
           }

           strip-from-room-domain = "conference."
            usage-timeout = 0
            trust-all-xmpp-certs = true
        }]
}

}
recording {
recordings-directory = “/srv/recordings”
# TODO: make this an optional param and remove the default
finalize-script = “/path/to/finalize_recording.sh”
}
streaming {
// A list of regex patterns for allowed RTMP URLs. The RTMP URL used
// when starting a stream must match at least one of the patterns in
// this list.
rtmp-allow-list = [
// By default, all services are allowed
“.*”
]
}
chrome {
// The flags which will be passed to chromium when launching
flags = [
“–use-fake-ui-for-media-stream”,
“–start-maximized”,
“–kiosk”,
“–enabled”,
“–disable-infobars”,
“–autoplay-policy=no-user-gesture-required”
]
}
stats {
enable-stats-d = true
}
webhook {
// A list of subscribers interested in receiving webhook events
subscribers =
}
jwt-info {
// The path to a .pem file which will be used to sign JWT tokens used in webhook
// requests. If not set, no JWT will be added to webhook requests.
# signing-key-path = “/path/to/key.pem”

// The kid to use as part of the JWT
# kid = "key-id"

// The issuer of the JWT
# issuer = "issuer"

// The audience of the JWT
# audience = "audience"

// The TTL of each generated JWT.  Can't be less than 10 minutes.
# ttl = 1 hour

}
call-status-checks {
// If all clients have their audio and video muted and if Jibri does not
// detect any data stream (audio or video) comming in, it will stop
// recording after NO_MEDIA_TIMEOUT expires.
no-media-timeout = 30 seconds

// If all clients have their audio and video muted, Jibri consideres this
// as an empty call and stops the recording after ALL_MUTED_TIMEOUT expires.
all-muted-timeout = 10 minutes

// When detecting if a call is empty, Jibri takes into consideration for how
// long the call has been empty already. If it has been empty for more than
// DEFAULT_CALL_EMPTY_TIMEOUT, it will consider it empty and stop the recording.
default-call-empty-timeout = 30 seconds

}
}