JitsiMeet Ubuntu 安装及负载均衡配置

本文介绍基于 Ubuntu 20.04 安装 Jitsi-meet,同时实现多个视屏桥的负载均衡。本文只记录安装步骤,安装原理请自行阅读下面的参考文章。

名词解释

MUC:Multi User Chat

ssh 连接 Ubuntu 服务器

1
2
3
4
ssh username@ipInLAN

# 示例:
ssh yourUserName@192.168.1.1

Jitsi-meet 安装

下列命令中,位于一个代码块中的命令行可以整体复制并运行。

安装环境准备

1
2
3
4
5
# Retrieve the latest package versions across all repositories
sudo apt update

# Ensure support for apt repositories served via HTTPS
sudo apt install apt-transport-https
1
2
# Jitsi requires dependencies from Ubuntu's universe package repository
sudo apt-add-repository universe
1
sudo apt update

设置完全限定域名(FQDN)可选

  • 设置 hostname

    1
    sudo hostnamectl set-hostname meet.example.org

  • 修改 hosts:

    1
    sudo vim /etc/hosts

    向 hosts 里添加如下内容:

    1
    2
    127.0.0.1 localhost
    x.x.x.x meet.example.org

    x.x.x.x 是公网 IP 地址

  • 测试是否联通

    1
    ping "$(hostname)"

添加 Prosody 包

Ubuntu 18.04 and 20.04

1
2
3
echo deb http://packages.prosody.im/debian $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list
wget https://prosody.im/files/prosody-debian-packages.key -O- | sudo apt-key add -
sudo apt install lua5.2

Ubuntu 22.04

1
2
3
sudo curl -sL https://prosody.im/files/prosody-debian-packages.key -o /etc/apt/keyrings/prosody-debian-packages.key
echo "deb [signed-by=/etc/apt/keyrings/prosody-debian-packages.key] http://packages.prosody.im/debian $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/prosody-debian-packages.list
sudo apt install lua5.2

添加 Jitsi 包

Ubuntu 18.04 and 20.04

1
2
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

Ubuntu 22.04

1
2
curl -sL https://download.jitsi.org/jitsi-key.gpg.key | sudo sh -c 'gpg --dearmor > /usr/share/keyrings/jitsi-keyring.gpg'
echo "deb [signed-by=/usr/share/keyrings/jitsi-keyring.gpg] https://download.jitsi.org stable/" | sudo tee /etc/apt/sources.list.d/jitsi-stable.list

更新包

1
sudo apt update

设置防火墙

防火墙端口简介:

端口 作用
80/tcp 证书验证与更新接口
443/tcp jitsi 访问接口
10000/udp Audio/Video 传输
22/tcp ssh
3478/udp 用于查找 stun 服务
5349/tcp Audio/Video 交流
5222/tcp xmpp 通信
9090/tcp websocket 视屏桥中继

设置命令:

1
2
3
4
5
6
7
8
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 10000/udp
sudo ufw allow 22/tcp
sudo ufw allow 3478/udp
sudo ufw allow 5349/tcp
sudo ufw allow 5222/tcp
sudo ufw enable

设置完后查看状态:

1
sudo ufw status verbose

安装 Jitsi Meet

1
2
# jitsi-meet installation
sudo apt install jitsi-meet

在安装的过程中,会让你选择证书,若处于 NAT 中,且前端还有一层 Nginx 时,可以使用自签名证书。

NAT 设置

机器位于 NAT 之后,需要打开/etc/jitsi/videobridge/sip-communicator.properties文件:

1
sudo vim /etc/jitsi/videobridge/sip-communicator.properties

添加以下设置:

1
2
org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS=<Local.IP.Address>
org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS=<Public.IP.Address>

参考:want-to-replace-url-for-stun-mapping-harvester-addresses

修改系统限制

1
sudo vim /etc/systemd/system.conf

修改为:

1
2
3
DefaultLimitNOFILE=65000
DefaultLimitNPROC=65000
DefaultTasksMax=65000

查看修改结果:

1
2
3
systemctl show --property DefaultLimitNPROC
systemctl show --property DefaultLimitNOFILE
systemctl show --property DefaultTasksMax

若没有生效,需要重启系统 sudo reboot 或者重启守护进程 systemctl daemon-reexec

到这一步,即可通过域名进行访问

配置参会时输入用户名

打开配置文件:

1
sudo vim /etc/jitsi/yourDomain-config.js

在第 570 行左右,找到 requireDisplayName,将其修改为 true

重启 prosody

1
sudo systemctl resetart prosody

jwt 授权

为了方便使用 IFrame API 的方式与现有的系统集成,需要配置会议授权,方便对会议进行管理。

配置 JWT

1
sudo apt-get install jitsi-meet-tokens

安装过程中,会要求输入 ApplicationId 和 Secret:

image-20231102154852501

生成 token 有格式要求,见:lib-jitsi-meet/doc/tokens.md

生成 token 后,可以在 url 中添加 jwt=xxx 来进行测试。

允许访客进入

打开配置文件:

1
sudo vim /etc/prosody/conf.d/meet.mydomain.com.cfg.lua

VirtualHost "jitmeet.example.com" 中添加 allow_empty_token = true

1
2
3
4
5
6
VirtualHost "jitmeet.example.com"
authentication = "token";
app_id = "example_app_id"; -- application identifier
app_secret = "example_app_secret"; -- application secret known only to your token
-- generator and the plugin
allow_empty_token = true; -- tokens are verified only if they are supplied by the client

添加事件回调

为了实现现有系统获取会议的创建结束信息,需要在 jitsi-meet 中添加事件回调到既有的系统中。

插件配置

下载插件:

1
2
cd /usr/share/jitsi-meet/prosody-plugins/
sudo wget -O mod_event_sync_component.lua https://raw.githubusercontent.com/jitsi-contrib/prosody-plugins/main/event_sync/mod_event_sync_component.lua

启用插件:

打开配置文件

1
sudo vim /etc/prosody/conf.d/meet.mydomain.com.cfg.lua

添加如下内容

1
2
3
Component "event_sync.meet.mydomain.com" "event_sync_component"
muc_component = "conference.meet.mydomain.com"
api_prefix = "http://your.api.server/api"

注意:api_prefix 末尾没有 / 号

更多配置,参考:prosody-plugins/event_sync/README.md at main · jitsi-contrib/prosody-plugins (github.com)

回调的 api 为:http://your.api.server/api/events/xx

重启 prosody:

1
sudo systemctl restart prosody

插件修改

由于允许访客访问,原插件没有返回用户的 display_name,当用户通过网址进入时,无法确定用户的身份,因此需要返回用户自己设置的 display_name 供回调服务器处理。

1
sudo vim /usr/share/jitsi-meet/prosody-plugins/mod_event_sync_component.lua
  1. 修改 occupant_joined:

    1
    2
    3
    4
    5
    -- 找到 occupant_joined(约在 289 行) 函数
    -- 将
    local occupant_data = room_data:on_occupant_joined(occupant_jid, event.origin);
    -- 修改为
    local occupant_data = room_data:on_occupant_joined(occupant_jid, event);

    修改 EventData:on_occupant_joined:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    -- 找到 EventData:on_occupant_joined(约在 144 行) 函数,修改为如下代码:

    function EventData:on_occupant_joined(occupant_jid, event)
    local event_origin = event.origin
    local user_context = event_origin.jitsi_meet_context_user or {};

    -- get displayName
    local display_name = event.occupant:get_presence():get_child_text('nick', 'http://jabber.org/protocol/nick');

    -- N.B. we only store user details on join and assume they don't change throughout the duration of the meeting
    local occupant_data = {
    occupant_jid = occupant_jid,
    name = user_context.name,
    id = user_context.id,
    email = user_context.email,
    joined_at = now(),
    left_at = nil,
    display_name = display_name,
    nick = event.occupant.nick,
    role = event.occupant.role,
    stable_id = event.occupant.stable_id,
    bare_jid = event.occupant.bare_jid
    };

    self.occupants[occupant_jid] = occupant_data;
    self.active[occupant_jid] = true;

    return occupant_data;
    end
  2. 重启 prosody

    1
    sudo systemctl restart prosody

添加踢出用户功能

当用户加入后,检测是否有同名用户,若有,则踢出存在的同名用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
-- 在顶部添加导入
local st = require "util.stanza"

-- 找到 function occupant_joined(event) 方法,在 `room_data:on_occupant_joined` 之后添加如下代码
for _, occupant in room:each_occupant() do
local pr = occupant:get_presence();
local displayName = pr:get_child_text(
'nick', 'http://jabber.org/protocol/nick');
if displayName == occupant_data.display_name and occupant.nick~=occupant_data.nick then
-- 获取原用户的角色, 若为moderator, 则将新用户设置为moderator
local oldRole = room:get_role(occupant.nick);
room:set_role(true, occupant.nick, nil);
if oldRole == 'moderator' then
room:set_role(true, occupant_data.occupant_jid, 'moderator');
room:set_affiliation(true, occupant_data.occupant_jid, 'owner');
end

room:set_role(true, occupant.nick, nil);
module:log('info', '踢出用户 %s kicked %s from %s',displayName, occupant.nick, room.jid);
-- 发送 kickParticipant 命令
local presence = st.presence({
to = occupant.jid,
from = room.jid,
type = "unavailable"
}):tag("status"):text("你已被移出房间 " .. room.jid):up();
module:send(presence);
end
end

参考:mod_http_muc_kick - Prosody Community Modules

视频负载均衡

安装环境准备

在另一台主机上执行 安装环境准备添加 Jitsi 包

安装 jitsi-videobridge2

1
sudo apt install jitsi-videobridge2

修改 sip 配置

分别修改主服务器、视频服务器的配置:

1
sudo vi /etc/jitsi/videobridge/sip-communicator.properties

禁用主服务器的证书验证:

/etc/jitsi/videobridge/sip-communicator.properties 添加如下配置

1
org.jitsi.videobridge.xmpp.user.shard.DISABLE_CERTIFICATE_VERIFICATION=true

将主服务器的 sip 配置复制到负载均衡服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
org.ice4j.ice.harvest.DISABLE_AWS_HARVESTER=true
org.ice4j.ice.harvest.STUN_MAPPING_HARVESTER_ADDRESSES=meet-jit-si-turnrelay.jitsi.net:443
org.jitsi.videobridge.ENABLE_STATISTICS=true
org.jitsi.videobridge.STATISTICS_TRANSPORT=muc
org.jitsi.videobridge.xmpp.user.shard.HOSTNAME=192.168.23.20 # 此处为主服务所在的 ip
org.jitsi.videobridge.xmpp.user.shard.DOMAIN=auth.yourdomain
org.jitsi.videobridge.xmpp.user.shard.USERNAME=jvb
org.jitsi.videobridge.xmpp.user.shard.PASSWORD=siBYPh4z
org.jitsi.videobridge.xmpp.user.shard.MUC_JIDS=JvbBrewery@internal.yourdomain
org.jitsi.videobridge.xmpp.user.shard.MUC_NICKNAME=8705d9ca-4031-4080-8435-78d1f5f3025e # 此处值应唯一,不与其它服务冲突
org.jitsi.videobridge.xmpp.user.shard.DISABLE_CERTIFICATE_VERIFICATION=true
org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS=192.168.23.20
org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS=223.xxx.xxx.xxx

使用 Sctp 模式

增加视频桥后,连接时会报错:

image-20231106111136879

有两种方式可以解决,本文采用最简单的方式即 Sctp 方式:

编辑文件

1
sudo vim /etc/jitsi/videobridge/jvb.conf

videobridge修改如下内容:

  1. 允许 sctp
  2. 关闭 websocket
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
sctp {
// Whether SCTP data channels are enabled.
enabled=true,
}
stats {
// The interval at which stats are gathered.
interval = 5 seconds
}
websockets {
enabled=false
server-id="default-id"
// Whether to negotiate WebSocket compression (permessage-deflate)
enable-compression = true


// Optional, even when 'enabled' is set to true
#tls=true
// The domains used when advertising a colibri-ws URL. Must be set when enabled = true
domains= []
// The domain used when advertising a colibri-relay-ws URL. If empty defaults to the value of `domains`.
relay-domains = []
}

同时修改端口

本配置位于 NAT 内,只有一个公网出口,为了不与其它 jitsi-videobridge2 冲突,修改连接端口。

使用 sctp 后,不需要修改 websocket 端口

设置防火墙

1
2
3
sudo ufw allow 22/tcp
sudo ufw allow 10000/udp # 如果是在 NAT 后面,此处的修改要与其它主机的 jitsi-videobridge2 端口不一样
sudo ufw enable

重启服务

1
sudo service jitsi-videobridge2 restart

查看日志

通过查看日志,可以了解 jitsi-videobridge2 启动情况,并根据日志记录排查错误问题。

1
sudo cat /var/log/jitsi/jvb.log

配置 OCTO

当配置多个视频桥后,它只能对多个会议进行负载均衡,无法对单个会议生效。因此需要配置 OCTO 来达到这一目的。

打开 octo

编辑文件

1
sudo vim /etc/jitsi/jicofo/jicofo.conf

增改如下内容:

1
2
3
4
5
6
7
8
9
jicofo {
bridge {
selection-strategy = RegionBasedBridgeSelectionStrategy
}
octo {
enabled = true,
id = "1"
}
}

基中,selection-strategy 的值有:

  • RegionBasedBridgeSelectionStrategy:按地区选择视频桥
  • SplitBridgeSelectionStrategy:总是使用不同的视频桥,主要用于测试

视频桥配置适配

打开所有视屏桥服务器如下文件

1
sudo vim /etc/jitsi/videobridge/sip-communicator.properties

分别增加如下配置

1
2
3
4
org.jitsi.videobridge.octo.BIND_ADDRESS=x.x.x.x # 当前主机 ip
org.jitsi.videobridge.octo.PUBLIC_ADDRESS=x.x.x.x # 公网 ip
org.jitsi.videobridge.octo.BIND_PORT=4096
org.jitsi.videobridge.REGION=regionVN # 全局唯一

开放端口 4096

1
sudo ufw allow 4096/tcp

修改视频桥配置:

1
sudo vim /etc/jitsi/videobridge/jvb.conf

高 sctp 中增加 sctp-datachannels = true

1
2
3
4
5
6
7
sctp {
// Whether SCTP data channels are enabled.
enabled=true,

// Whether bridge-to-bridge communication should use SCTP datachannels (as opposed to websockets)
sctp-datachannels = true
}

重启服务

1
2
sudo service jicofo restart
sudo service jitsi-videobridge2 restart

本节参考

  1. jitsi-videobridge/doc/relay.md at master · jitsi/jitsi-videobridge (github.com)

配置文件路径

路径 作用
/etc/prosody/conf.avail/[your-domain].cfg.lua 域配置
/etc/jitsi/meet/[your-domain]-config.js jitsi 系统配置
/etc/jitsi/videobridge/config videobridge 配置文件
/etc/jitsi/videobridge/sip-communicator.properties sip 配置文件
/var/log/prosody prosody 日志位置
/var/log/jitsi/jvb.log jvb 日志位置
/var/log/jitsi/jicofo.log jicofo 日志位置
/usr/share/jitsi-meet/prosody-plugins/mod_event_sync_component.lua even_sync 插件位置

其它

如果需要额外的功能,可以通过安装 prosody 模块来实现,详见:Prosody Community Modules

参考

本文参考以下文章,在此致以诚挚谢意!

  1. Self-Hosting Guide - Debian/Ubuntu server | Jitsi Meet

  2. jitsi-videobridge/doc at master · jitsi/jitsi-videobridge (github.com)

  3. lib-jitsi-meet/doc/tokens.md at master · jitsi/lib-jitsi-meet (github.com)

  4. prosody-plugins/event_sync/README.md at main · jitsi-contrib/prosody-plugins (github.com)

  5. Configuration | Jitsi Meet

  6. Scaling Up Your Jitsi with Jitsi Bridges (doganbros.com)

  7. How to add another videobridge. Getting error when adding a new video bridge to the standalone setup - Install & Config - Jitsi Community Forum - developers & users

  8. Want to replace url for STUN MAPPING HARVESTER ADDRESSES? - Install & Config - Jitsi Community Forum - developers & users

  9. disable websockets to the bridge and use sctp

  10. jitsi-videobridge/doc/web-sockets.md at master · jitsi/jitsi-videobridge (github.com)

  11. Is port 9090 required for JVB with Websockets? - Install & Config - Jitsi Community Forum - developers & users

  12. Need to test that whether it's working or not after enabling OCTO / OCTO configuration - Install & Config - Jitsi Community Forum - developers & users

  13. jicofo/jicofo-selector/src/main/resources/reference.conf at master · jitsi/jicofo (github.com)

  14. This is tutorial to configure octo feature on jitsi. (github.com)

  15. working-multi-jitsi-meet-multi-videobridge-setup

  16. tutorial-jibri-overview-troubleshooting-tips-tricks-solve-your-jibri-problems-quickly