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:
deytenit authored and GitHub committed 2026-10-25 15:21:09 +03:00
1 parent c6487dc258
commit b3638f4d63
111 files changed
+2350 -1512

No files matched your search

@@ -1,36 +1,36 @@
---
title: 'Joplin Web Deployment Guide'
description: 'Joplin Server & Web App deployment from scratch'
description: 'Joplin Server & Web App deployment from scratch'
createdDate: 2026-03-20
tags: ['self-hosting', 'guides', 'joplin']
---
This guide describes how to deploy a private note-taking infrastructure using the Joplin Server and its web client.
This guide describes how to deploy a private note-taking infrastructure using the Joplin Server and its web client.
## Why I Chose Joplin?
I have been using Joplin for a long time, and it has become my primary note-taking tool. There are several reasons why I chose it over other alternatives:
I have been using Joplin for a long time, and it has become my primary note-taking tool. There are several reasons why I chose it over other alternatives:
- **Local-First**: Notes are stored locally on your device, ensuring fast access and full ownership (especially when the internet is inaccessible).
- **Markdown Format**: Joplin uses Markdown for all notes, making it incredibly easy to export, import, or move your data to another platform if needed.
- **Easy Sharing**: The ability to share notes via the web makes collaboration or public sharing straightforward.
- **Backups**: Joplin provides robust backup options, giving me peace of mind that my data is safe.
- **Local-First**: Notes are stored locally on your device, ensuring fast access and full ownership (especially when the internet is inaccessible).
- **Markdown Format**: Joplin uses Markdown for all notes, making it incredibly easy to export, import, or move your data to another platform if needed.
- **Easy Sharing**: The ability to share notes via the web makes collaboration or public sharing straightforward.
- **Backups**: Joplin provides robust backup options, giving me peace of mind that my data is safe.
One thing that was missing for me was the ability to quickly add or view notes when I don't have access to my primary devices (for example, at work). This article provides the solution: a self-hosted web client.
One thing that was missing for me was the ability to quickly add or view notes when I don't have access to my primary devices (for example, at work). This article provides the solution: a self-hosted web client.
## Technical Stack Overview
1. **Joplin Server**: The synchronization server. It handles the Joplin sync protocol, account logic, and note synchronization across devices.
2. **Postgres**: The database. Essential for production performance.
3. **Joplin Web App**: A browser-based client built from the Joplin mobile app source code using React Native for Web.
1. **Joplin Server**: The synchronization server. It handles the Joplin sync protocol, account logic, and note synchronization across devices.
2. **Postgres**: The database. Essential for production performance.
3. **Joplin Web App**: A browser-based client built from the Joplin mobile app source code using React Native for Web.
## 1. The Deployment Stack
## 1. The Deployment Stack
This configuration is generic, uses **Docker Volumes**, and provides a minimal setup for deploying the full stack.
This configuration is generic, uses **Docker Volumes**, and provides a minimal setup for deploying the full stack.
### Main docker-compose.yml
This compose file is a minimal configuration to run the Joplin Server and the web app. It assumes you understand how to set up a reverse proxy, or better yet, already have your own Joplin setup.
This compose file is a minimal configuration to run the Joplin Server and the web app. It assumes you understand how to set up a reverse proxy, or better yet, already have your own Joplin setup.
```yaml
x-environment: &shared-environment
@@ -84,9 +84,9 @@ volumes:
### Dockerfile
Create an `app` directory and place this `Dockerfile` inside it to build the web client. We build our own image since the original authors don't provide one.
Create an `app` directory and place this `Dockerfile` inside it to build the web client. We build our own image since the original authors don't provide one.
While there are repositories with pre-built images, it's easy enough to just create our own.
While there are repositories with pre-built images, it's easy enough to just create our own.
```dockerfile
# Stage 1: Build
@@ -128,9 +128,9 @@ CMD ["nginx", "-g", "daemon off;"]
### Nginx configuration
Place this `nginx.conf` alongside the `Dockerfile` in the `app` directory. Joplin is an SPA, meaning it doesn't matter where it's deployed since all navigation is handled internally without location dependency. So it's alright to just deploy it on a path that doesn't overlap with the main server, such as `/app`.
Place this `nginx.conf` alongside the `Dockerfile` in the `app` directory. Joplin is an SPA, meaning it doesn't matter where it's deployed since all navigation is handled internally without location dependency. So it's alright to just deploy it on a path that doesn't overlap with the main server, such as `/app`.
> This is a pretty minimal configuration; it assumes your reverse proxy is good enough to cover all questionable items, but you can expand it as you like.
> This is a pretty minimal configuration; it assumes your reverse proxy is good enough to cover all questionable items, but you can expand it as you like.
```nginx
server {
@@ -161,7 +161,7 @@ server {
## 2. Configuration
Create a `.env` file in the same directory as your `docker-compose.yml`. **Do not skip the secret generation step below.**
Create a `.env` file in the same directory as your `docker-compose.yml`. **Do not skip the secret generation step below.**
```bash
# --- Database Credentials ---
@@ -171,7 +171,7 @@ SHARED_PASSWORD=generate_this_with_openssl
### Generating Secrets
Use `openssl` to easily generate secure, random strings for your `.env` entries:
Use `openssl` to easily generate secure, random strings for your `.env` entries:
```bash
# Generate SHARED_PASSWORD
@@ -180,7 +180,7 @@ openssl rand -hex 32
## 3. Deployment
Start your stack by running the following command:
Start your stack by running the following command:
```bash
docker compose up -d --build
@@ -188,33 +188,33 @@ docker compose up -d --build
## 4. Initial Server Setup
Before configuring the web app, you must initialize your Joplin Server:
Before configuring the web app, you must initialize your Joplin Server:
Follow the official guide: [Joplin Server README](https://github.com/laurent22/joplin/blob/dev/packages/server/README.md)
Follow the official guide: [Joplin Server README](https://github.com/laurent22/joplin/blob/dev/packages/server/README.md)
Essentially, you need to ensure that basic synchronization via the app is functional.
Essentially, you need to ensure that basic synchronization via the app is functional.
## 5. Web App Showcase & Setup
Once the web app is running at `https://example.com/app/`, you will be greeted by it.
Once the web app is running at `https://example.com/app/`, you will be greeted by it.
### About the Web App
### About the Web App
![Joplin Web App Interface](https://static.ermnvldmr.com/www/articles/2026/joplin-web-deployment-guide/joplin-web-interface.webp)
It is basically the same mobile Joplin app, but in-browser. It leverages the LocalStorage API for data handling. Everything is still local-first, so after logging in, it will take some time to synchronize all remote notes.
It is basically the same mobile Joplin app, but in-browser. It leverages the LocalStorage API for data handling. Everything is still local-first, so after logging in, it will take some time to synchronize all remote notes.
But most importantly: _The Joplin web interface allows you to view and edit your notes directly from the browser._
But most importantly: _The Joplin web interface allows you to view and edit your notes directly from the browser._
> It is said that it's only guaranteed to work on Chrome due to the required API compatibility; however, I have had great success with Firefox as well. Browsers are catching up quickly.
> It is said that it's only guaranteed to work on Chrome due to the required API compatibility; however, I have had great success with Firefox as well. Browsers are catching up quickly.
### Authentication Setup
To connect to your self-hosted Joplin Server, go to **Settings > Synchronization** and configure the following parameters:
To connect to your self-hosted Joplin Server, go to **Settings > Synchronization** and configure the following parameters:
- **Sync Target**: Joplin Server
- **Joplin Server URL**: `https://example.com`
- **Joplin Server Email**: `your-email@example.com` (the one you just created/configured)
- **Joplin Server Email**: `your-email@example.com` (the one you just created/configured)
- **Joplin Server Password**: `your-password`
![Joplin Web App Setup](https://static.ermnvldmr.com/www/articles/2026/joplin-web-deployment-guide/joplin-web-setup.webp)
@@ -1,36 +1,36 @@
---
title: 'Руководство по развертыванию Joplin Web'
description: 'Развертывание Joplin Server и веб-приложения с нуля'
title: 'Руководство по развёртыванию Joplin Web'
description: 'Развёртывание Joplin Server и веб-приложения с нуля'
createdDate: 2026-03-20
tags: ['self-hosting', 'guides', 'joplin']
---
Это руководство описывает, как развернуть приватную инфраструктуру для заметок, используя Joplin Server и его веб-клиент.
В этом руководстве разберём, как развернуть приватную инфраструктуру для заметок на базе Joplin Server и веб-клиента.
## Почему я выбрал Joplin?
## Почему я выбрал Joplin?
Я давно пользуюсь Joplin, и он стал моим основным инструментом для ведения заметок. Есть несколько причин, по которым я выбрал его среди других альтернатив:
Я давно пользуюсь Joplin как основным приложением для заметок. Вот почему я выбрал именно его:
- **Local-First**: Заметки хранятся локально на вашем устройстве, что обеспечивает быстрый доступ и полное владение данными (особенно когда интернет недоступен).
- **Формат Markdown**: Joplin использует Markdown для всех заметок, что позволяет невероятно легко экспортировать, импортировать или переносить данные на другую платформу при необходимости.
- **Удобный обмен**: Возможность делиться заметками через веб делает совместную работу или публичный доступ простыми.
- **Резервное копирование**: Joplin предоставляет надежные варианты резервного копирования, давая мне уверенность в сохранности моих данных.
- **Local-First**: заметки хранятся локально на устройстве. Доступ к ним мгновенный, а данные остаются под полным контролем даже без интернета.
- **Формат Markdown**: все заметки сохраняются в Markdown, поэтому их легко экспортировать, импортировать или перенести на другую платформу.
- **Удобный обмен**: заметками можно делиться через веб для совместной работы или публичного доступа.
- **Резервное копирование**: в Joplin встроены надёжные механизмы бэкапа, поэтому за сохранность данных можно не беспокоиться.
Одной вещи мне не хватало — возможности быстро добавить или просмотреть заметки, когда у меня нет доступа к моим основным устройствам (например, на работе). Эта статья предлагает решение: самостоятельно размещенный (self-hosted) веб-клиент.
Мне не хватало лишь одного — возможности быстро открыть или записать заметку без доступа к основным устройствам (например, с рабочего компьютера). Решение — собственный (self-hosted) веб-клиент.
## Обзор технологического стека
1. **Joplin Server**: Сервер синхронизации. Он обрабатывает протокол синхронизации Joplin, логику учетных записей и синхронизацию заметок между устройствами.
2. **Postgres**: База данных. Необходима для производительности в рабочей среде.
3. **Joplin Web App**: Браузерный клиент, созданный из исходного кода мобильного приложения Joplin с использованием React Native for Web.
1. **Joplin Server**: сервер синхронизации. Отвечает за протокол обмена данными, учётные записи и синхронизацию заметок между устройствами.
2. **Postgres**: база данных. Обеспечивает высокую производительность и стабильность в рабочей среде.
3. **Joplin Web App**: браузерный клиент, собранный из исходного кода мобильного приложения Joplin с помощью React Native for Web.
## 1. Стек развертывания
## 1. Стек развёртывания
Эта конфигурация является универсальной, использует **Docker Volumes** и предоставляет минимальную настройку для развертывания полного стека.
Конфигурация универсальна, использует **Docker Volumes** и содержит минимум параметров для развёртывания полного стека.
### Основной docker-compose.yml
Этот compose-файл представляет собой минимальную конфигурацию для запуска Joplin Server и веб-приложения. Предполагается, что вы понимаете, как настроить обратный прокси-сервер, или, что еще лучше, у вас уже есть собственная установка Joplin.
В этом compose-файле собрана минимальная конфигурация для запуска Joplin Server и веб-приложения. Предполагается, что вы умеете настраивать обратный прокси-сервер или у вас уже развёрнут Joplin Server.
```yaml
x-environment: &shared-environment
@@ -84,9 +84,9 @@ volumes:
### Dockerfile
Создайте директорию `app` и поместите в нее этот `Dockerfile` для сборки веб-клиента. Мы собираем собственный образ, так как авторы оригинала его не предоставляют.
Создайте директорию `app` и поместите в неё `Dockerfile` для сборки веб-клиента. Собираем собственный образ, потому что разработчики Joplin пока не выпускают официальный контейнер.
Хотя существуют репозитории с готовыми образами, создать свой достаточно просто.
В сети встречаются сторонние образы, но собрать собственный надёжнее и проще:
```dockerfile
# Stage 1: Build
@@ -128,9 +128,9 @@ CMD ["nginx", "-g", "daemon off;"]
### Конфигурация Nginx
Поместите этот `nginx.conf` рядом с `Dockerfile` в директории `app`. Joplin — это SPA (Single Page Application), а значит, не имеет значения, где оно развернуто, так как вся навигация обрабатывается внутренне без зависимости от местоположения. Поэтому вполне нормально развернуть его по пути, который не пересекается с основным сервером, например `/app`.
Поместите `nginx.conf` рядом с `Dockerfile` в директорию `app`. Joplin Web — это SPA (Single Page Application): маршрутизация выполняется внутри браузера, поэтому клиент можно развернуть по любому пути, не конфликтующему с сервером синхронизации, например `/app`.
> Это довольно минималистичная конфигурация; предполагается, что ваш обратный прокси достаточно хорош, чтобы закрыть все спорные моменты, но вы можете расширить ее по своему усмотрению.
> Это базовая конфигурация: предполагается, что TLS и защиту периметра берёт на себя обратный прокси. При необходимости правила Nginx можно дополнить.
```nginx
server {
@@ -161,7 +161,7 @@ server {
## 2. Конфигурация
Создайте файл `.env` в той же директории, что и `docker-compose.yml`. **Не пропускайте шаг генерации секретов ниже.**
Создайте файл `.env` рядом с `docker-compose.yml`. **Обязательно сгенерируйте надёжный пароль перед запуском.**
```bash
# --- Учетные данные базы данных ---
@@ -171,16 +171,16 @@ SHARED_PASSWORD=generate_this_with_openssl
### Генерация секретов
Используйте `openssl`, чтобы легко создать безопасные случайные строки для записей в вашем `.env`:
Сгенерируйте пароль с помощью `openssl`:
```bash
# Генерация SHARED_PASSWORD
openssl rand -hex 32
```
## 3. Развертывание
## 3. Развёртывание
Запустите стек, выполнив следующую команду:
Запустите контейнеры:
```bash
docker compose up -d --build
@@ -188,38 +188,34 @@ docker compose up -d --build
## 4. Начальная настройка сервера
Перед настройкой веб-приложения необходимо инициализировать ваш Joplin Server:
Перед настройкой веб-клиента инициализируйте Joplin Server по [официальной инструкции](https://github.com/laurent22/joplin/blob/dev/packages/server/README.md): создайте учётную запись администратора и проверьте, что базовая синхронизация работает через десктопное или мобильное приложение.
Следуйте официальному руководству: [Joplin Server README](https://github.com/laurent22/joplin/blob/dev/packages/server/README.md)
## 5. Демонстрация и настройка веб-приложения
По сути, вам нужно убедиться, что базовая синхронизация через приложение работает.
После запуска откройте веб-клиент по адресу `https://example.com/app/`.
## 5. Демонстрация и настройка веб-приложения
Как только веб-приложение запустится по адресу `https://example.com/app/`, оно поприветствует вас.
### О веб-приложении
### О веб-приложении
![Интерфейс Joplin Web](https://static.ermnvldmr.com/www/articles/2026/joplin-web-deployment-guide/joplin-web-interface.webp)
По сути, это то же самое мобильное приложение Joplin, но в браузере. Оно использует LocalStorage API для обработки данных. Все по-прежнему работает по принципу local-first, поэтому после входа в систему потребуется время для синхронизации всех удаленных заметок.
Это интерфейс мобильного приложения Joplin, скомпилированный для браузера. Данные сохраняются в LocalStorage: приложение работает по принципу local-first, поэтому при первом входе потребуется время, чтобы скачать заметки с сервера.
Но самое главное: _Веб-интерфейс Joplin позволяет просматривать и редактировать заметки прямо из браузера._
Главная польза интерфейса — возможность просматривать и редактировать заметки прямо из браузера на любом устройстве без установки клиента.
> Говорят, что работа гарантирована только в Chrome из-за требований к совместимости API; однако я добился отличных результатов и в Firefox. Браузеры быстро догоняют друг друга.
> Разработчики заявляют гарантированную работу только в Chrome из-за требований к Web API, но клиент стабильно работает и в Firefox.
### Настройка аутентификации
Чтобы подключиться к вашему self-hosted серверу Joplin, перейдите в **Settings > Synchronization** и настройте следующие параметры:
Чтобы подключиться к своему серверу Joplin, откройте **Settings > Synchronization** и укажите параметры подключения:
- **Sync Target**: Joplin Server
- **Joplin Server URL**: `https://example.com`
- **Joplin Server Email**: `your-email@example.com` (тот, который вы только что создали/настроили)
- **Joplin Server Email**: `your-email@example.com` (созданный на предыдущем шаге)
- **Joplin Server Password**: `your-password`
![Настройка Joplin Web](https://static.ermnvldmr.com/www/articles/2026/joplin-web-deployment-guide/joplin-web-setup.webp)
_Наслаждайтесь!_
Теперь синхронизированные заметки доступны прямо в браузере.
## Ресурсы
@@ -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:
@@ -1,43 +1,43 @@
---
title: 'Руководство по развёртыванию Matrix-сервера'
description: 'Разбор архитектуры и развёртывание Synapse, Coturn, LiveKit SFU и Native Matrix RTC'
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 не ограничивается запуском одного веб-сервера. Matrix — открытый децентрализованный протокол для голосовой связи и обмена сообщениями со сквозным шифрованием в реальном времени. Если для текстовых чатов достаточно базового homeserver и базы данных, то современные мультимедийные возможности — от личных WebRTC-звонков 1:1 до групповых видеоконференций — требуют специализированных медиарелеев и мостов аутентификации.
В этой статье подробно разбирается устройство и пошаговое развёртывание производственного стека Matrix на базе **Synapse**, **PostgreSQL**, **Coturn**, **LiveKit SFU** и **lk-jwt-service**.
В статье разберём устройство и пошаговое развёртывание стека 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. **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 непосредственно на хост.
В конфигурации 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.
Для корректной передачи медиапотоков открываются следующие диапазоны портов:
- **Порты 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` содержит следующую конфигурацию:
Итоговый файл `docker-compose.yml`:
```yaml
networks:
@@ -142,15 +142,15 @@ services:
## 2. Конфигурация Homeserver (homeserver.yaml)
Synapse использует `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` регулярно удаляет кэш файлов с чужих серверов, сохраняя дисковое пространство (локальные файлы хранятся в течение года `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`.
- **Идентификация сервера (`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` выглядит следующим образом:
Полный файл `homeserver.yaml`:
```yaml
# Идентификация сервера
@@ -227,12 +227,12 @@ report_stats: false
## 3. Конфигурация LiveKit SFU (livekit.yaml)
LiveKit распределяет медиапотоки участников групповых звонков. Основные директивы в `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`.
- **`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`:
@@ -258,16 +258,16 @@ logging:
## 4. Конфигурация Coturn Relay (turnserver.conf)
Coturn обеспечивает ретрансляцию трафика для 1:1 звонков. Ключевые опции в `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`**: Блокирует попытки использовать релей для сканирования внутренних адресов сети.
- **`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` формируется следующим образом:
Конфигурация `turnserver.conf`:
```conf
listening-port=3478
@@ -293,11 +293,11 @@ no-multicast-peers
---
## 5. Переменные окружения и генерация секретов (.env)
## 5. Переменные окружения и генерация секретов (.env)
Вынос паролей и ключей в переменные окружения предотвращает их попадание в конфигурационные файлы и репозитории.
Вынос паролей и ключей в переменные окружения предотвращает их попадание в конфигурационные файлы и репозитории.
Секреты `DB_PASSWORD`, `LK_SECRET` и `TURN_SECRET` должны быть устойчивыми криптографическими строками. Мы используем `openssl` для их генерации.
Секреты `DB_PASSWORD`, `LK_SECRET` и `TURN_SECRET` должны быть криптографически стойкими строками. Для их генерации подойдёт утилита `openssl`.
Шаблон файла `.env`:
@@ -318,7 +318,7 @@ LK_SECRET=YOUR_LIVEKIT_SECRET
TURN_SECRET=YOUR_TURN_SHARED_SECRET
```
Генерация секретов через OpenSSL:
Генерация секретов с помощью OpenSSL:
```bash
# Выполните для создания DB_PASSWORD, LK_SECRET и TURN_SECRET
@@ -327,15 +327,15 @@ openssl rand -hex 32
---
## 6. Обратный прокси и автообнаружение (.well-known)
## 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 без ввода специальных портов пользователем.
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**:
```nginx
server {
@@ -396,11 +396,11 @@ server {
---
## 7. Создание аккаунтов и обслуживание
## 7. Создание аккаунтов и обслуживание
При отключенной публичной регистрации (`enable_registration: false`) новые аккаунты создаются вручную.
При отключённой публичной регистрации (`enable_registration: false`) новые аккаунты создаются вручную.
### Регистрация администратора через CLI
### Регистрация администратора через CLI
Выполните команду `register_new_matrix_user` внутри контейнера Synapse:
@@ -410,9 +410,9 @@ docker exec -it matrix-synapse register_new_matrix_user \
--user admin --password "SECURE_USER_PASSWORD" --admin
```
### Настройка SMTP для писем
### Настройка SMTP для писем
Для включения функции восстановления паролей и подтверждения почты добавьте блок `email` в `homeserver.yaml`:
Чтобы включить функцию восстановления паролей и подтверждения почты, добавьте блок `email` в `homeserver.yaml`:
```yaml
email:
@@ -1,67 +1,67 @@
---
title: 'Xray Subnet Mimicry (10.0.0.0/8)'
description: 'Building a distributed private network with Xray-core and reverse tunneling'
description: 'Building a distributed private network with Xray-core and reverse tunneling'
createdDate: 2026-03-20
tags: ['networking', 'guides', 'xray']
---
> **EDUCATIONAL PURPOSES ONLY**
> This project is designed as a technical demonstration of Xray-core's routing capabilities and private subnet mimicry. It is NOT intended for restriction evasion or illegal activities. Use this knowledge responsibly and in compliance with your local laws.
> This project is designed as a technical demonstration of Xray-core's routing capabilities and private subnet mimicry. It is NOT intended for restriction evasion or illegal activities. Use this knowledge responsibly and in compliance with your local laws.
This guide describes how to deploy a private, distributed communications infrastructure across distinct remote servers using a contiguous `10.0.0.0/8` private subnet mimicked via **Xray-core**, **TPROXY**, and **VLESS reverse tunneling**.
This guide describes how to deploy a private, distributed communications infrastructure across distinct remote servers using a contiguous `10.0.0.0/8` private subnet mimicked via **Xray-core**, **TPROXY**, and **VLESS reverse tunneling**.
---
## Technical Deep-Dive & Architecture
### The Virtual Subnet Concept
### The Virtual Subnet Concept
We are constructing a Layer 3 "Flat Network" over the public internet. Each server node acts as an authoritative gateway for its own `/16` segment within the `10.0.0.0/8` private address space:
We are constructing a Layer 3 "Flat Network" over the public internet. Each server node acts as an authoritative gateway for its own `/16` segment within the `10.0.0.0/8` private address space:
- **Server A (Hub / Portal)**: Owns `10.1.0.0/16`
- **Server A (Hub / Portal)**: Owns `10.1.0.0/16`
- **Server B (Spoke / Bridge)**: Owns `10.2.0.0/16`
- **Server C (Spoke / Bridge)**: Owns `10.3.0.0/16`
This setup enables seamless inter-node communication as if all servers and hosted containers resided on the same local physical network.
This setup enables seamless inter-node communication as if all servers and hosted containers resided on the same local physical network.
### The Science of Interception (TPROXY)
### The Science of Interception (TPROXY)
Unlike `REDIRECT`, which only supports TCP and modifies packet destination IP headers to match the proxy, **TPROXY** (Transparent Proxy) intercepts both TCP and UDP packets while preserving original source and destination IP headers.
Unlike `REDIRECT`, which only supports TCP and modifies packet destination IP headers to match the proxy, **TPROXY** (Transparent Proxy) intercepts both TCP and UDP packets while preserving original source and destination IP headers.
- **Marking**: When a packet destined for `10.x.x.x` enters the `PREROUTING` or `OUTPUT` iptables chain, the Mangle table marks it with `0x1`.
- **Preservation**: Xray's `tunnel` inbound listens with `"sockopt": { "tproxy": "tproxy" }`, allowing it to read the original destination IP from socket metadata and route packets transparently.
- **Marking**: When a packet destined for `10.x.x.x` enters the `PREROUTING` or `OUTPUT` iptables chain, the Mangle table marks it with `0x1`.
- **Preservation**: Xray's `tunnel` inbound listens with `"sockopt": { "tproxy": "tproxy" }`, allowing it to read the original destination IP from socket metadata and route packets transparently.
### Policy Routing (Table 100)
Firewall marks alone do not alter routing paths; standard Linux routing tables ignore firewall marks unless directed by **Policy Routing**:
Firewall marks alone do not alter routing paths; standard Linux routing tables ignore firewall marks unless directed by **Policy Routing**:
1. **The Rule (`ip rule`)**: `ip rule add fwmark 0x1 lookup 100 priority 100` tells the kernel to route any packet marked with `0x1` using custom routing table 100.
2. **The Table (`ip route`)**: Table 100 contains `ip route add local 0.0.0.0/0 dev lo table 100`, forcing marked packets onto the local loopback interface.
3. **The Handoff**: Xray listens on `127.0.0.1:12345` with TPROXY enabled, grabbing the packet from loopback.
4. **Loop Prevention**: Xray outbounds append `"sockopt": { "mark": 255 }` (`0xff`) to bypass TPROXY interception rules for its own generated traffic, preventing infinite routing loops.
1. **The Rule (`ip rule`)**: `ip rule add fwmark 0x1 lookup 100 priority 100` tells the kernel to route any packet marked with `0x1` using custom routing table 100.
2. **The Table (`ip route`)**: Table 100 contains `ip route add local 0.0.0.0/0 dev lo table 100`, forcing marked packets onto the local loopback interface.
3. **The Handoff**: Xray listens on `127.0.0.1:12345` with TPROXY enabled, grabbing the packet from loopback.
4. **Loop Prevention**: Xray outbounds append `"sockopt": { "mark": 255 }` (`0xff`) to bypass TPROXY interception rules for its own generated traffic, preventing infinite routing loops.
---
## 1. Setup Phase and Key Generation
## 1. Setup Phase and Key Generation
Generate four unique UUIDs to secure the VLESS tunnel connections between the Hub and Spokes:
Generate four unique UUIDs to secure the VLESS tunnel connections between the Hub and Spokes:
- `UUID_B_REVERSE`: Tunnel control for Server B (Bridge)
- `UUID_B_DIRECT`: Data traffic for Server B
- `UUID_C_REVERSE`: Tunnel control for Server C (Bridge)
- `UUID_C_DIRECT`: Data traffic for Server C
- `UUID_B_REVERSE`: Tunnel control for Server B (Bridge)
- `UUID_B_DIRECT`: Data traffic for Server B
- `UUID_C_REVERSE`: Tunnel control for Server C (Bridge)
- `UUID_C_DIRECT`: Data traffic for Server C
---
## 2. Host Networking and TPROXY (routing.sh and before.rules)
## 2. Host Networking and TPROXY (routing.sh and before.rules)
Before launching Xray containers, each server node requires kernel routing policy rules and UFW `mangle` firewall chains.
Before launching Xray containers, each server node requires kernel routing policy rules and UFW `mangle` firewall chains.
### A. Kernel Routing Initialization (routing.sh)
The shell script [`routing.sh`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/routing.sh) enables IPv4 forwarding, registers firewall mark `0x1` to lookup table 100, and routes all table 100 traffic to loopback (`dev lo`).
The shell script [`routing.sh`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/routing.sh) enables IPv4 forwarding, registers firewall mark `0x1` to lookup table 100, and routes all table 100 traffic to loopback (`dev lo`).
Run this script on **all** server nodes:
Run this script on **all** server nodes:
```bash
#!/usr/bin/env bash
@@ -93,13 +93,13 @@ echo "Routing configuration applied successfully."
### B. Hub Firewall Configuration (a/before.rules)
On **Server A (Hub)**, append the TPROXY rules to `/etc/ufw/before.rules` (after the initial `COMMIT` line).
On **Server A (Hub)**, append the TPROXY rules to `/etc/ufw/before.rules` (after the initial `COMMIT` line).
The rule logic performs the following steps:
1. **Excludes Local Subnet**: Packets targeting Server A's local subnet (`10.1.0.0/16`) are returned to standard processing.
The rule logic performs the following steps:
1. **Excludes Local Subnet**: Packets targeting Server A's local subnet (`10.1.0.0/16`) are returned to standard processing.
2. **Excludes External Traffic**: Packets outside `10.0.0.0/8` pass through unaffected.
3. **Excludes Xray Mark (`0xff`)**: Traffic generated by Xray itself is ignored to prevent routing loops.
4. **TPROXY Redirection**: Intercepts TCP and UDP traffic targeting `10.0.0.0/8` and redirects it to Xray on `127.0.0.1:12345` with mark `1`.
3. **Excludes Xray Mark (`0xff`)**: Traffic generated by Xray itself is ignored to prevent routing loops.
4. **TPROXY Redirection**: Intercepts TCP and UDP traffic targeting `10.0.0.0/8` and redirects it to Xray on `127.0.0.1:12345` with mark `1`.
Exact repository file: [`a/before.rules`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/a/before.rules)
@@ -139,13 +139,13 @@ COMMIT
-A ufw-before-input -s 10.1.0.0/16 -d 10.0.0.0/8 -m mark --mark 0x1 -j ACCEPT
```
### C. Spoke Firewall Configuration (b/before.rules and c/before.rules)
### C. Spoke Firewall Configuration (b/before.rules and c/before.rules)
On **Server B (Spoke)** and **Server C (Spoke)**, apply the node-specific `/etc/ufw/before.rules`.
On **Server B (Spoke)** and **Server C (Spoke)**, apply the node-specific `/etc/ufw/before.rules`.
For Server B (`10.2.0.0/16`), local traffic within `10.2.0.0/16` is exempted (`-d 10.2.0.0/16 -j RETURN`), while any packet destined for the rest of `10.0.0.0/8` (such as `10.1.x.x` or `10.3.x.x`) is intercepted via TPROXY and routed through the VLESS reverse tunnel back to Server A.
For Server B (`10.2.0.0/16`), local traffic within `10.2.0.0/16` is exempted (`-d 10.2.0.0/16 -j RETURN`), while any packet destined for the rest of `10.0.0.0/8` (such as `10.1.x.x` or `10.3.x.x`) is intercepted via TPROXY and routed through the VLESS reverse tunnel back to Server A.
Exact repository files: [`b/before.rules`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/b/before.rules) and [`c/before.rules`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/c/before.rules)
Exact repository files: [`b/before.rules`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/b/before.rules) and [`c/before.rules`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/c/before.rules)
```ini
*mangle
@@ -180,7 +180,7 @@ COMMIT
-A ufw-before-input -s 10.2.0.0/16 -d 10.0.0.0/8 -m mark --mark 0x1 -j ACCEPT
```
Apply the changes on each node with `sudo ufw reload`.
Apply the changes on each node with `sudo ufw reload`.
---
@@ -188,7 +188,7 @@ Apply the changes on each node with `sudo ufw reload`.
### A. Hub Configuration (a/xray.jsonc)
The Hub listens on public port 443 with VLESS and XTLS-Vision. It maps reverse tunnel incoming connections (`reverse-b`, `reverse-c`) to their respective subnet destination rules.
The Hub listens on public port 443 with VLESS and XTLS-Vision. It maps reverse tunnel incoming connections (`reverse-b`, `reverse-c`) to their respective subnet destination rules.
Exact repository file: [`a/xray.jsonc`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/a/xray.jsonc)
@@ -232,9 +232,9 @@ Exact repository file: [`a/xray.jsonc`](https://github.com/deytenit/xray-core-su
### B. Spoke Configuration (b/xray.jsonc)
The Spoke establishes VLESS client connections back to Server A (`A-EXTERNAL-IP`), maintaining a persistent reverse tunnel for incoming requests and forwarding outbound `10.0.0.0/8` traffic.
The Spoke establishes VLESS client connections back to Server A (`A-EXTERNAL-IP`), maintaining a persistent reverse tunnel for incoming requests and forwarding outbound `10.0.0.0/8` traffic.
Exact repository files: [`b/xray.jsonc`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/b/xray.jsonc) and [`c/xray.jsonc`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/c/xray.jsonc)
Exact repository files: [`b/xray.jsonc`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/b/xray.jsonc) and [`c/xray.jsonc`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/c/xray.jsonc)
```jsonc
{
@@ -272,9 +272,9 @@ Exact repository files: [`b/xray.jsonc`](https://github.com/deytenit/xray-core-s
## Resources & Reference
For the complete, runnable repository containing Docker Compose files ([`a/docker-compose.yaml`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/a/docker-compose.yaml) and [`b/docker-compose.yaml`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/b/docker-compose.yaml)), visit:
For the complete, runnable repository containing Docker Compose files ([`a/docker-compose.yaml`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/a/docker-compose.yaml) and [`b/docker-compose.yaml`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/b/docker-compose.yaml)), visit:
- [xray-core-subnet-mimicry Repository on GitHub](https://github.com/deytenit/xray-core-subnet-mimicry/tree/main)
- [xray-core-subnet-mimicry Repository on GitHub](https://github.com/deytenit/xray-core-subnet-mimicry/tree/main)
Technical Documentation & Guides:
@@ -1,67 +1,67 @@
---
title: 'Имитация подсети Xray (10.0.0.0/8)'
description: 'Создание распределенной частной сети с использованием Xray-core и обратного туннелирования'
title: 'Имитация подсети на базе Xray-core (10.0.0.0/8)'
description: 'Создание распределённой частной сети с помощью Xray-core и обратного туннелирования'
createdDate: 2026-03-20
tags: ['networking', 'guides', 'xray']
---
> **ТОЛЬКО ДЛЯ ОБРАЗОВАТЕЛЬНЫХ ЦЕЛЕЙ**
> Этот проект разработан как техническая демонстрация возможностей маршрутизации Xray-core и имитации частных подсетей. Он НЕ предназначен для обхода ограничений или незаконной деятельности. Используйте эти знания ответственно и в соответствии с местным законодательством.
> **ТОЛЬКО ДЛЯ ОБРАЗОВАТЕЛЬНЫХ ЦЕЛЕЙ**
> Этот проект разработан как техническая демонстрация возможностей маршрутизации Xray-core и имитации частных подсетей. Он не предназначен для обхода ограничений или незаконной деятельности. Используйте полученные знания ответственно и в рамках закона.
Это руководство описывает, как развернуть распределенную частную сеть между удаленными серверами, используя единое адресное пространство `10.0.0.0/8`, имитируемое с помощью **Xray-core**, **TPROXY** и **обратного VLESS-туннелирования**.
В этом руководстве разберём, как объединить удалённые серверы в распределённую частную сеть с единым адресным пространством `10.0.0.0/8`. Для этого используются **Xray-core**, **TPROXY** и **обратное VLESS-туннелирование**.
---
## Технический разбор и архитектура
## Архитектура и принцип работы
### Концепция виртуальной подсети
Мы создаем «плоскую сеть» третьего уровня (Layer 3) поверх публичного интернета. Каждый серверный узел выступает полномочным шлюзом для своего собственного отрезка `/16` из приватного пространства `10.0.0.0/8`:
Мы создаём «плоскую» сеть третьего уровня (Layer 3) поверх публичного интернета. Каждый узел служит шлюзом для своей подсети `/16` из приватного диапазона `10.0.0.0/8`:
- **Сервер A (Hub / Portal)**: Владеет `10.1.0.0/16`
- **Сервер B (Spoke / Bridge)**: Владеет `10.2.0.0/16`
- **Сервер C (Spoke / Bridge)**: Владеет `10.3.0.0/16`
- **Сервер A (Hub / Portal)**: `10.1.0.0/16`
- **Сервер B (Spoke / Bridge)**: `10.2.0.0/16`
- **Сервер C (Spoke / Bridge)**: `10.3.0.0/16`
Это обеспечивает прозрачное взаимодействие серверов и Docker-контейнеров, как если бы они находились в одной локальной физической сети.
Серверы и Docker-контейнеры взаимодействуют напрямую, будто находятся в одной локальной сети.
### Наука перехвата (TPROXY)
### Принцип перехвата трафика (TPROXY)
В отличие от `REDIRECT`, который поддерживает только TCP и подменяет IP-адрес назначения на адрес прокси, **TPROXY** (Transparent Proxy) перехватывает как TCP-, так и UDP-пакеты, сохраняя исходные IP-заголовки отправителя и получателя.
В отличие от `REDIRECT`, который работает только с TCP и подменяет IP-адрес назначения на адрес прокси, **TPROXY** (Transparent Proxy) перехватывает и TCP-, и UDP-пакеты, сохраняя исходные IP-заголовки отправителя и получателя.
- **Маркировка**: Когда пакет, предназначенный для `10.x.x.x`, попадает в цепочку `PREROUTING` или `OUTPUT` брандмауэра iptables, таблица Mangle помечает его меткой `0x1`.
- **Сохранение**: Входящий поток `tunnel` в Xray использует опцию сокета `"sockopt": { "tproxy": "tproxy" }`, позволяя извлекать оригинальный IP-адрес назначения из метаданных сокета и корректно маршрутизировать пакет.
- **Маркировка**: когда пакет для `10.x.x.x` попадает в цепочку `PREROUTING` или `OUTPUT` iptables, таблица `mangle` помечает его меткой `0x1`.
- **Сохранение адреса**: входящий обработчик `tunnel` в Xray с опцией сокета `"sockopt": { "tproxy": "tproxy" }` извлекает исходный IP-адрес назначения из метаданных сокета и маршрутизирует пакет дальше.
### Политика маршрутизации (Таблица 100)
### Политика маршрутизации (таблица 100)
Метки брандмауэра сами по себе не меняют маршрут следования пакета. Чтобы направить трафик в Xray, применяется **Policy Routing**:
Метки сами по себе не меняют маршрут пакета. Чтобы направить трафик в Xray, настраивается маршрутизация по политикам (**Policy Routing**):
1. **Правило (`ip rule`)**: `ip rule add fwmark 0x1 lookup 100 priority 100` предписывает ядру Linux использовать специальную таблицу маршрутизации 100 для пакетов с меткой `0x1`.
2. **Таблица (`ip route`)**: Таблица 100 содержит правило `ip route add local 0.0.0.0/0 dev lo table 100`, направляющее все помеченные пакеты на виртуальный интерфейс loopback (`dev lo`).
3. **Перехват**: Xray прослушивает порт `127.0.0.1:12345` с включенным TPROXY и подхватывает пакет с loopback.
4. **Защита от петель**: Для исходящего трафика самого Xray задается метка `"sockopt": { "mark": 255 }` (`0xff`), что исключает его из правил перехвата и предотвращает бесконечную рекурсию маршрутизации.
1. **Правило (`ip rule`)**: команда `ip rule add fwmark 0x1 lookup 100 priority 100` указывает ядру Linux направлять пакеты с меткой `0x1` в таблицу маршрутизации 100.
2. **Маршрут (`ip route`)**: таблица 100 содержит правило `ip route add local 0.0.0.0/0 dev lo table 100`, направляющее все помеченные пакеты на петлевой интерфейс (`dev lo`).
3. **Перехват**: Xray слушает порт `127.0.0.1:12345` с включённым TPROXY и принимает пакеты с loopback.
4. **Защита от петель**: исходящий трафик самого Xray маркируется меткой `"sockopt": { "mark": 255 }` (`0xff`). Это исключает его из правил перехвата и предотвращает зацикливание маршрутизации.
---
## 1. Подготовительный этап и генерация ключей
## 1. Подготовка и генерация ключей
Сгенерируйте 4 уникальных UUID для защиты обратных туннелей VLESS между Хабом и Узлами:
Сгенерируйте четыре уникальных UUID для защиты обратных туннелей VLESS между хабом и узлами:
- `UUID_B_REVERSE`: Служебный туннель управления для Сервера B (Bridge)
- `UUID_B_DIRECT`: Передача данных для Сервера B
- `UUID_C_REVERSE`: Служебный туннель управления для Сервера C (Bridge)
- `UUID_C_DIRECT`: Передача данных для Сервера C
- `UUID_B_REVERSE`: служебный туннель управления для сервера B (Bridge)
- `UUID_B_DIRECT`: передача данных для сервера B
- `UUID_C_REVERSE`: служебный туннель управления для сервера C (Bridge)
- `UUID_C_DIRECT`: передача данных для сервера C
---
## 2. Сетевая настройка хоста и TPROXY (routing.sh и before.rules)
## 2. Настройка маршрутизации хоста и TPROXY (routing.sh и before.rules)
До запуска контейнеров Xray на каждом узле необходимо активировать правила маршрутизации ядра и цепочки `mangle` в UFW.
Перед запуском контейнеров Xray на каждом узле нужно включить маршрутизацию в ядре и настроить цепочки `mangle` в UFW.
### A. Инициализация маршрутизации ядра (routing.sh)
### A. Настройка маршрутизации в ядре (routing.sh)
Скрипт [`routing.sh`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/routing.sh) включает пересылку IPv4-пакетов (ip_forward), связывает метку `0x1` с таблицей 100 и перенаправляет трафик таблицы 100 на интерфейс loopback (`dev lo`).
Скрипт [`routing.sh`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/routing.sh) включает пересылку IPv4-пакетов (`ip_forward`), связывает метку `0x1` с таблицей 100 и направляет трафик из неё на петлевой интерфейс (`dev lo`).
Запустите скрипт на **всех** серверах:
Запустите скрипт на **всех** серверах:
```bash
#!/usr/bin/env bash
@@ -91,17 +91,17 @@ fi
echo "Routing configuration applied successfully."
```
### B. Конфигурация брандмауэра Хаба (a/before.rules)
### B. Настройка файрвола на хабе (a/before.rules)
На **Сервере A (Hub)** добавьте правила TPROXY в конец файла `/etc/ufw/before.rules` (после первой директивы `COMMIT`).
На **сервере A (Hub)** добавьте правила TPROXY в конец файла `/etc/ufw/before.rules` (после первой директивы `COMMIT`).
Логика правил:
1. **Исключение локальной подсети**: Пакеты для `10.1.0.0/16` обрабатываются стандартно.
2. **Исключение внешнего трафика**: Трафик вне `10.0.0.0/8` не затрагивается.
3. **Исключение метки Xray (`0xff`)**: Собственный трафик Xray игнорируется для предотвращения зацикливания.
4. **TPROXY-перехват**: Запросы TCP и UDP к `10.0.0.0/8` направляются в Xray на `127.0.0.1:12345` с меткой `1`.
1. **Локальная подсеть**: пакеты для `10.1.0.0/16` обрабатываются стандартно.
2. **Внешний трафик**: пакеты за пределами `10.0.0.0/8` не затрагиваются.
3. **Метка Xray (`0xff`)**: собственный трафик Xray пропускается, чтобы исключить зацикливание.
4. **Перехват TPROXY**: TCP- и UDP-трафик к `10.0.0.0/8` направляется в Xray на `127.0.0.1:12345` с меткой `1`.
Файл в репозитории: [`a/before.rules`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/a/before.rules)
Файл в репозитории: [`a/before.rules`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/a/before.rules)
```ini
*mangle
@@ -139,13 +139,13 @@ COMMIT
-A ufw-before-input -s 10.1.0.0/16 -d 10.0.0.0/8 -m mark --mark 0x1 -j ACCEPT
```
### C. Конфигурация брандмауэра узлов Spoke (b/before.rules и c/before.rules)
### C. Настройка файрвола на узлах Spoke (b/before.rules и c/before.rules)
На **Сервере B (Spoke)** и **Сервере C (Spoke)** примените соответствующие `/etc/ufw/before.rules`.
На **сервере B (Spoke)** и **сервере C (Spoke)** примените соответствующие файлы `/etc/ufw/before.rules`.
Для Сервера B (`10.2.0.0/16`) локальный трафик внутри подсети `10.2.0.0/16` исключается (`-d 10.2.0.0/16 -j RETURN`), а любые пакеты к остальной части `10.0.0.0/8` (например, к `10.1.x.x` или `10.3.x.x`) перехватываются TPROXY и уходят через обратный VLESS-туннель на Сервер А.
Для сервера B (`10.2.0.0/16`) локальный трафик подсети `10.2.0.0/16` исключается (`-d 10.2.0.0/16 -j RETURN`), а пакеты к остальной части `10.0.0.0/8` (например, к `10.1.x.x` или `10.3.x.x`) перехватывает TPROXY и направляет через обратный VLESS-туннель на сервер A.
Файлы в репозитории: [`b/before.rules`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/b/before.rules) и [`c/before.rules`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/c/before.rules)
Файлы в репозитории: [`b/before.rules`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/b/before.rules) и [`c/before.rules`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/c/before.rules)
```ini
*mangle
@@ -180,17 +180,17 @@ COMMIT
-A ufw-before-input -s 10.2.0.0/16 -d 10.0.0.0/8 -m mark --mark 0x1 -j ACCEPT
```
Перезагрузите правила брандмауэра на каждом узле командой `sudo ufw reload`.
Перезагрузите правила файрвола на каждом узле командой `sudo ufw reload`.
---
## 3. Конфигурация узлов Xray-core (xray.jsonc)
## 3. Настройка узлов Xray-core (xray.jsonc)
### A. Конфигурация Хаба (a/xray.jsonc)
### A. Конфигурация хаба (a/xray.jsonc)
Хаб прослушивает публичный порт 443 по протоколам VLESS и XTLS-Vision. Он сопоставляет входящие соединения обратных туннелей (`reverse-b`, `reverse-c`) со свойствами маршрутизации для подсетей `/16`.
Хаб слушает публичный порт 443 по протоколам VLESS и XTLS-Vision. Он связывает входящие соединения обратных туннелей (`reverse-b`, `reverse-c`) с правилами маршрутизации для подсетей `/16`.
Файл в репозитории: [`a/xray.jsonc`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/a/xray.jsonc)
Файл в репозитории: [`a/xray.jsonc`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/a/xray.jsonc)
```jsonc
{
@@ -230,11 +230,11 @@ COMMIT
}
```
### B. Конфигурация Spoke (b/xray.jsonc)
### B. Конфигурация узлов Spoke (b/xray.jsonc)
Узел Spoke устанавливает клиенские соединения VLESS к Серверу A (`A-EXTERNAL-IP`), поддерживая постоянный обратный туннель для входящих запросов и передавая исходящий трафик `10.0.0.0/8`.
Узел Spoke устанавливает клиентские соединения VLESS к серверу A (`A-EXTERNAL-IP`), поддерживает постоянный обратный туннель для входящих запросов и передаёт исходящий трафик `10.0.0.0/8`.
Файлы в репозитории: [`b/xray.jsonc`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/b/xray.jsonc) и [`c/xray.jsonc`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/c/xray.jsonc)
Файлы в репозитории: [`b/xray.jsonc`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/b/xray.jsonc) и [`c/xray.jsonc`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/c/xray.jsonc)
```jsonc
{
@@ -270,14 +270,14 @@ COMMIT
---
## Ресурсы и ссылки
## Материалы и ссылки
Полный пример репозитория с конфигурациями Docker Compose ([`a/docker-compose.yaml`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/a/docker-compose.yaml) и [`b/docker-compose.yaml`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/b/docker-compose.yaml)):
Примеры конфигураций с Docker Compose ([`a/docker-compose.yaml`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/a/docker-compose.yaml) и [`b/docker-compose.yaml`](https://github.com/deytenit/xray-core-subnet-mimicry/blob/main/b/docker-compose.yaml)):
- [Репозиторий xray-core-subnet-mimicry на GitHub](https://github.com/deytenit/xray-core-subnet-mimicry/tree/main)
- [Репозиторий xray-core-subnet-mimicry на GitHub](https://github.com/deytenit/xray-core-subnet-mimicry/tree/main)
Техническая документация:
Документация:
- [Официальная документация Xray-core](https://xtls.github.io/)
- [Понимание TPROXY (блог Cloudflare)](https://blog.cloudflare.com/how-we-built-spectrum/)
- [Документация TPROXY в ядре Linux](https://www.kernel.org/doc/Documentation/networking/tproxy.txt)
- [Как устроен TPROXY (блог Cloudflare)](https://blog.cloudflare.com/how-we-built-spectrum/)
- [Документация по TPROXY в ядре Linux](https://www.kernel.org/doc/Documentation/networking/tproxy.txt)