Ставим matrix+LiveKit на FreeBSD
matrix — это такой протокол для мессенджера, есть несколько его реализаций, но, как водится, полноценная только одна. Протокол ругают за перетяжеленность, но matrix сегодня один из самых зрелых opensource‑вариантов для self‑hosted мессенджера.
Домен возьмем, естественно, example.com. Контейнер назовем matrix. Дадим ему реальный адрес: можно и с пробросом портов, но это отдельная возня. Предполагается, что вы уже умеете создавать контейнеры. Веб‑сервер nginx, но можно поставить любой другой.
Решение на видеосвязь
Передо мной стояла задача «в первую очередь звонки мобильник — мобильник».
Так что, LiveKit, только он. Все клиенты умеют в LiveKit, не все умеют в Jitsi. Возня с Jitsi оправдана, когда нам нужны интеграция с sip и запись аудиовидео «из коробки». Но, в принципе, можно интегрировать звонки с десктопа в телефонную сеть через jitsi.
Ставим зависимости
Предполагается, что example.com у нас развернут хотя бы заглушкой, там нужны будут.well‑known для информации о подключении
Из портов/пакетов
net‑im/py‑matrix‑synapse но есть нюанс (ниже)
www/npm‑node22 или более новый четный (LTS)
devel/git@lite клонировать репозитории
Свежий go из lang/goXXX
databases/py‑psycopg2 именно 2, если вы будете использовать postgres
www/nginx с обязательной поддержкой http2
Если вы собираете python без IPv6, то это вы зря. Соберите с IPv6. Даже если не слушать на IPv6-адресе, все равно поддержка нужна.
Дополнительно
Везде указана актуальная на 2026.07.12 версия. Проверяйте перед установкой текущую актуальную.
Аналогично с версией go, на момент написания это go126.
Вопросы запуска будут рассмотрены ниже.
matrix‑user‑verification‑service
git clone --branch v3.0.0 --depth 1 https://github.com/matrix-org/matrix-user-verification-service.git /usr/local/uvs &&\
cd /usr/local/uvs && npm install --omit=dev
Чттобы не тянуть кучу ненужных зависимостей.
livekit‑server
git clone --branch v1.13.3 --depth 1 \
https://github.com/livekit/livekit-server.git /usr/local/livekit && \
cd /usr/local/livekit && go126 build ./cmd/server
lk‑jwt‑service
git clone --branch v0.5.0 --depth 1 \
https://github.com/element-hq/lk-jwt-service.git /usr/local/lk-jwt-service && \
cd /usr/local/lk-jwt-service && \
go126 build -o lk-jwt-service .
synapse‑admin
С https://github.com/Awesome‑Technologies/synapse‑admin/releases/tag/0.11.4 (опять‑таки проверьте актуальную версию) берем synapse‑admin-0.11.4.tar.gz
Развертываем в /usr/local/www/synapse‑admin
Нюанс с версией synapse
В моем случае, Synapse 1.151 не давал работать с LiveKit (или это я где‑то запутался), так что поверх matrix‑из‑портов я сделал pip install --upgrade matrix-synapse==1.155.0 (ну или какая версия будет актуальна для вас). Так я получил rc‑script и актуальную версию кода.
Сертификаты
element.example.com если хотим свой веб‑клиент на отдельном поддомене.
не будем выделять livekit в отдельную сущность, он не настолько велик.
Клиенты
Element на десктопе и Element X на мобильном. Это вполне функционально. С LiveKit работает все. Настройка других клиентов оставляется читателю в качестве несложного самостоятельного упражнения.
Настройка nginx
Element Web
Берем релиз из https://github.com/element‑hq/element‑web/releases — ставим, например, в /usr/local/www/element
Настраиваем config.json
{
"default_server_config": {
"m.homeserver": {
"base_url": "https://matrix.example.com"
}
},
"disable_custom_urls": false,
"disable_guests": true,
"disable_login_language_selector": false,
"disable_3pid_login": false,
"force_verification": false,
"brand": "Element",
"integrations_ui_url": "https://scalar.vector.im/",
"integrations_rest_url": "https://scalar.vector.im/api",
"integrations_widgets_urls": [
"https://scalar.vector.im/_matrix/integrations/v1",
"https://scalar.vector.im/api",
"https://scalar-staging.vector.im/_matrix/integrations/v1",
"https://scalar-staging.vector.im/api"
],
"default_widget_container_height": 280,
"default_country_code": "GB",
"show_labs_settings": false,
"default_federate": true,
"default_theme": "light",
"room_directory": {
"servers": ["matrix.org"]
},
"enable_presence_by_hs_url": {
"https://matrix.org": false,
"https://matrix-client.matrix.org": false
},
"setting_defaults": {
"breadcrumbs": true
},
"features": {
"feature_group_calls": true
},
"element_call": {
"use_exclusively": true,
"participant_limit": 8,
"brand": "Element Call"
},
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
}
element_call.use_exclusively — значит, отключить старые звонки через jitsi. Совсем.
well‑known на example.com
Там у нас хранятся те же самые настройки но для внешних клиентов. Проще всего не делать отдельный файл, а прямо положить все в nginx.config
location = /.well-known/matrix/server {
default_type application/json;
add_header Access-Control-Allow-Origin *;
return 200
'{
"m.server": "matrix.example.com:443"
}';
}
location = /.well-known/matrix/client {
default_type application/json;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'X-Requested-With, Content-Type, Authorization';
return 200
'{
"m.homeserver": {
"base_url": "https://matrix.example.com"
},
"org.matrix.msc4143.rtc_foci": [
{
"type": "livekit",
"livekit_url": "wss://matrix.example.com",
"livekit_service_url": "https://matrix.example.com/\\_lk-jwt-service"
}
]
}';
}
Обработка путей на matrix.example.com
Сервисов и путей у нас много.
# livekit
location /twirp/ {
proxy_pass http://127.0.0.1:7880;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
location /rtc/ {
proxy_pass http://127.0.0.1:7880;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
# lk-jwt-service
location /_lk-jwt-service/ {
proxy_pass http://127.0.0.1:8080/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
}
# letsencrypt
location ^~ /.well-known/acme-challenge/ {
root /usr/local/www/nginx;
default_type "text/plain";
}
# matrix
location / {
proxy_pass http://127.0.0.1:8008;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
}
# matrix admin api
location /_synapse/admin {
proxy_pass http://127.0.0.1:8008;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_http_version 1.1;
}
# admin
location /synapse-admin {
alias /usr/local/www/synapse-admin;
index index.html;
}
После создания сертификатов, добавляем сервер для федерации.
server {
listen 8448 ssl;
http2 on;
server_name matrix.example.com:8448;
ssl_certificate /usr/local/etc/letsencrypt/live/matrix.example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /usr/local/etc/letsencrypt/live/matrix.example.com/privkey.pem; # managed by Certbot
include /usr/local/etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /usr/local/etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
location / {
proxy_pass http://127.0.0.1:8008;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
}
}
Настройка matrix
/usr/local/etc/matrix‑synapse/homeserver.yaml генерируется командой
python3.12 -m synapse.app.homeserver \
--server-name example.com \
--config-path /usr/local/etc/matrix-synapse/homeserver.yaml \
--generate-config \
--report-stats=no
При этом генерируется ключ для федерации. Потом к файлу нужно добавить, что у нас есть livekit и где его найти
experimental_features:
msc3266_enabled: true
msc4143_enabled: true
msc4140_enabled: true
max_event_delay_duration: 24h
rc_message:
per_second: 0.5
burst_count: 30
matrix_rtc:
transports:
- type: livekit
livekit_service_url: "https://matrix.example.com/\\_lk-jwt-service"
Правите настройки логов в файле /usr/local/etc/matrix‑synapse/example.org.log.config
handlers:
file:
class: logging.handlers.TimedRotatingFileHandler
formatter: precise
filename: /var/log/synapse/homeserver.log
Создаете каталог, даете права.
Создаете базу, даете доступы, прописываете в конфиг.
database:
name: psycopg2
args:
user: matrix
password: ***
database: matrix
host: host
port: 5432
cp_min: 5
cp_max: 10
# если у вас локаль в базе русская
allow_unsafe_locale: true
pid_file выставляете в /var/run/matrix-synapse/homeserver.pid
После этого проверяем пути, доступность для юзера synapse всего в /usr/local/etc/matrix‑synapse, правильность путей к медиахранилищу и собственно matrix у вас работает. Но в нем еще нет пользователей.
synapse‑admin
Нужно создать админа.
register_new_matrix_user -c /usr/local/etc/matrix-synapse/homeserver.yaml -u admin -p YOUR_PASSWORD --admin http://localhost:8008
Зайти под админом на synapse‑admin и создать пользователя.
Запуск дополнительных сервисов
Я делаю по олдскульному. daemontools и простейшие run‑scripts. Написание rc‑скриптов оставляется читателю.
Общая часть
cd /var/spool
# это для bash
for s in uvs livekit lk-jwt-service; do mkdir -p ${s}/log/main && chown nobody ${s}/log/main
cat > ${s}/log/run << EOF
#!/bin/sh
exec setuidgid nobody multilog t ./main
EOF
chmod a+x ${s}/log/run; done
и у нас есть три отличных логгера.
Настройка UVS
run для uvs
#!/bin/sh
cd /usr/local/uvs && exec npm start
Потом, естественно, chmod a+x для него
Настройка lk‑jwt‑service
Для начала, нужно сгенерировать ключи
/usr/local/livekit/server generate-keys
Потом создать run
#!/bin/sh
exec env \
LIVEKIT_URL="wss://matrix.example.com" \
LIVEKIT_KEY="API..." \
LIVEKIT_SECRET="Secret..." \
LIVEKIT_JWT_BIND=":8080" \
LIVEKIT_FULL_ACCESS_HOMESERVERS="example.com" \
/usr/local/lk-jwt-service/lk-jwt-service 2>&1
Наверное, правильнее через средства daemontools, но если не планируется массовое развертывание, то можно и так.
Настройка livekit
run:
#!/bin/sh
exec /usr/local/livekit/server --config /usr/local/livekit/config.yaml 2>&1
config.yaml
port: 7880
rtc:
tcp_port: 7881
port_range_start: 50000
port_range_end: 50200
use_external_ip: false
node_ip: your_ip_here
keys:
API: Secret
logging:
level: info
Зацепляем за svscan
ln -s /var/spool/livekit /var/spool/lk-jwt-service /var/spool/uvs /var/service
Запускаем svscan, проверяем, что все поднялось.
Результат
Как писали в журнале «Радио», схема, аккуратно собранная из исправных компонентов, начинает работать без наладки.
К этому надо бы добавить логин по QR, сервер идентичности и, наверное, что‑то еще, но это уже другая история.