[Setup / Guide] Jitsi Meet Native + Multiple (6) Jibri Docker instances working on the same AWS server

This is a tutorial and a record of how I set up a Jitsi Meet server and 6 dockerized Jibri instances on an AWS Ubuntu server. (c5.4xlarge)

This means that the Jitsi Meet, Prosody, Jicofo and 6 jibri recorders are working on the same server. It took me a whole week to get this up and running so this document is also for my own reference! I referred many documents and forums, and this is where I decided to compile everything.

For security reasons, I will use the domain as my.domain.com and the IP address as my-elastic-ip

Preface

If the below steps seem daunting, I provide Jitsi setup consulting, so message me if you require any help setting up!




So here goes:

Jitsi Server Setup

  1. Get a domain. I have to stress how important this is. If you don’t have one, there are multiple places you can get one for free. Make it easy to write since you’ll be writing this everywhere. A Jitsi setup hardly ever works without a proper domain.

  2. Get an AWS instance: Ubuntu, preferably c5.4xlarge. Setting up an EC2 instance is well documented.

  3. Use Route 53 to point your domain to your elastic IP address. All subdomains (*.my.domain.com) should also point to this elastic IP

  4. Once your server is set up, you need to open a few ports. Actually, more than a few. Please let me know if some ports are redundant! (Please ignore port 5033)

  5. Edit hostnamectl
    sudo hostnamectl set-hostname my.domain.com

  6. Edit /etc/hosts
    sudo nano /etc/hosts
    Add the following lines
    Line 1: 127.0.0.1 localhost my.domain.com
    Line 2: my-elastic-ip my.domain.com

  7. This should already be installed, but execute this command
    sudo apt install -y apt-transport-https

  8. Add Jitsi to repo echo 'deb https://download.jitsi.org stable/' | sudo tee \ /etc/apt/sources.list.d/jitsi-stable.list

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

  10. sudo apt update

  11. Now Install Jitsi Meet
    sudo apt install -y jitsi-meet
    When asked for the domain, make sure you type this correctly. This domain is added to a plethora of files and if you get this step wrong, the easiest way would be to purge and start again.
    Create a self-signed certificate. Use Let’s Encrpyt later. If you know what you’re doing, use your own SSL cert.

  12. Generate a lets encrypt cert.
    sudo /usr/share/jitsi-meet/scripts/install-letsencrypt-cert.sh
    You will be asked for an email address, and if your domain works correctly, et voila! you have HTTPS!

  13. Test if Jitsi Meet works correctly. Go to https://my.domain.com and if you see Jitsi, you’re almost done with this stage of the setup.

Prosody, Jicofo and Auth setup

Basically, to see the screen where “I am the host”, and login, you need to do the following.

  1. Most of these commands need root, so
    sudo su

  2. cd /etc/prosody/conf.avail/

  3. nano my.domain.com.cfg.lua

  4. In the VirtualHost section for your domain, change the authentication method from anonymous to internal_plain

VirtualHost "my.domain.com"
...
authentication = "internal_plain"
...

  1. Above the existing VirtualHost section for your site, insert a new VirtualHost section. The name of this VirtualHost is guest. my.domain . For example, insert the following lines to create a new guest VirtualHost for the site my.domain.com.

VirtualHost "guest.my.domain.com"
authentication = "anonymous"
c2s_require_encryption = false
modules_enabled = {
"bosh";
"pubsub";
"ping";
"speakerstats";
"turncredentials";
"conference_duration";
}`

Save the file.

  1. Jicofo (Jitsi Conference Focus) is a component of Jitsi Meet that manages user sessions.
    While you’re still root,
    nano /etc/jitsi/jicofo/sip-communicator.properties

  2. Add a new line here

org.jitsi.jicofo.auth.URL=XMPP:my.domain.com

Save and exit.

  1. Edit Prosody for Jibri
    nano /etc/prosody/conf.d/my.domain.com.cfg.lua
    Update the internal muc component as:
file content
-- internal muc component

Component "internal.auth.MY.DOMAIN.COM" "muc"

storage = "memory"

modules_enabled = {

      "ping";

    }

    admins = { "focus@auth.MY.DOMAIN.COM", "jvb@auth.MY.DOMAIN.COM", "jibri@auth.MY.DOMAIN.COM" }

    muc_room_locking = false

    muc_room_default_public_jids = true

    muc_room_cache_size = 1000

    c2s_require_encryption = false
  1. In the same file, add a recorder VirtualHost
file content
VirtualHost "recorder.MY.DOMAIN.COM"

    modules_enabled = {

        "ping";

    }

    authentication = "internal_plain"

    c2s_require_encryption = false

    allow_empty_token = true
  1. Create Jitsi admin users. These are basically moderators to the conference. If you’re signed in, you will see options like recording and kicking people out.
    sudo prosodyctl register christopherblackwell my.domain.com niceAndLongPassword123
    Repeat this command for any additional users you want to create.

  2. Add Jibri to SIP
    nano /etc/jitsi/jicofo/sip-communicator.properties
    Add the following content to this file

org.jitsi.jicofo.jibri.BREWERY=JibriBrewery@internal.auth.my.domain.com
org.jitsi.jicofo.jibri.PENDING_TIMEOUT=90

  1. Add Jibri User

prosodyctl register jibri auth.my.domain.com niceAndLongPassword123
prosodyctl register recorder recorder.my.domain.com niceAndLongPassword123

  1. Restart all services.
    sudo systemctl restart {prosody,jicofo,jitsi-videobridge2,nginx}

  2. Login to the Jitsi console and you will see everything up and running! If you can log in using the password and username you set above, you have setup prosody correctly.

Customise the UI

For your instance, you may want to change some logos and text. You can find it all here. I won't go too deep, but here goes
  1. Changing the watermark: Simply go to /usr/share/jitsi-meet/images/ and replace watermark.png with your own file called watermark.png. Using SFTP or FTP is outside the scope this document.
  2. Changing the background of the index page: In /usr/share/jitsi-meet/css/, replace all.css with your own version. Please keep in mind that the CSS is minified, so you may find it difficult to do any changes. From Woodworker_Life:

Original: background-image: linear-gradient(-90deg, #1251AE 0, #0074FF 50%, #1251AE 100%);
my.domain: background-image: linear-gradient(-90deg, #047500 0, #069E00 50%, #047500 100%);

  1. Changing the text:
    You will find this at /usr/share/jitsi-meet/libs/app.bundle.min.js
    Simply find and replace the text you want to change

  2. Changing the app name and a few other things Have a look at /usr/share/jitsi-meet/interface_config.js

Optimise the video quality

Again, thanks Woodworker_Life!

nano /etc/jitsi/meet/my.domain.com-config.js

Find the audio section and set

disableAudioLevels: true,

Find the video-section and insert:

startBitrate: 500,
resolution: 720,
constraints: {
video: {
aspectRatio: 16 / 9,
height: {
ideal: 720,
max: 720,
min: 240
}
}
},

Tweak these values according to your user base.

=================================================================

Setting up 6 dockerized Jibri instances

Phew. Okay if you've reached here, then let's finish this!

Each recorder requires a Jibri instance. Expect up to 1 GB of RAM required per Jibri instance.
You have been warned. If your server crashes, it means you need more horsepower.

Couple of things to keep in mind:

  1. AWS does not come with a Loopback interface. This means that you have to install these in the kernel yourself. Each Jibri recorder requires 2 of its own Loopback interfaces, so please read, and re-read everything I have done here. The limit for number of loopback interfaces is 32, so this means you can have 16 recorders at the most, at one server.
  2. If you got something wrong, from this point on, you can simply start over from here.
  3. You will be tweaking with the kernel, so I am not responsible for any loss of data.
  4. You SHOULD have completed steps 8 - 12 of the Jitsi setup. If you’ve jumped to here, go ahead and visit that.

Setting up the Loopback interfaces

I’m assuming you’re still root. If you’re not
sudo su

  1. apt -y install linux-image-extra-virtual

  2. nano /etc/default/grub

  3. Configure the 12 loopback interfaces for 6 recorders.
    echo "options snd-aloop enable=1,1,1,1,1,1,1,1,1,1,1,1 index=0,1,2,3,4,5,6,7,8,9,10,11" > /etc/modprobe.d/alsa-loopback.conf

  4. Load it on boot:
    echo "snd-aloop">>/etc/modules

  5. Load it into the existing Kernel
    modprobe snd-aloop

  6. See if it’s working
    lsmod | grep snd_aloop

Output should be:

snd_aloop 24576 0
snd_pcm 98304 1 snd_aloop
snd 81920 3 snd_timer,snd_aloop,snd_pcm

  1. Important Edit the following file:

nano /etc/default/grub

  1. Modify the value of GRUB_DEFAULT from “0” to “1>2”
    This is the most important step. You’re basically telling the AWS server to use a generic kernel instead of the one it’s currently using.

  2. Reboot your instance

reboot

  1. SSH back in to the server and execute

ls -alh /proc/asound

Your output should be similar to:

Output

dr-xr-xr-x 16 root root 0 Nov 24 13:54 .
dr-xr-xr-x 192 root root 0 Nov 24 13:54 …
dr-xr-xr-x 6 root root 0 Nov 24 13:55 card0
dr-xr-xr-x 6 root root 0 Nov 24 13:55 card1
dr-xr-xr-x 6 root root 0 Nov 24 13:55 card10
dr-xr-xr-x 6 root root 0 Nov 24 13:55 card11
dr-xr-xr-x 6 root root 0 Nov 24 13:55 card2
dr-xr-xr-x 6 root root 0 Nov 24 13:55 card3
dr-xr-xr-x 6 root root 0 Nov 24 13:55 card4
dr-xr-xr-x 6 root root 0 Nov 24 13:55 card5
dr-xr-xr-x 6 root root 0 Nov 24 13:55 card6
dr-xr-xr-x 6 root root 0 Nov 24 13:55 card7
dr-xr-xr-x 6 root root 0 Nov 24 13:55 card8
dr-xr-xr-x 6 root root 0 Nov 24 13:55 card9
-r–r--r-- 1 root root 0 Nov 24 13:55 cards
-r–r--r-- 1 root root 0 Nov 24 13:55 devices
lrwxrwxrwx 1 root root 5 Nov 24 13:55 Loopback → card0
lrwxrwxrwx 1 root root 5 Nov 24 13:55 Loopback_1 → card1
lrwxrwxrwx 1 root root 5 Nov 24 13:55 Loopback_2 → card2
lrwxrwxrwx 1 root root 5 Nov 24 13:55 Loopback_3 → card3
lrwxrwxrwx 1 root root 5 Nov 24 13:55 Loopback_4 → card4
lrwxrwxrwx 1 root root 5 Nov 24 13:55 Loopback_5 → card5
lrwxrwxrwx 1 root root 5 Nov 24 13:55 Loopback_6 → card6
lrwxrwxrwx 1 root root 5 Nov 24 13:55 Loopback_7 → card7
lrwxrwxrwx 1 root root 5 Nov 24 13:55 Loopback_8 → card8
lrwxrwxrwx 1 root root 5 Nov 24 13:55 Loopback_9 → card9
lrwxrwxrwx 1 root root 6 Nov 24 13:55 Loopback_A → card10
lrwxrwxrwx 1 root root 6 Nov 24 13:55 Loopback_B → card11
-r–r--r-- 1 root root 0 Nov 24 13:55 modules

If this output looks good, proceed to docker.

Installing Docker

A few APT commands

  1. sudo apt-get install curl apt-transport-https ca-certificates software-properties-common

  2. curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

  3. sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

  4. sudo apt update

  5. apt-cache policy docker-ce
    Check the output:

Output

docker-ce:
Installed: (none)
Candidate: 5:19.03.13~3-0~ubuntu-bionic
Version table:
5:19.03.13~3-0~ubuntu-bionic 500
500 https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages

  1. sudo apt install docker-ce
  2. sudo systemctl status docker
  3. sudo apt install docker-compose

Setting up Docker Jibri

Now that you have docker installed, we need to pull jibri, make 6 instances and connect them to the loopback interfaces.

First, go root:

  1. sudo su

  2. docker pull jitsi/jibri

  3. Copy the whole following command in one go

cd &&
mkdir jibri-docker &&
cd jibri-docker &&
touch .env &&
touch jibri.yml &&
mkdir config &&
cd config &&
touch .asoundrc1 &&
touch .asoundrc2 &&
touch .asoundrc3 &&
touch .asoundrc4 &&
touch .asoundrc5 &&
touch .asoundrc6 &&
cd …

  1. Important: you need to specify the env file that docker will use for Jibri
    nano /root/jibri-docker/.env

  2. Add the following content to this file:

.env file content
# JIBRI CONFIG
# Internal XMPP domain for authenticated services
XMPP_AUTH_DOMAIN=auth.MY.DOMAIN.COM

# XMPP domain for the internal MUC used for jibri, jigasi and jvb pools
XMPP_INTERNAL_MUC_DOMAIN=internal.auth.MY.DOMAIN.COM

# XMPP domain for the jibri recorder
XMPP_RECORDER_DOMAIN=recorder.MY.DOMAIN.COM

# Internal XMPP server
XMPP_SERVER=MY.DOMAIN.COM

# Internal XMPP domain
XMPP_DOMAIN=MY.DOMAIN.COM

# XMPP user for Jibri client connections
JIBRI_XMPP_USER=jibri

# XMPP password for Jibri client connections
JIBRI_XMPP_PASSWORD=YOUR_JIBRI_USER_PASSWORD

# MUC name for the Jibri pool
JIBRI_BREWERY_MUC=jibribrewery

# XMPP recorder user for Jibri client connections
JIBRI_RECORDER_USER=recorder

# XMPP recorder password for Jibri client connections
JIBRI_RECORDER_PASSWORD=YOUR_RECORDER_USER_PASSWORD

# Directory for recordings inside Jibri container
JIBRI_RECORDING_DIR=/config/recordings

# The finalizing script. Will run after recording is complete
JIBRI_FINALIZE_RECORDING_SCRIPT_PATH=/config/finalize.sh

 
# When jibri gets a request to start a service for a room, the room
# jid will look like: roomName@optional.prefixes.subdomain.xmpp_domain
# We'll build the url for the call by transforming that into:
# https://xmpp_domain/subdomain/roomName
# So if there are any prefixes in the jid (like jitsi meet, which
# has its participants join a muc at conference.xmpp_domain) then
# list that prefix here so it can be stripped out to generate
# the call url correctly

JIBRI_STRIP_DOMAIN_JID=conference

# Directory for logs inside Jibri container
JIBRI_LOGS_DIR=/config/logs

DISPLAY=:0=
  1. Create a docker-compose file for Jibri
    nano /root/jibri-docker/jibri.yml
jibri.yml file content
version: '3'

services:
    jibri1:
        image: jitsi/jibri
        restart: ${RESTART_POLICY}
        volumes:
            - ${CONFIG}/jibri1:/config:Z
            - /dev/shm:/dev/shm
            - /root/jibri-docker/config/.asoundrc1:/home/jibri/.asoundrc
            - /root/jibri-docker/recordings:/config/recordings
        cap_add:
            - SYS_ADMIN
            - NET_BIND_SERVICE
        devices:
            - /dev/snd:/dev/snd
        environment:
            - XMPP_AUTH_DOMAIN
            - XMPP_INTERNAL_MUC_DOMAIN
            - XMPP_RECORDER_DOMAIN
            - XMPP_SERVER
            - XMPP_DOMAIN
            - JIBRI_XMPP_USER
            - JIBRI_XMPP_PASSWORD
            - JIBRI_BREWERY_MUC
            - JIBRI_RECORDER_USER
            - JIBRI_RECORDER_PASSWORD
            - JIBRI_RECORDING_DIR
            - JIBRI_FINALIZE_RECORDING_SCRIPT_PATH
            - JIBRI_STRIP_DOMAIN_JID
            - JIBRI_LOGS_DIR
            - DISPLAY=:0
            - TZ
        depends_on:
            - jicofo
    jibri2:
        image: jitsi/jibri
        restart: ${RESTART_POLICY}
        volumes:
            - ${CONFIG}/jibri2:/config:Z
            - /dev/shm:/dev/shm
            - /root/jibri-docker/config/.asoundrc2:/home/jibri/.asoundrc
            - /root/jibri-docker/recordings:/config/recordings
        cap_add:
            - SYS_ADMIN
            - NET_BIND_SERVICE
        devices:
            - /dev/snd:/dev/snd
        environment:
            - XMPP_AUTH_DOMAIN
            - XMPP_INTERNAL_MUC_DOMAIN
            - XMPP_RECORDER_DOMAIN
            - XMPP_SERVER
            - XMPP_DOMAIN
            - JIBRI_XMPP_USER
            - JIBRI_XMPP_PASSWORD
            - JIBRI_BREWERY_MUC
            - JIBRI_RECORDER_USER
            - JIBRI_RECORDER_PASSWORD
            - JIBRI_RECORDING_DIR
            - JIBRI_FINALIZE_RECORDING_SCRIPT_PATH
            - JIBRI_STRIP_DOMAIN_JID
            - JIBRI_LOGS_DIR
            - DISPLAY=:0
            - TZ
    jibri3:
        image: jitsi/jibri
        restart: ${RESTART_POLICY}
        volumes:
            - ${CONFIG}/jibri3:/config:Z
            - /dev/shm:/dev/shm
            - /root/jibri-docker/config/.asoundrc3:/home/jibri/.asoundrc
            - /root/jibri-docker/recordings:/config/recordings
        cap_add:
            - SYS_ADMIN
            - NET_BIND_SERVICE
        devices:
            - /dev/snd:/dev/snd
        environment:
            - XMPP_AUTH_DOMAIN
            - XMPP_INTERNAL_MUC_DOMAIN
            - XMPP_RECORDER_DOMAIN
            - XMPP_SERVER
            - XMPP_DOMAIN
            - JIBRI_XMPP_USER
            - JIBRI_XMPP_PASSWORD
            - JIBRI_BREWERY_MUC
            - JIBRI_RECORDER_USER
            - JIBRI_RECORDER_PASSWORD
            - JIBRI_RECORDING_DIR
            - JIBRI_FINALIZE_RECORDING_SCRIPT_PATH
            - JIBRI_STRIP_DOMAIN_JID
            - JIBRI_LOGS_DIR
            - DISPLAY=:0
            - TZ
    jibri4:
        image: jitsi/jibri
        restart: ${RESTART_POLICY}
        volumes:
            - ${CONFIG}/jibri4:/config:Z
            - /dev/shm:/dev/shm
            - /root/jibri-docker/config/.asoundrc4:/home/jibri/.asoundrc
            - /root/jibri-docker/recordings:/config/recordings
        cap_add:
            - SYS_ADMIN
            - NET_BIND_SERVICE
        devices:
            - /dev/snd:/dev/snd
        environment:
            - XMPP_AUTH_DOMAIN
            - XMPP_INTERNAL_MUC_DOMAIN
            - XMPP_RECORDER_DOMAIN
            - XMPP_SERVER
            - XMPP_DOMAIN
            - JIBRI_XMPP_USER
            - JIBRI_XMPP_PASSWORD
            - JIBRI_BREWERY_MUC
            - JIBRI_RECORDER_USER
            - JIBRI_RECORDER_PASSWORD
            - JIBRI_RECORDING_DIR
            - JIBRI_FINALIZE_RECORDING_SCRIPT_PATH
            - JIBRI_STRIP_DOMAIN_JID
            - JIBRI_LOGS_DIR
            - DISPLAY=:0
            - TZ
    jibri5:
        image: jitsi/jibri
        restart: ${RESTART_POLICY}
        volumes:
            - ${CONFIG}/jibri5:/config:Z
            - /dev/shm:/dev/shm
            - /root/jibri-docker/config/.asoundrc5:/home/jibri/.asoundrc
            - /root/jibri-docker/recordings:/config/recordings
        cap_add:
            - SYS_ADMIN
            - NET_BIND_SERVICE
        devices:
            - /dev/snd:/dev/snd
        environment:
            - XMPP_AUTH_DOMAIN
            - XMPP_INTERNAL_MUC_DOMAIN
            - XMPP_RECORDER_DOMAIN
            - XMPP_SERVER
            - XMPP_DOMAIN
            - JIBRI_XMPP_USER
            - JIBRI_XMPP_PASSWORD
            - JIBRI_BREWERY_MUC
            - JIBRI_RECORDER_USER
            - JIBRI_RECORDER_PASSWORD
            - JIBRI_RECORDING_DIR
            - JIBRI_FINALIZE_RECORDING_SCRIPT_PATH
            - JIBRI_STRIP_DOMAIN_JID
            - JIBRI_LOGS_DIR
            - DISPLAY=:0
            - TZ
        depends_on:
            - jicofo
    jibri6:
        image: jitsi/jibri
        restart: ${RESTART_POLICY}
        volumes:
            - ${CONFIG}/jibri6:/config:Z
            - /dev/shm:/dev/shm
            - /root/jibri-docker/config/.asoundrc6:/home/jibri/.asoundrc
            - /root/jibri-docker/recordings:/config/recordings
        cap_add:
            - SYS_ADMIN
            - NET_BIND_SERVICE
        devices:
            - /dev/snd:/dev/snd
        environment:
            - XMPP_AUTH_DOMAIN
            - XMPP_INTERNAL_MUC_DOMAIN
            - XMPP_RECORDER_DOMAIN
            - XMPP_SERVER
            - XMPP_DOMAIN
            - JIBRI_XMPP_USER
            - JIBRI_XMPP_PASSWORD
            - JIBRI_BREWERY_MUC
            - JIBRI_RECORDER_USER
            - JIBRI_RECORDER_PASSWORD
            - JIBRI_RECORDING_DIR
            - JIBRI_FINALIZE_RECORDING_SCRIPT_PATH
            - JIBRI_STRIP_DOMAIN_JID
            - JIBRI_LOGS_DIR
            - DISPLAY=:0
            - TZ
  1. Important Step
    Add the contents of the following files
    nano /root/jibri-docker/config/.asoundrc1
    nano /root/jibri-docker/config/.asoundrc2
    nano /root/jibri-docker/config/.asoundrc3
    nano /root/jibri-docker/config/.asoundrc4
    nano /root/jibri-docker/config/.asoundrc5
    nano /root/jibri-docker/config/.asoundrc6
.asoundrc1 file content
pcm.amix {
  type dmix
  ipc_key 219345
  slave.pcm "hw:Loopback,0,0"
}

pcm.asnoop {
  type dsnoop
  ipc_key 219346
  slave.pcm "hw:Loopback_1,1,0"
}
pcm.aduplex {
  type asym
  playback.pcm "amix"
  capture.pcm "asnoop"
}

pcm.bmix {
  type dmix
  ipc_key 219347
  slave.pcm "hw:Loopback_1,0,0"
}

pcm.bsnoop {
  type dsnoop
  ipc_key 219348
  slave.pcm "hw:Loopback,1,0"
}

pcm.bduplex {
  type asym
  playback.pcm "bmix"
  capture.pcm "bsnoop"
}

pcm.pjsua {
  type plug
  slave.pcm "bduplex"
}

pcm.!default {
  type plug
  slave.pcm "aduplex"
}
.asoundrc2 file content
pcm.amix {
  type dmix
  ipc_key 219345
  slave.pcm "hw:Loopback_2,0,0"
}
pcm.asnoop {
  type dsnoop
  ipc_key 219346
  slave.pcm "hw:Loopback_3,1,0"
}
pcm.aduplex {
  type asym
  playback.pcm "amix"
  capture.pcm "asnoop"
}
pcm.bmix {
  type dmix
  ipc_key 219347
  slave.pcm "hw:Loopback_3,0,0"
}
pcm.bsnoop {
  type dsnoop
  ipc_key 219348
  slave.pcm "hw:Loopback_2,1,0"
}
pcm.bduplex {
  type asym
  playback.pcm "bmix"
  capture.pcm "bsnoop"
}

pcm.pjsua {
  type plug
  slave.pcm "bduplex"
}

pcm.!default {
  type plug
  slave.pcm "aduplex"
}
.asoundrc3 file content
pcm.amix {
  type dmix
  ipc_key 219345
  slave.pcm "hw:Loopback_4,0,0"
}
pcm.asnoop {
  type dsnoop
  ipc_key 219346
  slave.pcm "hw:Loopback_5,1,0"
}
pcm.aduplex {
  type asym
  playback.pcm "amix"
  capture.pcm "asnoop"
}
pcm.bmix {
  type dmix
  ipc_key 219347
  slave.pcm "hw:Loopback_5,0,0"
}
pcm.bsnoop {
  type dsnoop
  ipc_key 219348
  slave.pcm "hw:Loopback_4,1,0"
}
pcm.bduplex {
  type asym
  playback.pcm "bmix"
  capture.pcm "bsnoop"
}

pcm.pjsua {
  type plug
  slave.pcm "bduplex"
}

pcm.!default {
  type plug
  slave.pcm "aduplex"
}
.asoundrc4 file content
pcm.amix {
  type dmix
  ipc_key 219345
  slave.pcm "hw:Loopback_6,0,0"
}
pcm.asnoop {
  type dsnoop
  ipc_key 219346
  slave.pcm "hw:Loopback_7,1,0"
}
pcm.aduplex {
  type asym
  playback.pcm "amix"
  capture.pcm "asnoop"
}
pcm.bmix {
  type dmix
  ipc_key 219347
  slave.pcm "hw:Loopback_7,0,0"
}
pcm.bsnoop {
  type dsnoop
  ipc_key 219348
  slave.pcm "hw:Loopback_6,1,0"
}
pcm.bduplex {
  type asym
  playback.pcm "bmix"
  capture.pcm "bsnoop"
}

pcm.pjsua {
  type plug
  slave.pcm "bduplex"
}

pcm.!default {
  type plug
  slave.pcm "aduplex"
}
.asoundrc5 file content
pcm.amix {
  type dmix
  ipc_key 219345
  slave.pcm "hw:Loopback_8,0,0"
}
pcm.asnoop {
  type dsnoop
  ipc_key 219346
  slave.pcm "hw:Loopback_9,1,0"
}
pcm.aduplex {
  type asym
  playback.pcm "amix"
  capture.pcm "asnoop"
}
pcm.bmix {
  type dmix
  ipc_key 219347
  slave.pcm "hw:Loopback_9,0,0"
}
pcm.bsnoop {
  type dsnoop
  ipc_key 219348
  slave.pcm "hw:Loopback_8,1,0"
}
pcm.bduplex {
  type asym
  playback.pcm "bmix"
  capture.pcm "bsnoop"
}

pcm.pjsua {
  type plug
  slave.pcm "bduplex"
}

pcm.!default {
  type plug
  slave.pcm "aduplex"
}
.asoundrc6 file content
pcm.amix {
  type dmix
  ipc_key 219345
  slave.pcm "hw:Loopback_A,0,0"
}

pcm.asnoop {
  type dsnoop
  ipc_key 219346
  slave.pcm "hw:Loopback_B,1,0"
}
pcm.aduplex {
  type asym
  playback.pcm "amix"
  capture.pcm "asnoop"
}

pcm.bmix {
  type dmix
  ipc_key 219347
  slave.pcm "hw:Loopback_B,0,0"
}

pcm.bsnoop {
  type dsnoop
  ipc_key 219348
  slave.pcm "hw:Loopback_A,1,0"
}

pcm.bduplex {
  type asym
  playback.pcm "bmix"
  capture.pcm "bsnoop"
}

pcm.pjsua {
  type plug
  slave.pcm "bduplex"
}

pcm.!default {
  type plug
  slave.pcm "aduplex"
}
  1. Finally, up the docker containers:
    cd /root/jibri-docker
    docker-compose -f jibri.yml up -d

  2. Check if running docker ps

  3. Check logs of the first container
    docker logs jibri-docker_jibri1_1 (This may differ based on your container)

  4. If you want to restart docker on reboot, execute
    docker update –restart unless-stopped CONTAINER ID

  5. You’re ready to roll!!

Thank you for reading this. I hope you've been able to set up correctly!

Maintainers please let me know if something is incorrect

I provide Jitsi setup consulting, so message me if you require some help setting up!

Credits and references

@Woodworker_Life This wouldn't have been possible without you
2 Likes

UPDATE

It seems that AWS automatically upgrades the kernel back to AWS from generic, every couple of days

This can potentially break your system.

Run

sudo apt-get remove unattended-upgrades

To disable this behaviour

Just a remark - removing unattended-upgrades only to stop kernel upgrades is not the best thing to do. For example there could be security upgrades that you would like to keep, especially on systems where you rarely enter to check and do the upgrades.

You can just blacklist the kernels instead - in /etc/apt/apt.conf.d/50unattended-upgrades locate and edit/add the following:

Unattended-Upgrade::Package-Blacklist {
“linux-”;

This will stop all packages named “linux-*” from being auto upgraded. This includes linux and linux headers. You can be more specific with “linux-image-” to blacklist only linux.

1 Like

Hi, I followed the exact same procedure and seems live the recording feature is not working. Here is the logs

2021-07-17 11:55:27.964 INFO: [52] org.jitsi.jibri.selenium.JibriSelenium.log() Transitioning from state Starting up to Error: FailedToJoinCall SESSION Failed to join the call 2021-07-17 11:55:27.965 INFO: [52] org.jitsi.jibri.service.impl.FileRecordingJibriService.log() File recording service transitioning from state Starting up to Error: FailedToJoinCall SESSION Failed to join the call 2021-07-17 11:55:27.965 INFO: [52] org.jitsi.jibri.api.xmpp.XmppApi.log() Current service had an error Error: FailedToJoinCall SESSION Failed to join the call, sending error iq <iq to='jibribrewery@internal.auth.sessions.aureal.one/focus' id='EqqTw-38' type='set'><jibri xmlns='http://jitsi.org/protocol/jibri' status='off' failure_reason='error' should_retry='true'/></iq> 2021-07-17 11:55:27.966 FINE: [52] org.jitsi.jibri.statsd.JibriStatsDClient.log() Incrementing statsd counter: stop:recording 2021-07-17 11:55:27.966 INFO: [52] org.jitsi.jibri.JibriManager.log() Stopping the current service 2021-07-17 11:55:27.966 INFO: [52] org.jitsi.jibri.service.impl.FileRecordingJibriService.log() Stopping capturer 2021-07-17 11:55:27.966 INFO: [52] org.jitsi.jibri.util.JibriSubprocess.log() Stopping ffmpeg process 2021-07-17 11:55:27.967 INFO: [52] org.jitsi.jibri.util.JibriSubprocess.log() ffmpeg exited with value null 2021-07-17 11:55:27.967 INFO: [52] org.jitsi.jibri.service.impl.FileRecordingJibriService.log() Quitting selenium 2021-07-17 11:55:27.975 INFO: [52] org.jitsi.jibri.service.impl.FileRecordingJibriService.log() Participants in this recording: [] 2021-07-17 11:55:28.000 INFO: [52] org.jitsi.jibri.selenium.JibriSelenium.log() Leaving call and quitting browser 2021-07-17 11:55:28.000 INFO: [52] org.jitsi.jibri.selenium.JibriSelenium.log() Recurring call status checks cancelled 2021-07-17 11:55:28.009 INFO: [52] org.jitsi.jibri.selenium.JibriSelenium.log() Got 0 log entries for type browser 2021-07-17 11:55:28.018 INFO: [52] org.jitsi.jibri.selenium.JibriSelenium.log() Got 81 log entries for type driver 2021-07-17 11:55:28.028 INFO: [52] org.jitsi.jibri.selenium.JibriSelenium.log() Got 0 log entries for type client 2021-07-17 11:55:28.029 INFO: [52] org.jitsi.jibri.selenium.JibriSelenium.log() Leaving web call 2021-07-17 11:55:28.046 INFO: [52] org.jitsi.jibri.selenium.JibriSelenium.log() Quitting chrome driver 2021-07-17 11:55:28.113 INFO: [52] org.jitsi.jibri.selenium.JibriSelenium.log() Chrome driver quit 2021-07-17 11:55:28.113 INFO: [52] org.jitsi.jibri.service.impl.FileRecordingJibriService.log() Finalizing the recording 2021-07-17 11:55:28.115 SEVERE: [52] org.jitsi.jibri.service.impl.FileRecordingJibriService.log() Failed to run finalize script java.io.IOException: Cannot run program "/config/finalize.sh": error=2, No such file or directory at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048) at org.jitsi.jibri.util.ProcessWrapper.start(ProcessWrapper.kt:88) at org.jitsi.jibri.service.impl.FileRecordingJibriService.finalize(FileRecordingJibriService.kt:220) at org.jitsi.jibri.service.impl.FileRecordingJibriService.stop(FileRecordingJibriService.kt:205) at org.jitsi.jibri.JibriManager.stopService(JibriManager.kt:263) at org.jitsi.jibri.JibriManager$startService$1.invoke(JibriManager.kt:211) at org.jitsi.jibri.JibriManager$startService$1.invoke(JibriManager.kt:85) at org.jitsi.jibri.util.StatusPublisher$addStatusHandler$1.invoke(StatusPublisher.kt:37) at org.jitsi.jibri.util.StatusPublisher$addStatusHandler$1.invoke(StatusPublisher.kt:29) at org.jitsi.jibri.util.StatusPublisher$publishStatus$1.invoke(StatusPublisher.kt:53) at org.jitsi.jibri.util.StatusPublisher$publishStatus$1.invoke(StatusPublisher.kt:29) at kotlin.collections.CollectionsKt__MutableCollectionsKt.filterInPlace$CollectionsKt__MutableCollectionsKt(MutableCollections.kt:285) at kotlin.collections.CollectionsKt__MutableCollectionsKt.retainAll(MutableCollections.kt:276) at org.jitsi.jibri.util.StatusPublisher.publishStatus(StatusPublisher.kt:53) at org.jitsi.jibri.service.impl.StatefulJibriService.onServiceStateChange(StatefulJibriService.kt:40) at org.jitsi.jibri.service.impl.StatefulJibriService.access$onServiceStateChange(StatefulJibriService.kt:26) at org.jitsi.jibri.service.impl.StatefulJibriService$1.invoke(StatefulJibriService.kt:35) at org.jitsi.jibri.service.impl.StatefulJibriService$1.invoke(StatefulJibriService.kt:26) at org.jitsi.jibri.util.NotifyingStateMachine.notify(NotifyingStateMachine.kt:26) at org.jitsi.jibri.service.JibriServiceStateMachine.access$notify(JibriServiceStateMachine.kt:46) at org.jitsi.jibri.service.JibriServiceStateMachine$stateMachine$1$5.invoke(JibriServiceStateMachine.kt:100) at org.jitsi.jibri.service.JibriServiceStateMachine$stateMachine$1$5.invoke(JibriServiceStateMachine.kt:46) at com.tinder.StateMachine.notifyOnTransition(StateMachine.kt:65) at com.tinder.StateMachine.transition(StateMachine.kt:23) at org.jitsi.jibri.service.JibriServiceStateMachine.transition(JibriServiceStateMachine.kt:112) at org.jitsi.jibri.service.impl.StatefulJibriService$registerSubComponent$1.invoke(StatefulJibriService.kt:46) at org.jitsi.jibri.service.impl.StatefulJibriService$registerSubComponent$1.invoke(StatefulJibriService.kt:26) at org.jitsi.jibri.util.StatusPublisher$addStatusHandler$1.invoke(StatusPublisher.kt:37) at org.jitsi.jibri.util.StatusPublisher$addStatusHandler$1.invoke(StatusPublisher.kt:29) at org.jitsi.jibri.util.StatusPublisher$publishStatus$1.invoke(StatusPublisher.kt:53) at org.jitsi.jibri.util.StatusPublisher$publishStatus$1.invoke(StatusPublisher.kt:29) at kotlin.collections.CollectionsKt__MutableCollectionsKt.filterInPlace$CollectionsKt__MutableCollectionsKt(MutableCollections.kt:285) at kotlin.collections.CollectionsKt__MutableCollectionsKt.retainAll(MutableCollections.kt:276) at org.jitsi.jibri.util.StatusPublisher.publishStatus(StatusPublisher.kt:53) at org.jitsi.jibri.selenium.JibriSelenium.onSeleniumStateChange(JibriSelenium.kt:208) at org.jitsi.jibri.selenium.JibriSelenium.access$onSeleniumStateChange(JibriSelenium.kt:158) at org.jitsi.jibri.selenium.JibriSelenium$1.invoke(JibriSelenium.kt:193) at org.jitsi.jibri.selenium.JibriSelenium$1.invoke(JibriSelenium.kt:158) at org.jitsi.jibri.util.NotifyingStateMachine.notify(NotifyingStateMachine.kt:26) at org.jitsi.jibri.selenium.SeleniumStateMachine.access$notify(SeleniumStateMachine.kt:33) at org.jitsi.jibri.selenium.SeleniumStateMachine$stateMachine$1$5.invoke(SeleniumStateMachine.kt:78) at org.jitsi.jibri.selenium.SeleniumStateMachine$stateMachine$1$5.invoke(SeleniumStateMachine.kt:33) at com.tinder.StateMachine.notifyOnTransition(StateMachine.kt:65) at com.tinder.StateMachine.transition(StateMachine.kt:23) at org.jitsi.jibri.selenium.SeleniumStateMachine.transition(SeleniumStateMachine.kt:83) at org.jitsi.jibri.selenium.JibriSelenium$joinCall$1.run(JibriSelenium.kt:311) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.io.IOException: error=2, No such file or directory at java.lang.UNIXProcess.forkAndExec(Native Method) at java.lang.UNIXProcess.<init>(UNIXProcess.java:247) at java.lang.ProcessImpl.start(ProcessImpl.java:134) at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029) ... 50 more 2021-07-17 11:55:28.115 FINE: [52] org.jitsi.jibri.config.log() FallbackSupplier: checking for value via suppliers: LambdaSupplier: 'JibriConfig::singleUseMode' ConfigSourceSupplier: key: 'jibri.single-use-mode', type: 'kotlin.Boolean', source: 'config' 2021-07-17 11:55:28.116 FINE: [52] org.jitsi.jibri.config.log() LambdaSupplier: Trying to retrieve value via JibriConfig::singleUseMode 2021-07-17 11:55:28.116 FINE: [52] org.jitsi.jibri.config.log() FallbackSupplier: failed to find value via LambdaSupplier: 'JibriConfig::singleUseMode': org.jitsi.metaconfig.ConfigException$UnableToRetrieve$Error: class java.lang.NullPointerException 2021-07-17 11:55:28.116 FINE: [52] org.jitsi.jibri.config.log() ConfigSourceSupplier: Trying to retrieve key 'jibri.single-use-mode' from source 'config' as type kotlin.Boolean 2021-07-17 11:55:28.117 FINE: [52] org.jitsi.jibri.config.log() ConfigSourceSupplier: Successfully retrieved key 'jibri.single-use-mode' from source 'config' as type kotlin.Boolean 2021-07-17 11:55:28.117 FINE: [52] org.jitsi.jibri.config.log() FallbackSupplier: value found via ConfigSourceSupplier: key: 'jibri.single-use-mode', type: 'kotlin.Boolean', source: 'config' 2021-07-17 11:55:28.117 INFO: [52] org.jitsi.jibri.status.JibriStatusManager.log() Busy status has changed: BUSY -> IDLE 2021-07-17 11:55:28.117 FINE: [52] org.jitsi.jibri.webhooks.v1.WebhookClient.log() Updating 0 subscribers of status 2021-07-17 11:55:28.118 INFO: [52] org.jitsi.jibri.api.xmpp.XmppApi.log() Jibri reports its status is now JibriStatus(busyStatus=IDLE, health=OverallHealth(healthStatus=HEALTHY, details={})), publishing presence to connections 2021-07-17 11:55:28.118 FINE: [52] org.jitsi.xmpp.mucclient.MucClientManager.log() Setting a presence extension: org.jitsi.xmpp.extensions.jibri.JibriStatusPacketExt@2b0a55c5

Hi @Dhawal_Patel,

You are right, I missed one little detail in the jibri.yml file content…

I also forgot to add finalize.sh

Thank you for pointing that out. I can’t seem to edit the original post so here it is:

jibri.yml file content
version: '3'

services:
    jibri1:
        image: jitsi/jibri
        restart: ${RESTART_POLICY}
        volumes:
            - ${CONFIG}/jibri1:/config:Z
            - /dev/shm:/dev/shm
            - /root/jibri-docker/config/.asoundrc1:/home/jibri/.asoundrc
            - /root/jibri-docker/recordings/recorder1:/config/recordings
            - /root/jibri-docker/config/finalize.sh:/config/finalize.sh
            - /home/ubuntu:/home/jibri
        cap_add:
            - SYS_ADMIN
            - NET_BIND_SERVICE
        devices:
            - /dev/snd:/dev/snd
        environment:
            - XMPP_AUTH_DOMAIN
            - XMPP_INTERNAL_MUC_DOMAIN
            - XMPP_RECORDER_DOMAIN
            - XMPP_SERVER
            - XMPP_DOMAIN
            - JIBRI_XMPP_USER
            - JIBRI_XMPP_PASSWORD
            - JIBRI_BREWERY_MUC
            - JIBRI_RECORDER_USER
            - JIBRI_RECORDER_PASSWORD
            - JIBRI_RECORDING_DIR
            - JIBRI_FINALIZE_RECORDING_SCRIPT_PATH
            - JIBRI_STRIP_DOMAIN_JID
            - JIBRI_LOGS_DIR
            - DISPLAY=:0
            - TZ

    jibri2:
        image: jitsi/jibri
        restart: ${RESTART_POLICY}
        volumes:
            - ${CONFIG}/jibri2:/config:Z
            - /dev/shm:/dev/shm
            - /root/jibri-docker/config/.asoundrc2:/home/jibri/.asoundrc
            - /root/jibri-docker/recordings/recorder2:/config/recordings
            - /root/jibri-docker/config/finalize.sh:/config/finalize.sh
            - /home/ubuntu:/home/jibri
        cap_add:
            - SYS_ADMIN
            - NET_BIND_SERVICE
        devices:
            - /dev/snd:/dev/snd
        environment:
            - XMPP_AUTH_DOMAIN
            - XMPP_INTERNAL_MUC_DOMAIN
            - XMPP_RECORDER_DOMAIN
            - XMPP_SERVER
            - XMPP_DOMAIN
            - JIBRI_XMPP_USER
            - JIBRI_XMPP_PASSWORD
            - JIBRI_BREWERY_MUC
            - JIBRI_RECORDER_USER
            - JIBRI_RECORDER_PASSWORD
            - JIBRI_RECORDING_DIR
            - JIBRI_FINALIZE_RECORDING_SCRIPT_PATH
            - JIBRI_STRIP_DOMAIN_JID
            - JIBRI_LOGS_DIR
            - DISPLAY=:0
            - TZ
    jibri3:
        image: jitsi/jibri
        restart: ${RESTART_POLICY}
        volumes:
            - ${CONFIG}/jibri3:/config:Z
            - /dev/shm:/dev/shm
            - /root/jibri-docker/config/.asoundrc3:/home/jibri/.asoundrc
            - /root/jibri-docker/recordings/recorder3:/config/recordings
            - /root/jibri-docker/config/finalize.sh:/config/finalize.sh
            - /home/ubuntu:/home/jibri
        cap_add:
            - SYS_ADMIN
            - NET_BIND_SERVICE
        devices:
            - /dev/snd:/dev/snd
        environment:
            - XMPP_AUTH_DOMAIN
            - XMPP_INTERNAL_MUC_DOMAIN
            - XMPP_RECORDER_DOMAIN
            - XMPP_SERVER
            - XMPP_DOMAIN
            - JIBRI_XMPP_USER
            - JIBRI_XMPP_PASSWORD
            - JIBRI_BREWERY_MUC
            - JIBRI_RECORDER_USER
            - JIBRI_RECORDER_PASSWORD
            - JIBRI_RECORDING_DIR
            - JIBRI_FINALIZE_RECORDING_SCRIPT_PATH
            - JIBRI_STRIP_DOMAIN_JID
            - JIBRI_LOGS_DIR
            - DISPLAY=:0
            - TZ
    jibri4:
        image: jitsi/jibri
        restart: ${RESTART_POLICY}
        volumes:
            - ${CONFIG}/jibri4:/config:Z
            - /dev/shm:/dev/shm
            - /root/jibri-docker/config/.asoundrc4:/home/jibri/.asoundrc
            - /root/jibri-docker/recordings/recorder4:/config/recordings
            - /root/jibri-docker/config/finalize.sh:/config/finalize.sh
            - /home/ubuntu:/home/jibri
        cap_add:
            - SYS_ADMIN
            - NET_BIND_SERVICE
        devices:
            - /dev/snd:/dev/snd
        environment:
            - XMPP_AUTH_DOMAIN
            - XMPP_INTERNAL_MUC_DOMAIN
            - XMPP_RECORDER_DOMAIN
            - XMPP_SERVER
            - XMPP_DOMAIN
            - JIBRI_XMPP_USER
            - JIBRI_XMPP_PASSWORD
            - JIBRI_BREWERY_MUC
            - JIBRI_RECORDER_USER
            - JIBRI_RECORDER_PASSWORD
            - JIBRI_RECORDING_DIR
            - JIBRI_FINALIZE_RECORDING_SCRIPT_PATH
            - JIBRI_STRIP_DOMAIN_JID
            - JIBRI_LOGS_DIR
            - DISPLAY=:0
            - TZ
    jibri5:
        image: jitsi/jibri
        restart: ${RESTART_POLICY}
        volumes:
            - ${CONFIG}/jibri5:/config:Z
            - /dev/shm:/dev/shm
            - /root/jibri-docker/config/.asoundrc5:/home/jibri/.asoundrc
            - /root/jibri-docker/recordings/recorder5:/config/recordings
            - /root/jibri-docker/config/finalize.sh:/config/finalize.sh
            - /home/ubuntu:/home/jibri
        cap_add:
            - SYS_ADMIN
            - NET_BIND_SERVICE
        devices:
            - /dev/snd:/dev/snd
        environment:
            - XMPP_AUTH_DOMAIN
            - XMPP_INTERNAL_MUC_DOMAIN
            - XMPP_RECORDER_DOMAIN
            - XMPP_SERVER
            - XMPP_DOMAIN
            - JIBRI_XMPP_USER
            - JIBRI_XMPP_PASSWORD
            - JIBRI_BREWERY_MUC
            - JIBRI_RECORDER_USER
            - JIBRI_RECORDER_PASSWORD
            - JIBRI_RECORDING_DIR
            - JIBRI_FINALIZE_RECORDING_SCRIPT_PATH
            - JIBRI_STRIP_DOMAIN_JID
            - JIBRI_LOGS_DIR
            - DISPLAY=:0
            - TZ

    jibri6:
        image: jitsi/jibri
        restart: ${RESTART_POLICY}
        volumes:
            - ${CONFIG}/jibri6:/config:Z
            - /dev/shm:/dev/shm
            - /root/jibri-docker/config/.asoundrc6:/home/jibri/.asoundrc
            - /root/jibri-docker/recordings/recorder6:/config/recordings
            - /root/jibri-docker/config/finalize.sh:/config/finalize.sh
            - /home/ubuntu:/home/jibri
        cap_add:
            - SYS_ADMIN
            - NET_BIND_SERVICE
        devices:
            - /dev/snd:/dev/snd
        environment:
            - XMPP_AUTH_DOMAIN
            - XMPP_INTERNAL_MUC_DOMAIN
            - XMPP_RECORDER_DOMAIN
            - XMPP_SERVER
            - XMPP_DOMAIN
            - JIBRI_XMPP_USER
            - JIBRI_XMPP_PASSWORD
            - JIBRI_BREWERY_MUC
            - JIBRI_RECORDER_USER
            - JIBRI_RECORDER_PASSWORD
            - JIBRI_RECORDING_DIR
            - JIBRI_FINALIZE_RECORDING_SCRIPT_PATH
            - JIBRI_STRIP_DOMAIN_JID
            - JIBRI_LOGS_DIR
            - DISPLAY=:0
            - TZ

And you need to create a new file in /root/jibri-docker

nano /root/jibri-docker/config/finalize.sh
finalize.sh file content
RECORDINGS_DIR=/config/recordings

VIDEO_FILE_PATH=$(find $RECORDINGS_DIR -name *.mp4)

mkdir -p /home/jibri/recordings

mv $VIDEO_FILE_PATH /home/jibri/recordings

You will then find your recordings at /home/ubuntu/recordings

Note:

If you are deploying Jibri to a different server

To your .env file, add
PUBLIC_URL=https://my.domain.com

Also Change your jibri.yml file as

services:
    jibri1:
        image: jitsi/jibri
        restart: ${RESTART_POLICY}
        volumes:
            - ${CONFIG}/jibri1:/config:Z
            - /dev/shm:/dev/shm
            - /root/jibri-docker/config/.asoundrc1:/home/jibri/.asoundrc
            - /root/jibri-docker/recordings/recorder1:/config/recordings
            - /root/jibri-docker/config/finalize.sh:/config/finalize.sh
            - /home/ubuntu:/home/jibri
        cap_add:
            - SYS_ADMIN
            - NET_BIND_SERVICE
        devices:
            - /dev/snd:/dev/snd
        environment:
            - PUBLIC_URL     ### ADD THIS LINE
            - XMPP_AUTH_DOMAIN
            - XMPP_INTERNAL_MUC_DOMAIN
            - XMPP_RECORDER_DOMAIN
            - XMPP_SERVER
            - XMPP_DOMAIN
            - JIBRI_XMPP_USER
            - JIBRI_XMPP_PASSWORD
            - JIBRI_BREWERY_MUC
            - JIBRI_RECORDER_USER
            - JIBRI_RECORDER_PASSWORD
            - JIBRI_RECORDING_DIR
            - JIBRI_FINALIZE_RECORDING_SCRIPT_PATH
            - JIBRI_STRIP_DOMAIN_JID
            - JIBRI_LOGS_DIR
            - DISPLAY=:0
            - TZ

It feels like relying on the index value in grub for your kernel is just dangerous.

You should be doing it by actually specifying the menuentry:

grep -A200 submenu /boot/grub/grub.cfg |grep menuentry
//Find the menu title for the image you've installed. Title is important! it will probably be generic
// Set that as your GRUB_DEFAULT in /etc/default/grub
sudo update-grub 
// and make sure its fine. It'll tell you off and suggest the proper way to specify it, but you can confirm in /boot/grub/grub.cfg that it's loading your image as default. If it tells you off, it'll suggest the correct menuentry (which isn't obvious)

Interestingly, if I follow your guide, adding the kernel, editing /etc/default/grub to be GRUB_DEFAULT=1>2 and then update-grub, it does nothing (still loads the aws image), because that’s what the entries for those are that you can see in /boot/grub/grub.cfg .

1 Like