Архитектура

Стек технологий

  • VLESS+Reality (Xray-core) — прокси-протокол, который маскируется под легитимный TLS-сайт. Цензоры, проверяющие сервер, видят реальный сертификат (например, от microsoft.com). Подключиться могут только клиенты с правильным приватным ключом.
  • 3x-ui — веб-панель для управления Xray, развёрнутая как Docker-контейнер. Meridian управляет ею полностью через REST API.
  • nginx — единый процесс веб-сервера, обрабатывающий как SNI-маршрутизацию, так и TLS. Модуль stream слушает порт 443 и маршрутизирует трафик по SNI-имени хоста без завершения TLS. Модуль http на порту 8443 завершает TLS, обслуживает страницы подключения, обратно проксирует панель и трафик XHTTP/WSS к Xray. Сертификаты управляются acme.sh (сертификат Let’s Encrypt IP через профиль ACME shortlived в автономном режиме, сертификат домена в режиме домена).
  • Docker — запускает 3x-ui (который содержит Xray). Весь прокси-трафик проходит через контейнер.
  • Чистый Python provisionersrc/meridian/provision/ выполняет шаги развёртывания через SSH. Каждый шаг получает (conn, ctx) и возвращает StepResult.
  • uTLS — имитирует отпечаток TLS Client Hello Chrome, делая соединения неотличимыми от реального браузерного трафика.

Топология сервисов

Автономный режим (без домена)

flowchart TD
    Internet((Internet)) -->|Port 443| Nginx[nginx stream<br>SNI Router]
    Nginx -->|"SNI = reality_sni"| Xray["Xray Reality<br>:10443"]
    Nginx -->|"SNI = server IP"| NginxHTTP["nginx http<br>:8443"]
    NginxHTTP -->|/info-path| Page[Connection Page]
    NginxHTTP -->|/panel-path| Panel[3x-ui Panel]
    NginxHTTP -->|/xhttp-path| XrayXHTTP["Xray XHTTP<br>localhost"]
    Internet -->|Port 80| NginxACME["nginx<br>ACME challenges"]

nginx stream не завершает TLS. Он читает имя хоста SNI из TLS Client Hello и пересылает необработанный TCP-поток на соответствующий бэкенд.

acme.sh запрашивает сертификат Let’s Encrypt IP через профиль ACME shortlived (6-дневное действие, автоматическое обновление). При невозможности выпуска сертификата IP использует самоподписанный сертификат.

XHTTP работает на порту localhost и обратно проксируется nginx — дополнительного внешнего порта не требуется.

Режим домена

flowchart TD
    Internet((Internet)) -->|Port 443| Nginx[nginx stream<br>SNI Router]
    Nginx -->|"SNI = reality_sni"| Xray["Xray Reality<br>:10443"]
    Nginx -->|"SNI = domain"| NginxHTTP["nginx http<br>:8443"]
    NginxHTTP -->|/info-path| Page[Connection Page]
    NginxHTTP -->|/panel-path| Panel[3x-ui Panel]
    NginxHTTP -->|/xhttp-path| XrayXHTTP["Xray XHTTP<br>localhost"]
    NginxHTTP -->|/ws-path| XrayWSS["Xray WSS<br>localhost"]
    Internet -->|Port 80| NginxACME["nginx<br>ACME challenges"]
    Internet -.->|"CDN (Cloudflare)"| NginxHTTP

Режим домена добавляет VLESS+WSS как резервный путь CDN. Трафик проходит через CDN Cloudflare через WebSocket, что позволяет соединению работать даже если IP-адрес сервера заблокирован.

Топология ретранслятора

flowchart LR
    Client([Client]) -->|Port 443| Relay["Relay<br>(Realm TCP)"]
    Relay -->|Port 443| Exit["Exit Server<br>(abroad)"]
    Exit --> Internet((Internet))

Ретранслятор позволяет клиентам подключаться к внутреннему IP-адресу в своей стране, который затем пересылает трафик на выходной сервер за границей. Весь трафик между клиентом и выходом шифруется — ретранслятор видит только необработанный TCP и не может расшифровать содержимое. Все протоколы (Reality, XHTTP, WSS) работают прозрачно через ретранслятор.

Как работает протокол Reality

  1. Сервер генерирует пару ключей x25519. Открытый ключ используется с клиентами, приватный ключ остаётся на сервере.
  2. Клиент подключается к порту 443 с TLS Client Hello содержащим домен маскировки (например, www.microsoft.com) в качестве SNI.
  3. Для любого наблюдателя это выглядит как обычное HTTPS-соединение с microsoft.com.
  4. Если проверяющий отправит свой собственный Client Hello, сервер проксирует соединение на реальный microsoft.com — проверяющий видит действительный сертификат.
  5. Если клиент включает действительную аутентификацию (полученную из ключа x25519), сервер устанавливает VLESS-туннель.
  6. uTLS делает Client Hello идентичным Chrome в каждом байте, преодолевая TLS fingerprinting.

Структура Docker-контейнера

Docker-контейнер 3x-ui содержит:

  • Веб-панель 3x-ui — REST API на порту 2053 (внутренний)
  • Бинарник Xray в /app/bin/xray-linux-* (путь зависит от архитектуры)
  • База данных в /etc/x-ui/x-ui.db (SQLite, хранит конфигурации входящих и клиентов)
  • Конфигурация Xray управляется 3x-ui (не статический файл)

Meridian управляет 3x-ui полностью через REST API:

  • POST /login — аутентификация (form-urlencoded, возвращает session cookie)
  • POST /panel/api/inbounds/add — создание VLESS inbound
  • GET /panel/api/inbounds/list — список inbounds (проверка перед созданием)
  • POST /panel/setting/update — настройка параметров панели
  • POST /panel/setting/updateUser — смена учётных данных панели

Панель управления (3x-ui)

Meridian использует 3x-ui как веб-панель управления Xray. CLI автоматизирует всё, но вы также можете получить прямой доступ к веб-панели для мониторинга и расширенной настройки.

Как получить доступ

Панель доступна через nginx по случайному секретному HTTPS-пути — SSH-туннель не нужен. URL и учётные данные хранятся в локальном файле:

cat ~/.meridian/credentials/<IP>/proxy.yml

Найдите секцию panel:

panel:
  username: a1b2c3d4e5f6
  password: Xk9mP2qR7vW4nL8jF3hT6yBs
  web_base_path: n7kx2m9qp4wj8vh3rf6tby5e
  port: 2053

URL панели:

https://<ip-вашего-сервера>/n7kx2m9qp4wj8vh3rf6tby5e/

Возможности

  • Мониторинг трафика — статистика загрузки/выгрузки по клиентам
  • Просмотр inbounds — все настроенные протоколы VLESS (Reality, XHTTP, WSS)
  • Статус Xray — проверка работоспособности прокси-движка
  • Расширенная настройка — прямое изменение параметров Xray (для опытных пользователей)

Важно

  • web_base_path — случайная строка, это защита вашей панели. Не передавайте её посторонним.
  • Все команды meridian CLI используют тот же API панели.
  • Если вы измените настройки в панели напрямую, они могут быть перезаписаны при следующем meridian deploy.

Конфигурация nginx

Meridian записывает в /etc/nginx/conf.d/meridian-stream.conf и /etc/nginx/conf.d/meridian-http.conf (никогда в основной nginx.conf). Это позволяет Meridian сосуществовать с собственной конфигурацией пользователя.

nginx обрабатывает:

  • SNI-маршрутизацию на порту 443 (модуль stream, без завершения TLS)
  • Завершение TLS на порту 8443 (модуль http, сертификаты управляются acme.sh)
  • Обратный прокси для панели 3x-ui (на случайном пути)
  • Обслуживание страниц подключения (размещённые страницы с URL для обмена)
  • Обратный прокси для XHTTP-трафика к Xray (маршрутизация по пути, во всех режимах когда XHTTP включён)
  • Обратный прокси для WSS-трафика к Xray (только режим домена)

Назначение портов

ПортСервисРежим
443nginx stream (SNI router)Все
80nginx (ACME challenges)Все
10443Xray Reality (внутренний)Все
8443nginx http (внутренний)Все
localhostXray XHTTPКогда XHTTP включён
localhostXray WSSРежим домена
20533x-ui panel (внутренний)Все

Порты XHTTP и WSS видны только на localhost — nginx обратно проксирует их на порт 443.

Конвейер подготовки

Шаги выполняются последовательно через build_setup_steps(). Каждый шаг получает (conn, ctx) и возвращает StepResult.

ШагМодульНазначение
1InstallPackagescommon.pyПакеты ОС
2EnableAutoUpgradescommon.pyАвтоматические обновления
3SetTimezonecommon.pyUTC
4HardenSSHcommon.pyАутентификация только по ключу
5ConfigureBBRcommon.pyTCP congestion control
6ConfigureFirewallcommon.pyUFW: 22 + 80 + 443
7InstallDockerdocker.pyDocker CE
8Deploy3xuidocker.py3x-ui контейнер
9ConfigurePanelpanel.pyУчётные данные панели
10LoginToPanelpanel.pyAPI аутентификация
11CreateRealityInboundxray.pyVLESS+Reality
12CreateXHTTPInboundxray.pyVLESS+XHTTP
13CreateWSSInboundxray.pyVLESS+WSS (домен)
14VerifyXrayxray.pyПроверка здоровья
15InstallNginxservices.pySNI маршрутизация + TLS + reverse proxy
16DeployConnectionPageservices.pyQR коды + страница

Жизненный цикл учётных данных

  1. Генерация: случайные учётные данные (пароль панели, ключи x25519, UUID клиента)
  2. Сохранение локально: ~/.meridian/credentials/<IP>/proxy.yml — сохраняется ДО применения к серверу
  3. Применение: пароль панели изменён, входящие точки созданы
  4. Синхронизация: учётные данные скопированы в /etc/meridian/proxy.yml на сервере
  5. Повторные запуски: загружены из кэша, не регенерированы (идемпотентно)
  6. На разных машинах: загружены с сервера через SSH
  7. Удаление: удалены как с сервера, так и с локальной машины

Расположение файлов

На сервере

  • /etc/meridian/proxy.yml — учётные данные и список клиентов
  • /etc/nginx/conf.d/meridian-stream.conf — конфигурация nginx stream (SNI маршрутизация)
  • /etc/nginx/conf.d/meridian-http.conf — конфигурация nginx http (TLS, reverse proxy)
  • /etc/ssl/meridian/ — TLS сертификаты (управляются acme.sh)
  • Docker-контейнер 3x-ui — Xray + панель

На локальной машине

  • ~/.meridian/credentials/<IP>/ — кэшированные учётные данные для каждого сервера
  • ~/.meridian/servers — реестр серверов
  • ~/.meridian/cache/ — кэш проверки обновлений
  • ~/.local/bin/meridian — точка входа CLI (установлено через uv/pipx)
On this page