[matrix] Element Call
В предыдущей статье мы рассмотрели установку домашнего сервера Matrix Synapse, а также сервисов, которые обеспечивают текстовые сообщения, голосовые сообщения и управление пользователями. Однако этого не достаточно для организации полноценного home‑сервера.
Для обеспечения видео и аудио звонков необходимо инсталлировать еще два сервера:
tags
Кроме того, на стороне сервера Synapse должно быть обеспечено взаимодействие в соответствии с текущими спецификациями (Matrix Specification Proposals):
- MSC3266: Room Summary API: In Standalone mode Element Call is able to join rooms over federation using knocking. In this context MSC3266 is required as it allows to request a room summary of rooms you are not joined. The summary contains the room join rules. We need that information to decide if the user gets prompted with the option to knock ("Request to join call"), a "cannot join error" or "the join view".
- MSC4140: Delayed Events: Delayed events are required for proper call participation signalling. If disabled it is very likely that you end up with stuck calls in Matrix rooms.
- MSC4222: Adding state_after to sync v2: Allow clients to opt-in to a change of the sync v2 API that allows them to correctly track the state of the room. This is required by Element Call to track room state reliably.
MatrixRTC Backend
В общем виде, схему взаимодействия можно представить следующим образом:
Итак, нам необходимо инсталлировать еще два сервера. Начнем с сервера LiveKit SFU (Matrix LiveKit Server).
Прежде чем начать сборку, создадим необходимые каталоги:
mkdir -p /var/run/matrix-rtc mkdir -p /var/log/matrix-rtc mkdir -p /var/lib/matrix-rtc
Данные каталоги предназначены для хранения log‑файлов, pid‑файлов и имитации домашнего пространства серверов SFU и JWT.
LiveKit SFU
Сервер написан на языке Go и его сборка не представляет никаких трудностей:
git clone https://github.com/livekit/livekit cd livekit ./bootstrap.sh mage
Результат сборки в виде единственного исполняемого файла livekit‑server будет находиться в каталоге сборки livekit/bin/.
Скопируем его в каталог /usr/bin/:
cp -a bin/livekit-server /usr/bin/
Для обеспечения запуска сервера при старте системы, составим следующий скрипт:
/etc/rc.d/rc.matrix-sfu:
#!/bin/sh
SFU_NAME="livekit-server"
SFU_PROG=/usr/bin/livekit-server
PID_DIR=/var/run/matrix-rtc
LOG_DIR=/var/log/matrix-rtc
WORKDIR=/var/lib/matrix-rtc
SFU_CONFIG_FILE=/etc/matrix-synapse/sfu-config.yaml
SFU_LOG_FILE=${LOG_DIR}/${SFU_NAME}.log
SFU_PID_FILE=${PID_DIR}/${SFU_NAME}.pid
case "$1" in
start)
# create $PID_DIR with correct access rights
if [ ! -d ${PID_DIR} ] ; then
rm -rf ${PID_DIR}
mkdir -p ${PID_DIR}
fi
chmod 0755 ${PID_DIR}
# create $LOG_DIR with correct access rights
if [ ! -d ${LOG_DIR} ] ; then
rm -rf ${LOG_DIR}
mkdir -p ${LOG_DIR}
fi
chmod 0755 ${LOG_DIR}
# create $WORKDIR with correct access rights
if [ ! -d ${WORKDIR} ] ; then
rm -rf ${WORKDIR}
mkdir -p ${WORKDIR}
fi
chmod 0755 ${WORKDIR}
echo "Starting ${SFU_NAME}..."
if [ -f "${SFU_PID_FILE}" ]; then
echo "${SFU_NAME} is already running (PID: $(cat "${SFU_PID_FILE}"))."
exit 1
fi
cd "${WORKDIR}" || exit 1
${SFU_PROG} --config ${SFU_CONFIG_FILE} >>${SFU_LOG_FILE} 2>&1 &
echo "$!" > ${SFU_PID_FILE}
;;
stop)
echo "Stopping ${SFU_NAME}..."
if [ ! -f "${SFU_PID_FILE}" ]; then
echo "${SFU_NAME} is not running."
exit 1
fi
/bin/kill -9 $(cat "${SFU_PID_FILE}") 1> /dev/null 2>/dev/null
rm -f "${SFU_PID_FILE}"
;;
restart)
echo "Restarting ${SFU_NAME}..."
$0 stop
sleep 5
$0 start
;;
status)
if [ -f "${SFU_PID_FILE}" ]; then
echo "${SFU_NAME} is running (PID: $(cat "${SFU_PID_FILE}"))."
else
echo "${SFU_NAME} is not running."
fi
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
exit 1
;;
esac
exit 0
Разумеется, необходимо составить конфигурационный файл /etc/matrix‑synapse/sfu‑config.yaml следующего содержания:
/etc/matrix‑synapse/sfu‑config.yaml:
port: 7880 bind_addresses: - "0.0.0.0" rtc: tcp_port: 7881 port_range_start: 50100 port_range_end: 50200 use_external_ip: false room: auto_create: false logging: level: info turn: enabled: false domain: localhost cert_file: "" key_file: "" tls_port: 5349 udp_port: 443 external_tls: true keys: devkey: "9z1Qv6J3Ky2EiaZToYx2Qdh8MWkykzShdpWeZQeqqwhZ"
Ключ devkey создается с помощью команды:
# /usr/bin/livekit-server generate-keys API Key: APIqZ3K9pBeN3k3 API Secret: 9z1Qv6J3Ky2EiaZToYx2Qdh8MWkykzShdpWeZQeqqwhZ
Этот ключ понадобится нам для запуска сервера авторизации далее.
MatrixRTC Authorization Service
Данный сервис также написан на языке Go. Его сборка может быть выполнена с помощью следующих команд:
wget https://github.com/element-hq/lk-jwt-service/archive/refs/tags/v0.3.0.tar.gz tar -xvf v0.3.0.tar.gz mv lk-jwt-service-0.3.0 lk-jwt-service cd lk-jwt-service go build -o lk-jwt-service .
Результат сборки в виде исполняемого файла lk‑jwt‑service будет находиться в каталоге сборки lk‑jwt‑service/. Его также надо скопировать в каталог /usr/bin/:
cp -a lk-jwt-service /usr/bin/
Для запуска сервиса следует использовать скрипт /etc/rc.d/rc.matrix‑jwt:
/etc/rc.d/rc.matrix‑jwt:
#!/bin/sh
JWT_NAME="lk-jwt-service"
JWT_PROG=/usr/bin/lk-jwt-service
PID_DIR=/var/run/matrix-rtc
LOG_DIR=/var/log/matrix-rtc
WORKDIR=/var/lib/matrix-rtc
JWT_LOG_FILE=${LOG_DIR}/${JWT_NAME}.log
JWT_PID_FILE=${PID_DIR}/${JWT_NAME}.pid
LIVEKIT_URL="https://matrix-rtc.home.ru/livekit/sfu"
LIVEKIT_KEY=APIqZ3K9pBeN3k3
LIVEKIT_SECRET=9z1Qv6J3Ky2EiaZToYx2Qdh8MWkykzShdpWeZQeqqwhZ
LIVEKIT_FULL_ACCESS_HOMESERVERS=*
LIVEKIT_JWT_PORT=8990
case "$1" in
start)
# create $PID_DIR with correct access rights
if [ ! -d ${PID_DIR} ] ; then
rm -rf ${PID_DIR}
mkdir -p ${PID_DIR}
fi
chmod 0755 ${PID_DIR}
# create $LOG_DIR with correct access rights
if [ ! -d ${LOG_DIR} ] ; then
rm -rf ${LOG_DIR}
mkdir -p ${LOG_DIR}
fi
chmod 0755 ${LOG_DIR}
# create $WORKDIR with correct access rights
if [ ! -d ${WORKDIR} ] ; then
rm -rf ${WORKDIR}
mkdir -p ${WORKDIR}
fi
chmod 0755 ${WORKDIR}
echo "Starting ${JWT_NAME}..."
if [ -f "${JWT_PID_FILE}" ]; then
echo "${JWT_NAME} is already running (PID: $(cat "${JWT_PID_FILE}"))."
exit 1
fi
cd "${WORKDIR}" || exit 1
LIVEKIT_URL="${LIVEKIT_URL}" \
LIVEKIT_KEY=${LIVEKIT_KEY} \
LIVEKIT_SECRET=${LIVEKIT_SECRET} \
LIVEKIT_FULL_ACCESS_HOMESERVERS="${LIVEKIT_FULL_ACCESS_HOMESERVERS}" \
LIVEKIT_JWT_PORT=${LIVEKIT_JWT_PORT} \
${JWT_PROG} >>${JWT_LOG_FILE} 2>&1 &
echo "$!" > ${JWT_PID_FILE}
;;
stop)
echo "Stopping ${JWT_NAME}..."
if [ ! -f "${JWT_PID_FILE}" ]; then
echo "${JWT_NAME} is not running."
exit 1
fi
/bin/kill -9 $(cat "${JWT_PID_FILE}") 1> /dev/null 2>/dev/null
rm -f "${JWT_PID_FILE}"
;;
restart)
echo "Restarting ${JWT_NAME}..."
$0 stop
sleep 5
$0 start
;;
status)
if [ -f "${JWT_PID_FILE}" ]; then
echo "${JWT_NAME} is running (PID: $(cat "${JWT_PID_FILE}"))."
else
echo "${JWT_NAME} is not running."
fi
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
exit 1
;;
esac
exit 0
Здесь, значения переменных:
LIVEKIT_KEY=APIqZ3K9pBeN3k3 LIVEKIT_SECRET=9z1Qv6J3Ky2EiaZToYx2Qdh8MWkykzShdpWeZQeqqwhZ
Получены нами ранее посредством команды:
# /usr/bin/livekit-server generate-keys
Как видно по значению переменной LIVEKIT_URL скрипта запуска /etc/rc.d/rc.matrix‑jwt, web‑сервер будет находиться по адресу https://matrix‑rtc.home.ru и нам остается составить конфирурацию виртуального сервера Nginx:
#
# matrix-rtc.home.ru server:
#
server {
listen 80;
listen [::]:80;
server_name matrix-rtc.home.ru;
return 301 https://matrix-rtc.home.ru$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name matrix-rtc.home.ru;
error_log /var/log/nginx/matrix-rtc.home.ru-error.log;
access_log /var/log/nginx/matrix-rtc.home.ru-access.log;
#
# Comment before getting first Certificates:
#
ssl_certificate /etc/letsencrypt/live/matrix-rtc.home.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/matrix-rtc.home.ru/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/matrix-rtc.home.ru/chain.pem;
location ^~ /sfu/get {
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "POST";
add_header Access-Control-Allow-Headers "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:8990/sfu/get;
}
location ^~ /livekit/sfu/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_send_timeout 120;
proxy_read_timeout 120;
proxy_set_header Accept-Encoding gzip;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
proxy_pass http://127.0.0.1:7880/;
}
}
Составим еще один файл.
/etc/logrotate.d/rc.matrix‑rtc:
/var/log/matrix-rtc/livekit-server.log /var/log/matrix-rtc/lk-jwt-service.log {
rotate 7
size=5M
compress
notifempty
missingok
}
Теперь SFU и JWT серверы готовы к работе и нам остается отредактировать конфигурацию Matrix Synapse сервера.
MatrixRTC Backend Announcement
В конфигурационный файл /etc/matrix‑synapse/matrix.home.ru.conf необходимо добавить следующие строки:
# # matrix-rtc.home.ru: # experimental_features: # MSC3266: Room summary API. Used for knocking over federation msc3266_enabled: true # MSC4222 needed for syncv2 state_after. This allow clients to # correctly track the state of the room. msc4222_enabled: true # The maximum allowed duration by which sent events can be delayed, as # per MSC4140. max_event_delay_duration: 24h rc_message: # This needs to match at least e2ee key sharing frequency plus a bit of headroom # Note key sharing events are bursty per_second: 0.5 burst_count: 30 rc_delayed_event_mgmt: # This needs to match at least the heart-beat frequency plus a bit of headroom # Currently the heart-beat is every 5 seconds which translates into a rate of 0.2s per_second: 1 burst_count: 20
Кроме того, необходимо аннонсировать сервер https://matrix‑rtc.home.ru в файле https://matrix.home.ru/.well‑known/matrix/client так, чтобы его новое содержимое было таким:
https://matrix.home.ru/.well‑known/matrix/client:
{
"m.homeserver": {
"base_url": "https://matrix.home.ru"
},
"org.matrix.msc4143.rtc_foci":[
{
"type":"livekit",
"livekit_service_url":"https://matrix-rtc.home.ru"
}
]
}
В файле /etc/nginx/vhosts/matrix.home.ru.conf это будет выглядеть следующим образом:
location = /.well-known/matrix/client {
return 200 '{"m.homeserver": {"base_url": "https://matrix.home.ru"},"org.matrix.msc4143.rtc_foci":[{"type":"livekit","livekit_service_url":"https://matrix-rtc.home.ru"}]}';
default_type application/json;
add_header Access-Control-Allow-Origin *;
}
На этом наши настройки закончены и можно перезагрузить конфирурацию Nginx:
/etc/rc.d/rc.nginx reload
Теперь наш домашний сервер Synapse в состоянии обеспечить аудио и видео звонки.
Следует отметить, что в случае использования web‑клиента Element, для совершения видеовызова надо использовать Legacy тип звонка. Кроме того, на смартфон следует устанавливать Element Classic, так как [matrix] совершенствуется непрерывно и на данный момент Element X не будет корректно работать с нашим сервером.
Литература:
- Synapse Installation Instructions
- End-to-end encrypted voice and video for self-hosted community users
- Self-Hosting Element Call
- Element Server Suite (ESS)
Links:
Sources:
- Synapse – Matrix homeserver implementation
- Coturn TURN server
- LiveKit SFU
- MatrixRTC Authorization Service
Поскольку [matrix] – это децентрализованная сеть, вы можете создать аккаунт на любом сервере, а также звонить не только пользователям собственного сервера, но и общаться с людьми, зарегистрированным на любом сервере [matrix] в сети Internet.
Enjoy.