BigBlueButton

Updated 8 April 2021

BigBlueButton

BigBlueButton is an open source Web conferencing solution. Initially, it was developed for educational purposes. Its name comes from the original concept that starting a web conference should be as easy as possible, like pressing a "big blue button".

Creating a LXC container

BigBlueButton is developed and tested on Ubuntu Xenial. You can install Ubuntu in a LXC container. To create a LXC container, first install the necessary packages:

emerge -a app-emulation/lxc dev-libs/libcgroup

Run cgconfig to create cgroup systemd:

/etc/init.d/cgconfig start

Confinguring Docker start in LXC

If Docker used inside a LXC container, load the necessary kernel modules on the host and add to them to autostart:

modprobe -a br_netfilter ip_tables nf_conntrack_netlink nf_nat overlay xt_conntrack

echo -e "br_netfilter\nip_tables\nnf_conntrack_netlink\nnf_nat\noverlay\nxt_conntrack" > /etc/modules-load.d/docker.conf

Create a container for BigBlueButton:

lxc-create -t download -n bigbluebutton -- -d ubuntu -r xenial -a amd64

Launch the container:

lxc-start bigbluebutton

Configure your network according to the instructions, but do not assign an IP address nor a gateway by editing the configuration file of the container.

Add the permission to run the hello-world test for Docker:

/var/calculate/lxc/calculate/config
lxc.cgroup.devices.allow = c 10:200 rwm

Edit the network settings inside the container. Specify the relevant IP, the network mask, the default gateway and the DNS server addresses:

/etc/network/interfaces
...
auto eth0
iface eth0 inet static
  address 192.168.11.2
  netmask 255.255.255.0
  gateway 192.168.11.1
  dns-nameservers 8.8.8.8
...

Restart the container.

lxc-stop -r bigbluebutton

Attach the container:

lxc-attach bigbluebutton

Update the binary repository:

apt-get update

Install the SSH client and server:

apt-get install ssh openssh-server -y

Edit the root password:

passwd

Allow the root user to connect via SSH:

/etc/ssh/sshd_config
...
PermitRootLogin yes
...

Restart SSH:

systemctl restart ssh

Reset the locale:

sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen

sed -i -e 's/# ru_RU.UTF-8 UTF-8/ru_RU.UTF-8 UTF-8/' /etc/locale.gen

dpkg-reconfigure --frontend=noninteractive locales

update-locale LANG=en_US.UTF-8

Make sure that the locale is specified as an environment variable:

systemctl show-environment
LANG=en_US.UTF-8
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

Add the server's definition as meet.example.org:

/etc/hosts
127.0.0.1   meet.example.org bigbluebutton localhost

Since the installation process runs in a container, some BigBlueButton components require an entropy source. Install the random number generator:

apt-get install haveged -y

Add the daemon to autostart and run it:

systemctl enable haveged

systemctl start haveged

Install the repo management toolkit:

apt-get install software-properties-common -y

Installing and configuring BigBlueButton

Add the repos to install from:

add-apt-repository ppa:bigbluebutton/support -y

add-apt-repository ppa:rmescandon/yq -y

Enable the MongoDB repository and install the database:

wget -qO - https://www.mongodb.org/static/pgp/server-3.4.asc | apt-key add -

echo "deb [ arch=amd64,arm64 ] http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-3.4.list

apt-get update

apt-get install -y mongodb-org curl

Add the NodeJS repository with version 8.x and install it:

curl -sL https://deb.nodesource.com/setup_8.x | bash -

apt-get install -y nodejs

Add the BigBlueButton key and repository:

wget https://ubuntu.bigbluebutton.org/repo/bigbluebutton.asc -O- | apt-key add -

echo "deb https://ubuntu.bigbluebutton.org/xenial-220/ bigbluebutton-xenial main" | tee /etc/apt/sources.list.d/bigbluebutton.list

apt-get update

Start the installation process for BigBlueButton:

apt-get install bigbluebutton -y

You will have to accept the EULA licence.

Due to the LXC limitations, the installation process cannot be completed as Redis and FreeSWITCH cannot be started.

Fix the Redis startup module by disabling missing restrictions:

/etc/systemd/system/redis.service
[Unit]
Description=Advanced key-value store
After=network.target
Documentation=http://redis.io/documentation, man:redis-server(1)

[Service]
Type=forking
ExecStart=/usr/bin/redis-server /etc/redis/redis.conf
PIDFile=/var/run/redis/redis-server.pid
TimeoutStopSec=0
Restart=always
User=redis
Group=redis

ExecStartPre=-/bin/run-parts --verbose /etc/redis/redis-server.pre-up.d
ExecStartPost=-/bin/run-parts --verbose /etc/redis/redis-server.post-up.d
ExecStop=-/bin/run-parts --verbose /etc/redis/redis-server.pre-down.d
ExecStop=/bin/kill -s TERM $MAINPID
ExecStopPost=-/bin/run-parts --verbose /etc/redis/redis-server.post-down.d

UMask=007
#PrivateTmp=yes
#PrivateDevices=yes
#ProtectHome=yes
#ReadOnlyDirectories=/
#ReadWriteDirectories=-/var/lib/redis
#ReadWriteDirectories=-/var/log/redis
#ReadWriteDirectories=-/var/run/redis
#CapabilityBoundingSet=~CAP_SYS_PTRACE

# redis-server writes its own config file when in cluster mode so we allow
# writing there (NB. ProtectSystem=true over ProtectSystem=full)
#ProtectSystem=true
#ReadWriteDirectories=-/etc/redis

[Install]
WantedBy=multi-user.target
Alias=redis.service

Run Redis:

systemctl daemon-reload

systemctl start redis

Fix the FreeSWITCH startup module by disabling missing restrictions:

/etc/systemd/system/multi-user.target.wants/freeswitch.service
[Unit]
Description=freeswitch
After=syslog.target network.target local-fs.target

[Service]
; service
Type=forking
PIDFile=/opt/freeswitch/var/run/freeswitch/freeswitch.pid
Environment="DAEMON_OPTS=-nonat"
EnvironmentFile=-/etc/default/freeswitch
ExecStart=/opt/freeswitch/bin/freeswitch -u freeswitch -g daemon -ncwait $DAEMON_OPTS
TimeoutSec=45s
Restart=always
; exec
WorkingDirectory=/opt/freeswitch
User=freeswitch
Group=daemon

#LimitCORE=infinity
#LimitNOFILE=100000
#LimitNPROC=60000
#LimitSTACK=250000
#LimitRTPRIO=infinity
#LimitRTTIME=7000000
#IOSchedulingClass=realtime
#IOSchedulingPriority=2
#CPUSchedulingPolicy=rr
#CPUSchedulingPriority=89

#UMask=0007

[Install]
WantedBy=multi-user.target

Start FreeSWITCH:

systemctl daemon-reload

systemctl start freeswitch

Resume the installation process:

apt-get install -f

Install BigBlueButton HTML5:

apt-get install bbb-html5

To reduce impulse noises, adjust the sound level for voice transmission between users:

/opt/freeswitch/etc/freeswitch/autoload_configs/conference.conf.xml
<profile name="cdquality">
  <param name="domain" value="$${domain}"/>
  <param name="rate" value="48000"/>
  <param name="interval" value="20"/>
  <param name="energy-level" value="10"/>
...

Restart BigBlueButton:

bbb-conf --restart

Check for configuration errors:

bbb-conf --check
BigBlueButton Server 2.2.3 (1833)
                    Kernel version: 4.19.96-calculate
                      Distribution: Ubuntu 16.04.6 LTS (64-bit)
                            Memory: 131797 MB
                         CPU cores: 16

/usr/share/bbb-web/WEB-INF/classes/bigbluebutton.properties (bbb-web)
       bigbluebutton.web.serverURL: http://meet.example.org
                defaultGuestPolicy: ALWAYS_ACCEPT
                 svgImagesRequired: true

/etc/nginx/sites-available/bigbluebutton (nginx)
                       server name: http://meet.example.org
                              port: 80, [::]:80
                    bbb-client dir: /var/www/bigbluebutton

/var/www/bigbluebutton/client/conf/config.xml (bbb-client)
                Port test (tunnel): rtmp://meet.example.org
                              red5: meet.example.org
              useWebrtcIfAvailable: true

/opt/freeswitch/etc/freeswitch/vars.xml (FreeSWITCH)
                       local_ip_v4: 192.168.11.2
                   external_rtp_ip: stun:stun.freeswitch.org
                   external_sip_ip: stun:stun.freeswitch.org

/opt/freeswitch/etc/freeswitch/sip_profiles/external.xml (FreeSWITCH)
                        ext-rtp-ip: $${local_ip_v4}
                        ext-sip-ip: $${local_ip_v4}
                        ws-binding: :5066
                       wss-binding: :7443

/usr/local/bigbluebutton/core/scripts/bigbluebutton.yml (record and playback)
                     playback_host: meet.example.org
                 playback_protocol: http
                            ffmpeg: 4.2.2-1bbb1~ubuntu16.04

/etc/bigbluebutton/nginx/sip.nginx (sip.nginx)
                        proxy_pass: 192.168.11.2

/usr/local/bigbluebutton/bbb-webrtc-sfu/config/default.yml (Kurento SFU)
                        kurento.ip: 192.168.11.2
                       kurento.url: ws://127.0.0.1:8888/kurento
                    localIpAddress: 192.168.11.2
               recordScreenSharing: true
                     recordWebcams: true
                  codec_video_main: VP8
               codec_video_content: VP8

/usr/share/meteor/bundle/programs/server/assets/app/config/settings.yml (HTML5 client)
                             build: 870
                        kurentoUrl: wss://meet.example.org/bbb-webrtc-sfu
                  enableListenOnly: true

# Potential problems described below

Specify the host name for BigBlueButton, meet.example.org:

bbb-conf --setip meet.example.org

HTTPS configuration

Getting Let's Encrypt certificat

Get a certificate for domain meet.example.org, as explained in the manual.

HTTPS configuration for Nginx

Create a certificate directory:

mkdir /etc/nginx/ssl

Copy the certificates received via Let's Encrypt:

cp fullchain.pem /etc/nginx/ssl/meet.example.org/fullchain.pem

cp privkey.pem /etc/nginx/ssl/meet.example.org/privkey.pem

Create a DH key:

openssl dhparam -out /etc/nginx/ssl/dhp-4096.pem 4096

Add HTTPS Nginx:

/etc/nginx/sites-available/bigbluebutton
server {
    server_name meet.example.org;
    listen 80;
    listen [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;

    ssl_certificate /etc/nginx/ssl/meet.example.org/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/meet.example.org/privkey.pem;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS:!AES256";
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/nginx/ssl/dhp-4096.pem;

    if ($scheme = http) {
        return 301 https://$server_name$request_uri;
    }
    ...

FreeSWITCH configuration for SSL

Configure FreeSWITCH for using SSL. To do this, specify the external address:

/etc/bigbluebutton/nginx/sip.nginx
location /ws {
    proxy_pass https://1.2.3.4:7443;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_read_timeout 6h;
    proxy_send_timeout 6h;
    client_body_timeout 6h;
    send_timeout 6h;
}

Important

Note that the external IP address is specified in this configuration, not the host name.

BigBlueButton configuration for running HTTPS sessions

Configure BigBlueButton for running HTTPS sessions and HTML5:

/usr/share/bbb-web/WEB-INF/classes/bigbluebutton.properties
...
#----------------------------------------------------
# This URL is where the BBB client is accessible. When a user sucessfully
# enters a name and password, she is redirected here to load the client.
# Do not commit changes to this field.
bigbluebutton.web.serverURL=https://meet.example.org
...
# Force all attendees to join the meeting using the HTML5 client
attendeesJoinViaHTML5Client=true

# Force all moderators to join the meeting using the HTML5 client
moderatorsJoinViaHTML5Client=true

Share the screen access, via HTTPS as well:

/usr/share/red5/webapps/screenshare/WEB-INF/screenshare.properties
...
streamBaseUrl=rtmp://meet.example.org/screenshare
jnlpUrl=https://meet.example.org/screenshare
jnlpFile=https://meet.example.org/screenshare/screenshare.jnlp

Tell the client to load components via HTTPS:

sed -e 's|http://|https://|g' -i /var/www/bigbluebutton/client/conf/config.xml

Configure WebRTC via the SSL socket:

/usr/share/meteor/bundle/programs/server/assets/app/config/settings.yml
...
  kurento:
    wsUrl: wss://meet.example.org/bbb-webrtc-sfu
...
  note:
    enabled: true
    url: https://meet.example.org/pad
...

Configure record handling via HTTPS:

/usr/local/bigbluebutton/core/scripts/bigbluebutton.yml
...
playback_protocol: https

Restart BigBlueButton:

bbb-conf --restart

Restart Nginx:

systemctl restart nginx

TURN server configuration

Configure your TURN server, turn.example.org, as described in the manual.

Tell BigBlueButton to use the configured turn.example.org server as the STUN and TURN servers. To connect to the TURN server, use key 4b85833c7fdf06130bd7398ac9af558b. It is stored in static-auth-secret, in your TURN server settings.

/usr/share/bbb-web/WEB-INF/classes/spring/turn-stun-servers.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="stun0" class="org.bigbluebutton.web.services.turn.StunServer">
        <constructor-arg index="0" value="stun:turn.example.org"/>
    </bean>

    <bean id="turn0" class="org.bigbluebutton.web.services.turn.TurnServer">
        <constructor-arg index="0" value="4b85833c7fdf06130bd7398ac9af558b"/>
        <constructor-arg index="1" value="turns:turn.example.org:443?transport=tcp"/>
        <constructor-arg index="2" value="86400"/>
    </bean>

    <bean id="turn1" class="org.bigbluebutton.web.services.turn.TurnServer">
        <constructor-arg index="0" value="4b85833c7fdf06130bd7398ac9af558b"/>
        <constructor-arg index="1" value="turn:turn.example.org:443?transport=tcp"/>
        <constructor-arg index="2" value="86400"/>
    </bean>

    <bean id="stunTurnService"
            class="org.bigbluebutton.web.services.turn.StunTurnService">
        <property name="stunServers">
            <set>
                <ref bean="stun0"/>
            </set>
        </property>
        <property name="turnServers">
            <set>
                <ref bean="turn0"/>
                <ref bean="turn1"/>
            </set>
        </property>
    </bean>
</beans>

Restart BigBlueButton:

bbb-conf --restart

Configuring Greenlight

Greenlight is a Ruby on Rails application that provides a simple interface for users to create rooms, run conferences, and manage conference records.

Install the utilities required to attach the repository:

apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common -y

Add the keys and attach the Docker repository:

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

apt-key fingerprint 0EBFCD88

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

apt-get update

Install Docker 17.09.1:

apt-get install docker-ce=17.09.1~ce-0~ubuntu docker-compose containerd.io -y

Check whether Docker is running by starting the hello-world container:

docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete 
Digest: sha256:f9dfddf63636d84ef479d645ab5885156ae030f611a56f3a7ac7f2fdd86d7e4e
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.
...

Disable docker-ce update:

echo docker-ce hold | dpkg --set-selections

Create a configuration directory for GreenLight:

mkdir ~/greenlight && cd ~/greenlight

Create a sample GreenLight configuration file:

docker run --rm bigbluebutton/greenlight:v2 cat ./sample.env > .env

Create a secret key for GreenLight:

docker run --rm bigbluebutton/greenlight:v2 bundle exec rake secret

458e2c786750cb534f2350d12bcf173052cf5fa275c66d545fb64affe805f49cb09169a8a8799cbcaff7762c1c1664e48e5cf4d8754a5f0865e0c9fedc53e1cc

Save this value in the SECRET_KEY_BASE file variable.env:

~/greenlight/.env
# Create a Secret Key for Rails
#
# You can generate a secure one through the Greenlight docker image
# with the command.
#
#   docker run --rm bigbluebutton/greenlight:v2 bundle exec rake secret
#
SECRET_KEY_BASE=458e2c786750cb534f2350d12bcf173052cf5fa275c66d545fb64affe805f49cb09169a8a8799cbcaff7762c1c1664e48e5cf4d8754a5f0865e0c9fedc53e1cc
...

Get the BigBlueButton URL and its key:

bbb-conf --secret
    URL: https://meet.example.org/bigbluebutton/
    Secret: zZ7XSEB7EjubByrCxAthTNYomDVbMwjUbfT4xqoa3p

    Link to the API-Mate:
    https://mconf.github.io/api-mate/#server=https://meet.example.org/bigbluebutton/&sharedSecret=zZ7XSEB7EjubByrCxAthTNYomDVbMwjUbfT4xqoa3p

Save this value in the BIGBLUEBUTTON_ENDPOINT and BIGBLUEBUTTON_SECRET file variables.env:

~/greenlight/.env
...
# The endpoint and secret for your BigBlueButton server.
# Set these if you are running GreenLight on a single BigBlueButton server.
# You can retrive these by running the following command on your BigBlueButton server:
#
#   bbb-conf --secret
#
BIGBLUEBUTTON_ENDPOINT=https://meet.example.org/bigbluebutton/
BIGBLUEBUTTON_SECRET=zZ7XSEB7EjubByrCxAthTNYomDVbMwjUbfT4xqoa3p

Check the GreenLight settings:

docker run --rm --env-file .env bigbluebutton/greenlight:v2 bundle exec rake conf:check
Checking environment: Passed
Checking Connection: Passed
Checking Secret: Passed

Add a Nginx configuration:

docker run --rm bigbluebutton/greenlight:v2 cat ./greenlight.nginx | tee /etc/bigbluebutton/nginx/greenlight.nginx

Add a BigBlueButton reference to the GreenLight page:

/etc/nginx/sites-available/bigbluebutton
...
    # Redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
            root   /var/www/nginx-default;
    }
    location = / {
        return 307 /b;
    }
}

Create a script for docker-compose:

docker run --rm bigbluebutton/greenlight:v2 cat ./docker-compose.yml > docker-compose.yml

Generate a password for PostgreSQL:

export pass=$(openssl rand -hex 8); sed -i 's/POSTGRES_PASSWORD=password/POSTGRES_PASSWORD='$pass'/g' docker-compose.yml;sed -i 's/DB_PASSWORD=password/DB_PASSWORD='$pass'/g' .env

Edit the version of docker-compose:

sed -i "s/version: '3'/version: '2'/" docker-compose.yml

Start the container:

docker-compose up -d

Restart Nginx:

systemctl restart nginx

Create the admin account:

docker exec greenlight-v2 bundle exec rake user:create["Admin Name","support@example.org","password","admin"]

All done! Once meet.example.org opened, the site will look somewhat like this:

BigBlueButton installed

To join as the administrator, specify thesupport@example.org e-mail and the admin password.

Configuring mail notifications

To enable account confirmation via email, specify the sending mail server settings:

~/greenlight/.env
...
# Set this to true if you want GreenLight to send verification emails upon
# the creation of a new account
#
ALLOW_MAIL_NOTIFICATIONS=true

SMTP_SERVER=mail.example.org
SMTP_PORT=465
SMTP_DOMAIN=example.org
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_ATUH=
SMTP_STARTTLS_AUTO=true

# Specify the email address that all mail is sent from
SMTP_SENDER=support@example.org
...

Restart Greenlight:

docker-compose down && docker-compose up -d

Changing user password

To change a user's password, you can use the RubyOnRail terminal:

docker exec -it greenlight-v2 bundle exec rails c

Loading production environment (Rails 5.2.3)
irb(main):001:0> User.find_by(email: "user@example.org").update_attribute(:password, "new_secret")
=> true

When this has been done, the user password can be reset on the account editing page:

Reset user password

Updating BigBlueButton

Attach the container:

lxc-attach bigbluebutton

Update the binary repository:

apt-get update

Update all system packages:

apt-get dist-upgrade

Update the Greenlight image:

cd ~/greenlight

docker pull bigbluebutton/greenlight:v2

Make sure the settings have not moved after update:

/opt/freeswitch/etc/freeswitch/autoload_configs/conference.conf.xml
<profile name="cdquality">
  <param name="domain" value="$${domain}"/>
  <param name="rate" value="48000"/>
  <param name="interval" value="20"/>
  <param name="energy-level" value="10"/>
...

Restart the container.

lxc-stop -r bigbluebutton

Recovering Docker images when using Btrfs

If your container runs on a Btrfs filesystem, Docker will use subvolumes for the images, which will not be copied when snapshotting for this container. You need to download again the source files to run Greenlight.

Download again all the Docker images used for Greenlight:

cd ~/greenlight

docker pull bigbluebutton/greenlight:v2

docker pull postgres:9.5

Restart Greenlight:

docker-compose down && docker-compose up -d