fix: cyrillic fonts, dev certs, page head, and ru-text typography (#67)
🤖 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`.
This commit is contained in:
1 parent
c6487dc258
commit
b3638f4d63
111 files changed
+2350
-1512
No files matched your search
@@ -1,43 +1,43 @@
|
||||
---
|
||||
title: 'Matrix Server Deployment Guide'
|
||||
description: 'Understanding and deploying Synapse, Coturn, LiveKit SFU, and Native Matrix RTC'
|
||||
description: 'Understanding and deploying Synapse, Coturn, LiveKit SFU, and Native Matrix RTC'
|
||||
createdDate: 2026-02-15
|
||||
tags: ['self-hosting', 'guides', 'matrix']
|
||||
---
|
||||
|
||||
Deploying a Matrix communications stack involves more than running a single web server. Matrix is an open, federated protocol for real-time, decentralized, end-to-end encrypted communication. While basic messaging requires only a homeserver and a database, modern voice and video capabilities—ranging from peer-to-peer 1:1 calls to multi-party group video conferences—require dedicated media relays and authentication bridges.
|
||||
Deploying a Matrix communications stack involves more than running a single web server. Matrix is an open, federated protocol for real-time, decentralized, end-to-end encrypted communication. While basic messaging requires only a homeserver and a database, modern voice and video capabilities—ranging from peer-to-peer 1:1 calls to multi-party group video conferences—require dedicated media relays and authentication bridges.
|
||||
|
||||
This article walks through the inner workings and deployment of a production-ready Matrix stack utilizing **Synapse**, **PostgreSQL**, **Coturn**, **LiveKit SFU**, and **lk-jwt-service**.
|
||||
This article walks through the inner workings and deployment of a production-ready Matrix stack utilizing **Synapse**, **PostgreSQL**, **Coturn**, **LiveKit SFU**, and **lk-jwt-service**.
|
||||
|
||||
---
|
||||
|
||||
## Technical Stack Architecture
|
||||
|
||||
To understand how a Matrix communications deployment functions, we must look at how each of its five core components handles data:
|
||||
To understand how a Matrix communications deployment functions, we must look at how each of its five core components handles data:
|
||||
|
||||
1. **Synapse**: The primary homeserver engine. It manages user authentication, room state, message synchronization, end-to-end encryption (E2EE) key distribution, and federation with other homeservers across the global Matrix network.
|
||||
2. **PostgreSQL**: The relational database powering Synapse. While Synapse supports SQLite for quick local experimentation, PostgreSQL is mandatory for production to handle concurrent database transactions, index room state, and maintain message history efficiently.
|
||||
3. **Coturn (STUN/TURN)**: The NAT traversal relay. When two users initiate a 1:1 call, their devices attempt a direct peer-to-peer WebRTC connection. If firewalls or symmetric NATs block direct traffic, Coturn acts as a relay server, forwarding encrypted audio and video packets between peers over UDP or TCP.
|
||||
4. **LiveKit SFU**: A high-performance Selective Forwarding Unit. Peer-to-peer meshes become bandwidth-prohibitive in group calls with three or more participants. LiveKit receives media streams from each speaker and forwards them to all other room members, reducing client upstream bandwidth.
|
||||
5. **lk-jwt-service**: The authentication bridge for Element Call and Element X Native Matrix RTC (governed by MSC4143 and MSC4186). When a user joins a group call in Element X, `lk-jwt-service` verifies their Matrix session with Synapse and issues a short-lived JSON Web Token (JWT), allowing them to authenticate with LiveKit automatically.
|
||||
6. **Reverse Proxy (Traefik / Nginx)**: The edge gateway. It terminates TLS certificates, handles WebSocket protocol upgrades for LiveKit signaling (`/livekit`), injects CORS headers for web clients, and serves Matrix client and federation auto-discovery JSON payloads (`.well-known`).
|
||||
1. **Synapse**: The primary homeserver engine. It manages user authentication, room state, message synchronization, end-to-end encryption (E2EE) key distribution, and federation with other homeservers across the global Matrix network.
|
||||
2. **PostgreSQL**: The relational database powering Synapse. While Synapse supports SQLite for quick local experimentation, PostgreSQL is mandatory for production to handle concurrent database transactions, index room state, and maintain message history efficiently.
|
||||
3. **Coturn (STUN/TURN)**: The NAT traversal relay. When two users initiate a 1:1 call, their devices attempt a direct peer-to-peer WebRTC connection. If firewalls or symmetric NATs block direct traffic, Coturn acts as a relay server, forwarding encrypted audio and video packets between peers over UDP or TCP.
|
||||
4. **LiveKit SFU**: A high-performance Selective Forwarding Unit. Peer-to-peer meshes become bandwidth-prohibitive in group calls with three or more participants. LiveKit receives media streams from each speaker and forwards them to all other room members, reducing client upstream bandwidth.
|
||||
5. **lk-jwt-service**: The authentication bridge for Element Call and Element X Native Matrix RTC (governed by MSC4143 and MSC4186). When a user joins a group call in Element X, `lk-jwt-service` verifies their Matrix session with Synapse and issues a short-lived JSON Web Token (JWT), allowing them to authenticate with LiveKit automatically.
|
||||
6. **Reverse Proxy (Traefik / Nginx)**: The edge gateway. It terminates TLS certificates, handles WebSocket protocol upgrades for LiveKit signaling (`/livekit`), injects CORS headers for web clients, and serves Matrix client and federation auto-discovery JSON payloads (`.well-known`).
|
||||
|
||||
---
|
||||
|
||||
## 1. The Docker Infrastructure (docker-compose.yml)
|
||||
## 1. The Docker Infrastructure (docker-compose.yml)
|
||||
|
||||
Organizing these services into containerized units ensures isolated environments, consistent startup ordering, and clean network mapping.
|
||||
Organizing these services into containerized units ensures isolated environments, consistent startup ordering, and clean network mapping.
|
||||
|
||||
In our setup, PostgreSQL includes a healthcheck (`pg_isready`) so that Synapse waits until database initialization is complete before attempting schema migrations. Services like Coturn, LiveKit, and `lk-jwt-service` run in network namespace mode (`network_mode: "service:synapse"`) or dedicated container networks, simplifying loopback communication while binding necessary host WebRTC and STUN/TURN ports directly.
|
||||
In our setup, PostgreSQL includes a healthcheck (`pg_isready`) so that Synapse waits until database initialization is complete before attempting schema migrations. Services like Coturn, LiveKit, and `lk-jwt-service` run in network namespace mode (`network_mode: "service:synapse"`) or dedicated container networks, simplifying loopback communication while binding necessary host WebRTC and STUN/TURN ports directly.
|
||||
|
||||
Notice that specific port ranges are opened for media traffic:
|
||||
- **Port 3478 & 5349 (TCP/UDP)**: Coturn STUN and TURN signaling.
|
||||
Notice that specific port ranges are opened for media traffic:
|
||||
- **Port 3478 & 5349 (TCP/UDP)**: Coturn STUN and TURN signaling.
|
||||
- **Port Range 49152-49172 (UDP)**: Coturn media relay channels.
|
||||
- **Port 7880 (TCP)**: LiveKit HTTP signaling and WebSockets.
|
||||
- **Port 7880 (TCP)**: LiveKit HTTP signaling and WebSockets.
|
||||
- **Port 7881 (TCP)**: LiveKit WebRTC TCP fallback.
|
||||
- **Port Range 50000-50020 (UDP)**: LiveKit SFU media channels.
|
||||
|
||||
The configuration below finalizes the infrastructure definition:
|
||||
The configuration below finalizes the infrastructure definition:
|
||||
|
||||
```yaml
|
||||
networks:
|
||||
@@ -142,15 +142,15 @@ services:
|
||||
|
||||
## 2. Homeserver Configuration (homeserver.yaml)
|
||||
|
||||
Synapse reads its operational rules from `homeserver.yaml`. Understanding key sections of this file prevents common administrative issues:
|
||||
Synapse reads its operational rules from `homeserver.yaml`. Understanding key sections of this file prevents common administrative issues:
|
||||
|
||||
- **Server Identity (`server_name`)**: This string defines your server's authority and user ID domain suffix (e.g., `@user:matrix.example.com`). Changing this later breaks existing user IDs and room history.
|
||||
- **Database Connection (`database`)**: Connects Synapse to PostgreSQL using the `psycopg2` driver. Setting `cp_min` and `cp_max` manages connection pooling efficiently under load.
|
||||
- **Media Retention (`media_retention`)**: Matrix room members frequently share images and files. Setting `remote_media_lifetime` to 14 days automatically purges cached media from federated servers, protecting your disk space while preserving local media (`local_media_lifetime: 365d`).
|
||||
- **VoIP Integration (`turn_uris` & `turn_shared_secret`)**: Informs Synapse of your Coturn installation. When two users place a call, Synapse uses `turn_shared_secret` to generate ephemeral, time-limited credentials, allowing clients to authenticate with Coturn securely.
|
||||
- **Native Matrix RTC (MSC4143 / MSC4186)**: Modern clients like Element X and Element Call use Matrix Specification Proposals MSC4143 (RTC Foci) and MSC4186 (LiveKit Call Authentication). Adding `extra_well_known_client_content` tells Matrix clients that group call authentication is handled by your `lk-jwt-service` endpoint (`https://matrix.example.com/livekit/jwt`).
|
||||
- **Server Identity (`server_name`)**: This string defines your server's authority and user ID domain suffix (e.g., `@user:matrix.example.com`). Changing this later breaks existing user IDs and room history.
|
||||
- **Database Connection (`database`)**: Connects Synapse to PostgreSQL using the `psycopg2` driver. Setting `cp_min` and `cp_max` manages connection pooling efficiently under load.
|
||||
- **Media Retention (`media_retention`)**: Matrix room members frequently share images and files. Setting `remote_media_lifetime` to 14 days automatically purges cached media from federated servers, protecting your disk space while preserving local media (`local_media_lifetime: 365d`).
|
||||
- **VoIP Integration (`turn_uris` & `turn_shared_secret`)**: Informs Synapse of your Coturn installation. When two users place a call, Synapse uses `turn_shared_secret` to generate ephemeral, time-limited credentials, allowing clients to authenticate with Coturn securely.
|
||||
- **Native Matrix RTC (MSC4143 / MSC4186)**: Modern clients like Element X and Element Call use Matrix Specification Proposals MSC4143 (RTC Foci) and MSC4186 (LiveKit Call Authentication). Adding `extra_well_known_client_content` tells Matrix clients that group call authentication is handled by your `lk-jwt-service` endpoint (`https://matrix.example.com/livekit/jwt`).
|
||||
|
||||
The complete `homeserver.yaml` configuration is structured as follows:
|
||||
The complete `homeserver.yaml` configuration is structured as follows:
|
||||
|
||||
```yaml
|
||||
# Server Identity
|
||||
@@ -227,14 +227,14 @@ report_stats: false
|
||||
|
||||
## 3. LiveKit SFU Configuration (livekit.yaml)
|
||||
|
||||
LiveKit powers group calls by receiving publisher streams and distributing them to subscribers. Key directives in `livekit.yaml` control media routing:
|
||||
LiveKit powers group calls by receiving publisher streams and distributing them to subscribers. Key directives in `livekit.yaml` control media routing:
|
||||
|
||||
- **`bind_addresses` & `port`**: Sets LiveKit to listen for HTTP signaling and WebSocket connections on port `7880`.
|
||||
- **`rtc.use_external_ip: true`**: Crucial for cloud server environments behind NAT. Instructs LiveKit to discover and advertise the host node's public IP address (`--node-ip`) to connecting WebRTC clients.
|
||||
- **`rtc.port_range_start` & `rtc.port_range_end`**: Restricts dynamic UDP WebRTC media allocation to ports `50000-50020`, keeping firewall policy simple.
|
||||
- **`room.auto_create: true`**: Allows rooms to be dynamically allocated whenever `lk-jwt-service` issues a valid access token.
|
||||
- **`bind_addresses` & `port`**: Sets LiveKit to listen for HTTP signaling and WebSocket connections on port `7880`.
|
||||
- **`rtc.use_external_ip: true`**: Crucial for cloud server environments behind NAT. Instructs LiveKit to discover and advertise the host node's public IP address (`--node-ip`) to connecting WebRTC clients.
|
||||
- **`rtc.port_range_start` & `rtc.port_range_end`**: Restricts dynamic UDP WebRTC media allocation to ports `50000-50020`, keeping firewall policy simple.
|
||||
- **`room.auto_create: true`**: Allows rooms to be dynamically allocated whenever `lk-jwt-service` issues a valid access token.
|
||||
|
||||
Here is the resulting `livekit.yaml`:
|
||||
Here is the resulting `livekit.yaml`:
|
||||
|
||||
```yaml
|
||||
port: 7880
|
||||
@@ -258,16 +258,16 @@ logging:
|
||||
|
||||
## 4. Coturn Relay Configuration (turnserver.conf)
|
||||
|
||||
Coturn handles fallback media relaying for 1:1 calls. When configuring `turnserver.conf`, several settings ensure reliability and security:
|
||||
Coturn handles fallback media relaying for 1:1 calls. When configuring `turnserver.conf`, several settings ensure reliability and security:
|
||||
|
||||
- **`listening-port=3478`**: Standard port for STUN/TURN requests over UDP and TCP.
|
||||
- **`external-ip`**: Tells Coturn its public IP address so it can communicate valid relay candidates to remote peers.
|
||||
- **`min-port` & `max-port`**: Limits dynamic UDP relay allocation to `49152-49172`.
|
||||
- **`use-auth-secret` & `static-auth-secret`**: Enables secret-based authentication matching `turn_shared_secret` in `homeserver.yaml`.
|
||||
- **`realm`**: The domain name associated with your TURN server, required for HMAC token verification.
|
||||
- **`no-multicast-peers`**: Prevents malicious users from abusing the TURN relay to probe internal private network addresses.
|
||||
- **`listening-port=3478`**: Standard port for STUN/TURN requests over UDP and TCP.
|
||||
- **`external-ip`**: Tells Coturn its public IP address so it can communicate valid relay candidates to remote peers.
|
||||
- **`min-port` & `max-port`**: Limits dynamic UDP relay allocation to `49152-49172`.
|
||||
- **`use-auth-secret` & `static-auth-secret`**: Enables secret-based authentication matching `turn_shared_secret` in `homeserver.yaml`.
|
||||
- **`realm`**: The domain name associated with your TURN server, required for HMAC token verification.
|
||||
- **`no-multicast-peers`**: Prevents malicious users from abusing the TURN relay to probe internal private network addresses.
|
||||
|
||||
Below is the complete `turnserver.conf` file:
|
||||
Below is the complete `turnserver.conf` file:
|
||||
|
||||
```conf
|
||||
listening-port=3478
|
||||
@@ -295,11 +295,11 @@ no-multicast-peers
|
||||
|
||||
## 5. Environment Setup (.env)
|
||||
|
||||
Storing credentials in environment variables keeps secret values out of configuration files and version control.
|
||||
Storing credentials in environment variables keeps secret values out of configuration files and version control.
|
||||
|
||||
Secrets such as `DB_PASSWORD`, `LK_SECRET`, and `TURN_SECRET` should be cryptographically random strings. We use `openssl` to generate secure 64-character hex strings.
|
||||
Secrets such as `DB_PASSWORD`, `LK_SECRET`, and `TURN_SECRET` should be cryptographically random strings. We use `openssl` to generate secure 64-character hex strings.
|
||||
|
||||
Here is the `.env` template file:
|
||||
Here is the `.env` template file:
|
||||
|
||||
```bash
|
||||
# Infrastructure
|
||||
@@ -318,7 +318,7 @@ LK_SECRET=YOUR_LIVEKIT_SECRET
|
||||
TURN_SECRET=YOUR_TURN_SHARED_SECRET
|
||||
```
|
||||
|
||||
Generating secrets with OpenSSL:
|
||||
Generating secrets with OpenSSL:
|
||||
|
||||
```bash
|
||||
# Generate DB_PASSWORD, LK_SECRET, and TURN_SECRET
|
||||
@@ -327,15 +327,15 @@ openssl rand -hex 32
|
||||
|
||||
---
|
||||
|
||||
## 6. Reverse Proxy and Client Discovery (.well-known)
|
||||
## 6. Reverse Proxy and Client Discovery (.well-known)
|
||||
|
||||
A reverse proxy routes external HTTPS traffic to internal services and satisfies protocol requirements for web clients:
|
||||
A reverse proxy routes external HTTPS traffic to internal services and satisfies protocol requirements for web clients:
|
||||
|
||||
1. **CORS Headers**: Web clients like Element Web or Element Call make cross-origin API requests. The proxy must return appropriate `Access-Control-Allow-*` headers.
|
||||
2. **WebSocket Proxying (`/livekit/`)**: LiveKit signaling requires persistent WebSocket connections (`Upgrade: $http_upgrade` and `Connection: "Upgrade"`).
|
||||
3. **Auto-Discovery (`/.well-known/matrix/client` & `/.well-known/matrix/server`)**: Matrix clients inspect these URIs upon user login to locate the homeserver API base URL and LiveKit JWT service without asking users to type custom port numbers or subdomains.
|
||||
1. **CORS Headers**: Web clients like Element Web or Element Call make cross-origin API requests. The proxy must return appropriate `Access-Control-Allow-*` headers.
|
||||
2. **WebSocket Proxying (`/livekit/`)**: LiveKit signaling requires persistent WebSocket connections (`Upgrade: $http_upgrade` and `Connection: "Upgrade"`).
|
||||
3. **Auto-Discovery (`/.well-known/matrix/client` & `/.well-known/matrix/server`)**: Matrix clients inspect these URIs upon user login to locate the homeserver API base URL and LiveKit JWT service without asking users to type custom port numbers or subdomains.
|
||||
|
||||
The following **Nginx** configuration puts all routing rules into practice:
|
||||
The following **Nginx** configuration puts all routing rules into practice:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
@@ -396,13 +396,13 @@ server {
|
||||
|
||||
---
|
||||
|
||||
## 7. Account Provisioning and Maintenance
|
||||
## 7. Account Provisioning and Maintenance
|
||||
|
||||
With public registration disabled (`enable_registration: false`), accounts are provisioned via Synapse's CLI tool.
|
||||
With public registration disabled (`enable_registration: false`), accounts are provisioned via Synapse's CLI tool.
|
||||
|
||||
### Admin User Registration
|
||||
|
||||
Run `register_new_matrix_user` inside the Synapse container to create your initial administrator account:
|
||||
Run `register_new_matrix_user` inside the Synapse container to create your initial administrator account:
|
||||
|
||||
```bash
|
||||
docker exec -it matrix-synapse register_new_matrix_user \
|
||||
@@ -412,7 +412,7 @@ docker exec -it matrix-synapse register_new_matrix_user \
|
||||
|
||||
### Transactional Email Configuration (SMTP)
|
||||
|
||||
To enable email verification and password reset functionality, append the `email` configuration block to `homeserver.yaml`:
|
||||
To enable email verification and password reset functionality, append the `email` configuration block to `homeserver.yaml`:
|
||||
|
||||
```yaml
|
||||
email:
|
||||
|
||||
Reference in new issue
Block a user