Обзор архитектуры
Для создания полностью автономного мессенджера на базе Matrix необходимо объединить несколько компонентов:
| Компонент | Назначение | Ключевые требования |
|---|---|---|
| Synapse | Основной homeserver, хранит события, управляет комнатами и пользователями | PostgreSQL, Redis (кеш), HTTPS‑терминация |
| OIDC‑провайдер (Keycloak, Auth0, Azure AD) | Внешняя аутентификация, единый вход (SSO) | OpenID Connect, поддержка динамических клиент‑регистраций |
| LiveKit + TURN | Реал‑тайм аудио/видео, NAT‑пробивание | WebRTC‑совместимый SFU, TURN‑сервер (coturn) |
| Подписанные обновления Android | Защита от подмены APK, гарантированный источник обновлений | RSA/ECDSA‑подпись, проверка в клиенте |
В результате получаем стек, где Synapse отвечает за протокол Matrix, OIDC берёт на себя управление пользователями, LiveKit обеспечивает VoIP‑связь, а подписи гарантируют целостность клиентского кода. Каждый слой имеет чётко определённую границу ответственности, что упрощает диагностику и масштабирование.
Установка Synapse и базовая конфигурация
-
Контейнеризация. Используем Docker‑compose, позволяющий управлять зависимостями в едином файле
docker-compose.yml. Основные сервисы:synapse,postgres,redis,nginx(обратный прокси) иcoturn. -
База данных. PostgreSQL 13+ рекомендуется из‑за поддержки JSONB‑полей, используемых в событиях Matrix. В
postgresзадаём параметрыmax_connections=200иshared_buffers=256MBдля нагрузки средних размеров. -
Кеш. Redis используется для ускорения запросов к токенам доступа и событийным потокам. Конфиг
redis.confоставляем по умолчанию, только включаемmaxmemory 256mbи политикуallkeys-lru. -
HTTPS. Nginx завершает TLS, предоставляя сертификаты от Let's Encrypt. В
nginx.confпрописываем правила:server { listen 443 ssl; 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; location / { proxy_pass http://synapse:8008; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; } } -
Synapse‑config.yaml. Важные секции:
server_name: matrix.example.compublic_baseurl: https://matrix.example.com/enable_registration: false(регистрация через OIDC)oidc: { enabled: true, client_id: "matrix", client_secret: "********", issuer: "https://oidc.example.com" }turn_uris: ["turn:turn.example.com:3478?transport=udp", "turns:turn.example.com:5349?transport=tcp"]turn_shared_secret: "supersecret"
Интеграция OIDC
Matrix поддерживает внешний провайдер идентификации через модуль sso. Для полной автоматизации процесса регистрации и логина:
-
Создание клиент‑регистрации в OIDC‑провайдере. В Keycloak задаём клиент
matrixс типомconfidential, включаемStandard FlowиDirect Access Grants. Redirect‑URI:https://matrix.example.com/_matrix/client/v3/login/sso/redirect. -
Настройка маппинга атрибутов. В OIDC‑провайдере указываем, какие claims будут использоваться в Matrix:
sub→user_id(внутренний ID)email→emailpreferred_username→displayname
-
Обновление
homeserver.yaml:sso: enabled: true provider: oidc oidc: client_id: matrix client_secret: ***** issuer: https://oidc.example.com/ redirect_uri: https://matrix.example.com/_matrix/client/v3/login/sso/redirect -
Тестирование. При переходе на
https://matrix.example.com/_matrix/client/v3/login/sso/redirectпользователь попадает на страницу входа OIDC, после чего получает токен, который Synapse валидирует и создаёт локальный Matrix‑аккаунт.
VoIP‑инфраструктура с LiveKit и TURN
LiveKit
LiveKit выступает в роли SFU (Selective Forwarding Unit), принимающего медиа‑потоки от участников и пересылающего их остальным. Для интеграции с Matrix:
-
Развёртывание. В
docker-compose.ymlдобавляем сервисlivekit:livekit: image: livekit/livekit-server:latest environment: - LIVEKIT_KEY=livekitkey - LIVEKIT_SECRET=livesecret - LIVEKIT_PORT=7880 ports: - "7880:7880" -
Конфигурация. В
livekit.yamlуказываемrtc: udp_port_range: 50000-60000 tcp_port_range: 60001-61000 turn: enabled: true address: turn.example.com port: 3478 secret: supersecret -
Связь с Element. Клиентская часть Element поддерживает WebRTC‑транзакции через сервер
livekit. Вelement-config.jsonзадаём:{ "livekitUrl": "wss://livekit.example.com", "livekitToken": "auto" }
TURN
Для обхода NAT‑ограничений требуется TURN‑сервер:
-
coturn разворачиваем отдельным контейнером, указываем
realm,static-auth-secretи открываем порты3478(UDP/TCP) и5349(TLS). -
Синхронизация с Synapse. В
homeserver.yamlдобавляемturn_urisиturn_shared_secret, как указано выше. Synapse будет автоматически генерировать временные TURN‑креды для каждого клиента.
Подписанные обновления Android‑клиента
Безопасность дистрибутива клиентского приложения достигается через криптографическую подпись:
-
Ключи. Генерируем RSA‑2048 (или ECDSA‑P256) ключи:
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048 openssl rsa -pubout -in private_key.pem -out public_key.pem -
Подпись APK. При сборке CI‑pipeline (GitHub Actions, GitLab CI) подписываем файл:
jarsigner -keystore mykeystore.jks -storepass $KS_PASS app-release.apk alias_name -
Создание манифеста. Генерируем
updates.json:{ "version": "2.3.1", "url": "https://downloads.example.com/app-release.apk", "signature": "<base64_of_sha256_signature>" }Подпись рассчитывается как
sha256(private_key, url + version). -
Валидация в клиенте. В Android‑приложении реализуем проверку:
val signature = Base64.decode(json.signature) val data = (json.url + json.version).toByteArray() val pubKey = KeyFactory.getInstance("RSA").generatePublic(X509EncodedKeySpec(publicKeyBytes)) val sig = Signature.getInstance("SHA256withRSA") sig.initVerify(pubKey) sig.update(data) if (!sig.verify(signature)) throw SecurityException("Invalid update signature") -
Обновление. Приложение периодически запрашивает
updates.json. При успешной проверке скачивает и устанавливает APK, минуя сторонние магазины.
Практические ограничения и рекомендации
- Производительность. При росте количества активных комнат Synapse начинает потреблять значительные ресурсы ОЗУ. Рекомендуется вынести репликацию событий в отдельный процесс
synapse-workersи использовать горизонтальное масштабирование черезsynapse‑федерацию. - OIDC‑синхронизация. При изменении атрибутов пользователя в провайдере OIDC требуется принудительно обновлять профиль в Matrix. Это можно автоматизировать через webhook‑listener, который вызывает
/_matrix/client/v3/profile/{userId}. - LiveKit‑нагрузка. Медиа‑трафик сильно нагружает CPU. При планировании масштабирования учитывайте количество одновременных видеоконференций и размещайте LiveKit на узлах с поддержкой AVX2.
- TURN‑безопасность. Статический секрет позволяет генерировать креды без отдельного аутентификационного сервиса, но в больших кластерах лучше использовать динамический механизм (REST‑API) для ограничения доступа.
- Подписи. Храните закрытый ключ в HSM или в защищённом хранилище CI. Утечка ключа приводит к полной компрометации цепочки обновлений.
Эти блоки образуют полностью автономный, безопасный и расширяемый мессенджер на основе Matrix, готовый к эксплуатации в продакшн‑условиях без привлечения облачных сервисов.