🤖 PR generated for branch `fix/cyrillic-fonts-dev-certs-and-page-head`.
### Changes Summary
- **Fonts**: Add Cyrillic glyph subsets for Lato, EB Garamond, and Fira
Code.
- **Dev**: Support remote Root CA and encrypted dev CA key in
`.env.dev`.
- **UI & Kits**: Add size variant to `Breadcrumbs` component and enlarge
`PageHead` breadcrumbs with tuned collapse scroll threshold.
- **ESLint**: Add `no-hanging-particles` i18n & markdown typography rule
with auto-fixer.
- **Content & i18n**: Apply `ru-text` editorial and typography polish
(em dashes, number ranges, «ё» restoration, non-breaking spaces) across
`services/www` and `services/docs`.
436 lines
21 KiB
Plaintext
436 lines
21 KiB
Plaintext
---
|
||
title: 'Руководство по развёртыванию Matrix-сервера'
|
||
description: 'Разбор архитектуры и развёртывание Synapse, Coturn, LiveKit SFU и Native Matrix RTC'
|
||
createdDate: 2026-02-15
|
||
tags: ['self-hosting', 'guides', 'matrix']
|
||
---
|
||
|
||
Развёртывание полноценного стека связи Matrix не ограничивается запуском одного веб-сервера. Matrix — открытый децентрализованный протокол для голосовой связи и обмена сообщениями со сквозным шифрованием в реальном времени. Если для текстовых чатов достаточно базового homeserver и базы данных, то современные мультимедийные возможности — от личных WebRTC-звонков 1:1 до групповых видеоконференций — требуют специализированных медиарелеев и мостов аутентификации.
|
||
|
||
В статье разберём устройство и пошаговое развёртывание стека Matrix для продакшена на базе **Synapse**, **PostgreSQL**, **Coturn**, **LiveKit SFU** и **lk-jwt-service**.
|
||
|
||
---
|
||
|
||
## Архитектура технического стека
|
||
|
||
Чтобы понять взаимодействие компонентов, разберём задачи каждого из шести ключевых компонентов:
|
||
|
||
1. **Synapse**: Основной движок homeserver. Управляет аутентификацией пользователей, состоянием комнат, синхронизацией сообщений, обменом ключами сквозного шифрования (E2EE) и федерацией с другими серверами в глобальной сети Matrix.
|
||
2. **PostgreSQL**: Реляционная база данных для Synapse. Если для коротких локальных тестов Synapse допускает SQLite, то в продакшене PostgreSQL обязателен для обработки параллельных транзакций, индексации комнат и истории сообщений.
|
||
3. **Coturn (STUN/TURN)**: Сервер ретрансляции для обхода NAT. При звонке 1:1 устройства пытаются установить прямое peer-to-peer WebRTC-соединение. Если между участниками есть симметричный NAT или фаервол, Coturn служит ретранслятором и передаёт зашифрованные аудио- и видеопакеты по протоколам UDP или TCP.
|
||
4. **LiveKit SFU**: Высокопроизводительный Selective Forwarding Unit. Соединение peer-to-peer становится неэффективным при групповых звонках от трёх участников. LiveKit принимает аудио- и видеопотоки каждого спикера и пересылает их остальным участникам, существенно экономя исходящий интернет-трафик клиентов.
|
||
5. **lk-jwt-service**: Мост аутентификации для Element Call и Element X Native Matrix RTC (стандарты MSC4143 и MSC4186). Когда пользователь входит в групповой звонок в Element X, `lk-jwt-service` проверяет его сессию в Synapse и генерирует временный токен JWT для подключения к комнате LiveKit.
|
||
6. **Обратный прокси (Traefik / Nginx)**: Входной шлюз. Терминирует SSL-сертификаты, обрабатывает WebSocket-соединения для сигнализации LiveKit (`/livekit`), проставляет заголовки CORS для веб-клиентов и отдаёт файлы автообнаружения `.well-known`.
|
||
|
||
---
|
||
|
||
## 1. Инфраструктура Docker (docker-compose.yml)
|
||
|
||
Контейнеризация обеспечит изоляцию сервисов, правильный порядок их запуска и предсказуемую сетевую связность.
|
||
|
||
В конфигурации Compose для PostgreSQL настроена проверка готовности (`pg_isready`), чтобы Synapse не запускался до полной инициализации базы данных. Дополнительные сервисы, такие как Coturn, LiveKit и `lk-jwt-service`, используют сетевой режим `network_mode: "service:synapse"` или выделенные сети контейнеров, что пробрасывает порты WebRTC и STUN/TURN непосредственно на хост.
|
||
|
||
Для корректной передачи медиапотоков открываются следующие диапазоны портов:
|
||
- **Порты 3478 и 5349 (TCP/UDP)**: Сигнализация Coturn STUN и TURN.
|
||
- **Диапазон 49152–49172 (UDP)**: Динамические каналы ретрансляции медиа Coturn.
|
||
- **Порт 7880 (TCP)**: HTTP-сигнализация и WebSockets в LiveKit.
|
||
- **Порт 7881 (TCP)**: Резервный TCP-порт для WebRTC в LiveKit.
|
||
- **Диапазон 50000–50020 (UDP)**: Каналы передачи медиа в LiveKit SFU.
|
||
|
||
Итоговый файл `docker-compose.yml`:
|
||
|
||
```yaml
|
||
networks:
|
||
matrix:
|
||
name: matrix-network
|
||
|
||
volumes:
|
||
synapse_data:
|
||
postgres_data:
|
||
|
||
services:
|
||
postgres:
|
||
image: postgres:16-alpine
|
||
container_name: matrix-db
|
||
environment:
|
||
POSTGRES_DB: synapse
|
||
POSTGRES_USER: synapse
|
||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||
POSTGRES_INITDB_ARGS: '--encoding=UTF-8 --lc-collate=C --lc-ctype=C'
|
||
volumes:
|
||
- postgres_data:/var/lib/postgresql/data
|
||
networks:
|
||
- matrix
|
||
healthcheck:
|
||
test: ['CMD-SHELL', 'pg_isready -U synapse -d synapse']
|
||
interval: 10s
|
||
timeout: 5s
|
||
retries: 5
|
||
start_period: 30s
|
||
restart: unless-stopped
|
||
|
||
synapse:
|
||
image: ghcr.io/element-hq/synapse:v1.146.0
|
||
container_name: matrix-synapse
|
||
depends_on:
|
||
postgres:
|
||
condition: service_healthy
|
||
environment:
|
||
SYNAPSE_SERVER_NAME: '${DOMAIN}'
|
||
SYNAPSE_REPORT_STATS: 'no'
|
||
SYNAPSE_CONFIG_PATH: '/data/homeserver.yaml'
|
||
volumes:
|
||
- ./homeserver.yaml:/data/homeserver.yaml:ro
|
||
- synapse_data:/data
|
||
networks:
|
||
- matrix
|
||
ports:
|
||
# Matrix Client & Federation HTTP API
|
||
- '8008:8008'
|
||
# Порты сигнализации Coturn STUN/TURN
|
||
- '3478:3478/tcp'
|
||
- '3478:3478/udp'
|
||
- '5349:5349/tcp'
|
||
- '5349:5349/udp'
|
||
# Диапазон UDP-портов для медиа-релея Coturn
|
||
- '49152-49172:49152-49172/udp'
|
||
# Порты LiveKit HTTP/WebSocket и WebRTC
|
||
- '7880:7880/tcp'
|
||
- '7881:7881/tcp'
|
||
- '50000-50020:50000-50020/udp'
|
||
restart: unless-stopped
|
||
|
||
coturn:
|
||
image: coturn/coturn:4.8-alpine
|
||
container_name: matrix-coturn
|
||
depends_on:
|
||
- synapse
|
||
volumes:
|
||
- ./turnserver.conf:/etc/coturn/turnserver.conf:ro
|
||
network_mode: 'service:synapse'
|
||
command: ['-c', '/etc/coturn/turnserver.conf']
|
||
restart: unless-stopped
|
||
|
||
livekit:
|
||
image: livekit/livekit-server:v1.9
|
||
container_name: matrix-livekit
|
||
depends_on:
|
||
- synapse
|
||
volumes:
|
||
- ./livekit.yaml:/etc/livekit.yaml:ro
|
||
environment:
|
||
LIVEKIT_KEYS: '${LK_KEY}: ${LK_SECRET}'
|
||
network_mode: 'service:synapse'
|
||
command: --config /etc/livekit.yaml --node-ip ${SERVER_IP}
|
||
restart: unless-stopped
|
||
|
||
lk-jwt:
|
||
image: ghcr.io/element-hq/lk-jwt-service:0.4.1
|
||
container_name: matrix-lk-jwt
|
||
depends_on:
|
||
- synapse
|
||
environment:
|
||
LK_JWT_PORT: 8080
|
||
LIVEKIT_URL: wss://${DOMAIN}/livekit
|
||
LIVEKIT_KEY: '${LK_KEY}'
|
||
LIVEKIT_SECRET: '${LK_SECRET}'
|
||
network_mode: 'service:synapse'
|
||
restart: unless-stopped
|
||
```
|
||
|
||
---
|
||
|
||
## 2. Конфигурация Homeserver (homeserver.yaml)
|
||
|
||
Synapse использует `homeserver.yaml` для определения правил работы. Разберём ключевые блоки:
|
||
|
||
- **Идентификация сервера (`server_name`)**: Определяет доменное имя сервера и суффикс ID пользователей (например, `@user:matrix.example.com`). Изменение этого имени в будущем приведёт к потере связей с другими серверами и поломке ID комнат.
|
||
- **Подключение к базе данных (`database`)**: Настраивает подключение к PostgreSQL через модуль `psycopg2`. Параметры `cp_min` и `cp_max` управляют пулом соединений при нагрузке.
|
||
- **Ротация медиафайлов (`media_retention`)**: Участники комнат постоянно отправляют фото и файлы. Параметр `remote_media_lifetime: 14d` очищает кэш файлов с чужих серверов каждые 14 дней, экономя дисковое пространство (локальные файлы хранятся в течение года: `local_media_lifetime: 365d`).
|
||
- **Интеграция VoIP (`turn_uris` и `turn_shared_secret`)**: Передаёт Synapse параметры Coturn. При звонке 1:1 Synapse с помощью `turn_shared_secret` генерирует временные логин и пароль для безопасного подключения к TURN-релею.
|
||
- **Native Matrix RTC (MSC4143 / MSC4186)**: Современные клиенты, такие как Element X и Element Call, используют спецификации MSC4143 (RTC Foci) и MSC4186 (LiveKit Call Authentication). Блок `extra_well_known_client_content` сообщает клиенту, что выпиской токенов для звонков занимается сервис `lk-jwt-service` по адресу `https://matrix.example.com/livekit/jwt`.
|
||
|
||
Полный файл `homeserver.yaml`:
|
||
|
||
```yaml
|
||
# Идентификация сервера
|
||
server_name: "matrix.example.com"
|
||
pid_file: /data/homeserver.pid
|
||
public_baseurl: "https://matrix.example.com"
|
||
|
||
# Слушатели (Listeners)
|
||
listeners:
|
||
- port: 8008
|
||
tls: false
|
||
type: http
|
||
x_forwarded: true
|
||
resources:
|
||
- names: [client, federation]
|
||
compress: false
|
||
|
||
# База данных
|
||
database:
|
||
name: psycopg2
|
||
args:
|
||
user: "synapse"
|
||
password: "YOUR_POSTGRES_PASSWORD"
|
||
database: "synapse"
|
||
host: "postgres"
|
||
cp_min: 5
|
||
cp_max: 10
|
||
|
||
# Безопасность и регистрация
|
||
enable_registration: false
|
||
enable_registration_captcha: false
|
||
registration_shared_secret: "YOUR_REGISTRATION_SHARED_SECRET"
|
||
|
||
# Хранение файлов и ротация
|
||
media_store_path: "/data/media_store"
|
||
max_upload_size: "50M"
|
||
max_image_pixels: "32M"
|
||
dynamic_thumbnails: true
|
||
|
||
media_retention:
|
||
remote_media_lifetime: 14d
|
||
local_media_lifetime: 365d
|
||
|
||
caches:
|
||
global_factor: 0.5
|
||
|
||
# VoIP / Coturn (Звонки 1:1)
|
||
turn_uris:
|
||
- "turn:matrix.example.com:3478?transport=udp"
|
||
- "turn:matrix.example.com:3478?transport=tcp"
|
||
turn_shared_secret: "YOUR_TURN_SHARED_SECRET"
|
||
turn_user_lifetime: 1h
|
||
turn_allow_guests: true
|
||
|
||
# Native Matrix RTC (MSC4143 / MSC4186 для звонков в Element X)
|
||
experimental_features:
|
||
msc3266_enabled: true
|
||
msc4222_enabled: true
|
||
|
||
serve_server_wellknown: true
|
||
extra_well_known_client_content:
|
||
"org.matrix.msc4186.stable": {"enabled": true}
|
||
"org.matrix.msc4143.rtc_foci": [
|
||
{
|
||
"type": "livekit",
|
||
"livekit_service_url": "https://matrix.example.com/livekit/jwt"
|
||
}
|
||
]
|
||
|
||
report_stats: false
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Конфигурация LiveKit SFU (livekit.yaml)
|
||
|
||
LiveKit распределяет медиапотоки участников групповых звонков. Основные директивы в `livekit.yaml`:
|
||
|
||
- **`bind_addresses` и `port`**: Задаёт служебный HTTP-порт и WebSockets на порту `7880`.
|
||
- **`rtc.use_external_ip: true`**: Необходимая опция для серверов за NAT: указывает LiveKit определять публичный IP-адрес хоста (`--node-ip`) и передавать его подключающимся клиентам.
|
||
- **`rtc.port_range_start` и `rtc.port_range_end`**: Ограничивают диапазон динамических UDP-портов WebRTC: от `50000` до `50020`.
|
||
- **`room.auto_create: true`**: Разрешает автоматическое создание комнат при получении валидного JWT-токена от `lk-jwt-service`.
|
||
|
||
Конфигурационный файл `livekit.yaml`:
|
||
|
||
```yaml
|
||
port: 7880
|
||
bind_addresses:
|
||
- 0.0.0.0
|
||
|
||
rtc:
|
||
tcp_port: 7881
|
||
port_range_start: 50000
|
||
port_range_end: 50020
|
||
use_external_ip: true
|
||
|
||
room:
|
||
auto_create: true
|
||
|
||
logging:
|
||
level: info
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Конфигурация Coturn Relay (turnserver.conf)
|
||
|
||
Coturn обеспечивает ретрансляцию трафика для звонков 1:1. Ключевые опции в `turnserver.conf`:
|
||
|
||
- **`listening-port=3478`**: Стандартный порт для приёма STUN/TURN-запросов по UDP и TCP.
|
||
- **`external-ip`**: Задаёт публичный IP-адрес сервера для корректного формирования адресов ретрансляции.
|
||
- **`min-port` и `max-port`**: Ограничивают диапазон динамических UDP-портов: от `49152` до `49172`.
|
||
- **`use-auth-secret` и `static-auth-secret`**: Включают авторизацию по секрету, совпадающему с `turn_shared_secret` в `homeserver.yaml`.
|
||
- **`realm`**: Доменное имя сервера, необходимое для проверки HMAC-токенов.
|
||
- **`no-multicast-peers`**: Блокирует попытки использовать релей для сканирования внутренних адресов сети.
|
||
|
||
Конфигурация `turnserver.conf`:
|
||
|
||
```conf
|
||
listening-port=3478
|
||
listening-ip=0.0.0.0
|
||
|
||
# Публичный IP-адрес вашего сервера
|
||
external-ip=203.0.113.10
|
||
|
||
min-port=49152
|
||
max-port=49172
|
||
|
||
fingerprint
|
||
use-auth-secret
|
||
static-auth-secret=YOUR_TURN_SHARED_SECRET
|
||
realm=matrix.example.com
|
||
|
||
total-quota=100
|
||
stale-nonce=600
|
||
log-file=stdout
|
||
simple-log
|
||
no-multicast-peers
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Переменные окружения и генерация секретов (.env)
|
||
|
||
Вынос паролей и ключей в переменные окружения предотвращает их попадание в конфигурационные файлы и репозитории.
|
||
|
||
Секреты `DB_PASSWORD`, `LK_SECRET` и `TURN_SECRET` должны быть криптографически стойкими строками. Для их генерации подойдёт утилита `openssl`.
|
||
|
||
Шаблон файла `.env`:
|
||
|
||
```bash
|
||
# Инфраструктура
|
||
DOMAIN=matrix.example.com
|
||
SERVER_IP=203.0.113.10
|
||
ADMIN_EMAIL=admin@example.com
|
||
|
||
# База данных
|
||
DB_PASSWORD=YOUR_POSTGRES_PASSWORD
|
||
|
||
# LiveKit (Групповые звонки)
|
||
LK_KEY=matrix_lk_key
|
||
LK_SECRET=YOUR_LIVEKIT_SECRET
|
||
|
||
# Coturn (Звонки 1:1)
|
||
TURN_SECRET=YOUR_TURN_SHARED_SECRET
|
||
```
|
||
|
||
Генерация секретов с помощью OpenSSL:
|
||
|
||
```bash
|
||
# Выполните для создания DB_PASSWORD, LK_SECRET и TURN_SECRET
|
||
openssl rand -hex 32
|
||
```
|
||
|
||
---
|
||
|
||
## 6. Обратный прокси и автообнаружение (.well-known)
|
||
|
||
Обратный прокси перенаправляет внешние запросы к нужным сервисам и выполняет требования веб-клиентов:
|
||
|
||
1. **Заголовки CORS**: Веб-клиенты Element Web и Element Call выполняют междоменные запросы. Прокси должен возвращать заголовки `Access-Control-Allow-*`.
|
||
2. **Проксирование WebSockets (`/livekit/`)**: Для работы LiveKit необходимо проксирование постоянных WebSocket-соединений (`Upgrade: $http_upgrade` и `Connection: "Upgrade"`).
|
||
3. **Автообнаружение (`/.well-known/matrix/client` и `/.well-known/matrix/server`)**: Клиенты Matrix запрашивают эти URL при входе, чтобы автоматически определить адрес сервера и сервиса LiveKit JWT без указания нестандартных портов вручную.
|
||
|
||
Пример конфигурации **Nginx**:
|
||
|
||
```nginx
|
||
server {
|
||
listen 443 ssl http2;
|
||
server_name matrix.example.com;
|
||
|
||
ssl_certificate /etc/letsencrypt/live/matrix.example.com/fullchain.pem;
|
||
ssl_certificate_key /etc/letsencrypt/live/matrix.example.com/privkey.pem;
|
||
|
||
# CORS-заголовки для веб-клиентов (Element Web / Element Call)
|
||
add_header Access-Control-Allow-Origin * always;
|
||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||
add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization, X-Matrix-User-ID" always;
|
||
|
||
if ($request_method = 'OPTIONS') {
|
||
return 204;
|
||
}
|
||
|
||
# API клиентов и федерации Matrix
|
||
location /_matrix {
|
||
proxy_pass http://127.0.0.1:8008;
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Forwarded-For $remote_addr;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
client_max_body_size 50M;
|
||
}
|
||
|
||
# Сигнализация LiveKit SFU (WebSockets)
|
||
location /livekit/ {
|
||
rewrite ^/livekit/(.*) /$1 break;
|
||
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;
|
||
}
|
||
|
||
# Сервис выписки JWT-токенов LiveKit для Element X
|
||
location /livekit/jwt/ {
|
||
rewrite ^/livekit/jwt/(.*) /$1 break;
|
||
proxy_pass http://127.0.0.1:8080;
|
||
proxy_set_header Host $host;
|
||
}
|
||
|
||
# Автообнаружение клиента Matrix (.well-known)
|
||
location /.well-known/matrix/client {
|
||
default_type application/json;
|
||
return 200 '{"m.homeserver":{"base_url":"https://matrix.example.com"},"org.matrix.msc4186.stable":{"enabled":true},"org.matrix.msc4143.rtc_foci":[{"type":"livekit","livekit_service_url":"https://matrix.example.com/livekit/jwt"}]}';
|
||
}
|
||
|
||
# Автообнаружение федерации Matrix (.well-known)
|
||
location /.well-known/matrix/server {
|
||
default_type application/json;
|
||
return 200 '{"m.server":"matrix.example.com:443"}';
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 7. Создание аккаунтов и обслуживание
|
||
|
||
При отключённой публичной регистрации (`enable_registration: false`) новые аккаунты создаются вручную.
|
||
|
||
### Регистрация администратора через CLI
|
||
|
||
Выполните команду `register_new_matrix_user` внутри контейнера Synapse:
|
||
|
||
```bash
|
||
docker exec -it matrix-synapse register_new_matrix_user \
|
||
-c /data/homeserver.yaml http://localhost:8008 \
|
||
--user admin --password "SECURE_USER_PASSWORD" --admin
|
||
```
|
||
|
||
### Настройка SMTP для писем
|
||
|
||
Чтобы включить функцию восстановления паролей и подтверждения почты, добавьте блок `email` в `homeserver.yaml`:
|
||
|
||
```yaml
|
||
email:
|
||
smtp_host: "smtp.example.com"
|
||
smtp_port: 587
|
||
smtp_user: "notifications@example.com"
|
||
smtp_pass: "YOUR_SMTP_PASSWORD"
|
||
require_transport_security: true
|
||
notif_from: "Matrix Server <notifications@example.com>"
|
||
```
|
||
|
||
---
|
||
|
||
## Ресурсы
|
||
|
||
- [Документация Synapse](https://element-hq.github.io/synapse/)
|
||
- [Документация LiveKit Server](https://docs.livekit.io/)
|
||
- [Element lk-jwt-service GitHub](https://github.com/element-hq/lk-jwt-service)
|
||
- [MSC4143: Native Matrix RTC Foci](https://github.com/matrix-org/matrix-spec-proposals/pull/4143)
|
||
- [MSC4186: LiveKit Call Authentication](https://github.com/matrix-org/matrix-spec-proposals/pull/4186)
|