Лёгкий, самостоятельно размещаемый relay сервер для P2P-сети NETFORY
Операторы запускают его на своих серверах, а клиенты SmartNet могут по желанию маршрутизировать трафик через эти релеи - в дополнение к стандартным публичным релеям n0 (n0-computer).
Крейт:
smartnet-relay· бинарь:smartnet-relay· основа:iroh-relay = "1.0"(featureserver)
Два узла стараются установить прямое соединение (hole-punching через QUIC). Когда оба пира за "строгими" NAT/файрволами и пробить прямой путь не удаётся, трафик идёт через relay - промежуточный сервер, который просто пересылает зашифрованные пакеты между пирами. Relay не расшифровывает данные: вся E2EE-криптография SmartNet (X25519 + AES-256-GCM) остаётся между конечными узлами. Relay видит только зашифрованный транзит и помогает с обнаружением адресов (QAD - QUIC Address Discovery).
По умолчанию SmartNet-клиент использует публичные релеи n0. n1-relay - это
наша собственная релей-инфраструктура ("n1" = "network tier 1", релеи
сообщества SmartHoldem).
- Независимость - сеть продолжает работать, даже если публичные релеи n0 недоступны или ограничены.
- Скорость / география - релей рядом с пользователями (свой регион) даёт меньшую задержку при transit-доставке сообщений и блобов.
- Приватность - в режиме
relay_only(Settings > Network) клиент не раскрывает свой прямой IP пирам, а весь трафик идёт через релей. Хостинг собственного релея означает, что доверять приходится только своему серверу. - Контроль пропускной способности - вы сами управляете лимитами и ресурсами.
- Отказоустойчивость - можно поднять несколько релеев в разных дата-центрах и раздать клиентам их список; сеть сама выберет лучший.
| Возможность | Описание |
|---|---|
| Relay HTTP-эндпоинт | Полноценный smartnet-relay (/relay) для пересылки зашифрованного P2P-трафика. |
| QAD (QUIC Address Discovery) | Помогает пирам узнавать свои внешние адреса для hole-punching. |
| Plain-HTTP (без TLS) | Релей слушает чистый HTTP - TLS навешивается снаружи (reverse-proxy), что упрощает деплой и ротацию сертификатов. |
| Конфигурация через ENV | Хост и порт задаются переменными окружения, без правки кода. |
| Graceful shutdown | Корректная остановка по Ctrl-C (SIGINT) - релей завершает задачи и закрывает соединения. |
| Структурированные логи | tracing + tracing-subscriber с фильтром через RUST_LOG. |
| Минимальные зависимости | Только smartnet-relay (server) + tokio + tracing. Маленький бинарь, низкое потребление ресурсов. |
❗ Релей не хранит сообщения и не имеет доступа к ключам/контенту - он только пересылает зашифрованные пакеты. Это "тупой", но надёжный транзит.
/app/smartnet-relay/
├── Cargo.toml # зависимости (smartnet-relay feature "server", tokio, tracing)
├── src/
│ └── main.rs # точка входа: конфиг из ENV > Server::spawn > ждём Ctrl-C
└── README-RELAY.md # этот файл
Cargo.toml (ключевое):
[dependencies]
smartnet-relay = { version = "1.0", features = ["server"] } # feature "server" обязателен
tokio = { version = "1", features = ["rt-multi-thread", "macros", "signal"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
⚠️ Безfeatures = ["server"]модульiroh_relay::serverнедоступен (ошибкаerror[E0432]: unresolved import iroh_relay::server).
| Переменная | Назначение | По умолчанию |
|---|---|---|
SMARTNET_RELAY_HOST |
Адрес привязки (bind) HTTP-сервера | 0.0.0.0 |
SMARTNET_RELAY_PORT |
Порт привязки HTTP-сервера | 3340 |
RUST_LOG |
Уровень/фильтр логов (tracing) |
smartnet_relay=info,iroh_relay=info |
- Rust (stable) + Cargo - https://rustup.rs
- Открытый порт (по умолчанию
3340) на сервере / в файрволе.
cd /smartnet-relay
# Проверка компиляции
cargo check
# Релизная сборка (оптимизированный бинарь)
cargo build --release
# бинарь: ./target/release/smartnet-relay# С настройками по умолчанию (0.0.0.0:3340)
cargo run --release
# Или напрямую бинарём, с переопределением порта/хоста и логов
SMARTNET_RELAY_HOST=0.0.0.0 \
SMARTNET_RELAY_PORT=3340 \
RUST_LOG=smartnet_relay=info,iroh_relay=debug \
./target/release/smartnet-relayПри успешном старте в консоль выведется:
SmartNet relay (n1-relay) up on http://0.0.0.0:3340 - front with HTTPS and point clients at https://<your-host>
Остановка - Ctrl-C (graceful shutdown).
Сам релей слушает чистый HTTP. Для интернета поставьте перед ним reverse-proxy с TLS (Caddy / Nginx / Traefik). Клиентам раздаётся уже HTTPS-URL вашего хоста.
# /etc/caddy/Caddyfile
relay.smartholdem.io {
reverse_proxy 127.0.0.1:3340
}server {
listen 443 ssl;
server_name relay.smartholdem.io;
ssl_certificate /etc/letsencrypt/live/relay.smartholdem.io/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/relay.smartholdem.io/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3340;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; # WebSocket-апгрейд relay
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400s; # долгоживущие соединения
}
}Релей использует WebSocket-апгрейд, поэтому заголовки
Upgrade/Connectionи большойproxy_read_timeoutобязательны.
# /etc/systemd/system/smartnet-relay.service
[Unit]
Description=SmartNet Relay (n1-relay)
After=network.target
[Service]
Environment=SMARTNET_RELAY_HOST=127.0.0.1
Environment=SMARTNET_RELAY_PORT=3340
Environment=RUST_LOG=smartnet_relay=info,iroh_relay=info
ExecStart=/opt/smartnet-relay/smartnet-relay
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now smartnet-relay
sudo journalctl -u smartnet-relay -f # логиСовет: для нескольких релеев поднимите по экземпляру в разных регионах и раздайте клиентам все их URL - система выберет наилучший по задержке.
Пользователь подключает кастомные релеи прямо из приложения - без пересборки клиента.
Настройки > Сеть > SmartNet Relays (n1-relay)
(Settings.vue, блок data-testid="n1-relay-row"):
- Тоггл
n1-relay-toggle- вкл/выкл использование кастомных релеев. - Поле ввода
n1-relay-input- список URL релеев, по одному в строке (напримерhttps://relay.smartholdem.io). - Кнопка
save-n1-relay-btn- сохранить.
- Фронтенд (
Settings.vue) вызывает мостbridge.ts:getRelayConfig()- загружает текущие настройкиonMount.setRelayConfig(enabled, urls)- сохраняет тоггл и список URL.
- Tauri-команды (Rust,
p2p.rs, зарегистрированы вlib.rs):get_relay_config/set_relay_config- читают/пишут настройки в локальную sled-БД под ключамиcfg:n1_relay_enabledиcfg:n1_relay_urls(JSON-массив строк). Пустые строки отфильтровываются.
- Применение к iroh-endpoint (
p2p.rs,mod p2p_impl::apply_smartnet_relays): при инициализации P2P-узла, если тоггл включён, каждый валидный URL парсится вiroh::RelayUrlи добавляется в relay-map endpoint-а рядом со стандартными релеями n0:То есть кастомные релеи дополняют, а не заменяют публичные - связность сохраняется, даже если один из ваших релеев недоступен.let rc = RelayConfig::new(url.clone(), Some(RelayQuicConfig::default())); endpoint.insert_relay(url, Arc::new(rc)).await;
- За reverse-proxy с TLS:
https://relay.smartholdem.io(рекомендуется для прод). - Локальный тест без TLS:
http://<ip>:3340.
Релей не требует регистрации/ключей со стороны клиента. Менять список релеев можно в любой момент; новые настройки применяются при следующей инициализации P2P-узла (перезапуск приложения гарантированно подхватывает изменения).
# 1. Релей слушает порт?
ss -ltnp | grep 3340
# 2. HTTP отвечает (релей поднят)?
curl -i http://127.0.0.1:3340/
# 3. Через прокси (TLS) снаружи
curl -i https://relay.smartholdem.io/В приложении: включите тоггл, впишите URL, сохраните - в логах релея при
обращении клиентов появятся записи соединений (RUST_LOG=...=debug для деталей).
| Симптом | Причина / решение |
|---|---|
error[E0432]: unresolved import iroh_relay::server |
В Cargo.toml не включён feature server у smartnet-relay. |
| Клиент не подключается через релей | URL должен быть https://... (через TLS-прокси) либо http://ip:port в локальной сети; проверьте открытость порта и заголовки Upgrade/Connection в прокси. |
| Соединения рвутся через ~минуту | Увеличьте proxy_read_timeout (релей держит долгоживущие WS-соединения). |
| Нет логов | Задайте RUST_LOG=smartnet_relay=info,iroh_relay=debug. |
| Порт занят | Поменяйте SMARTNET_RELAY_PORT или освободите порт. |
- Релей пересылает только зашифрованный трафик; контент сообщений и ключи ему недоступны (E2EE остаётся на конечных узлах).
- Релей видит факт соединения и сетевые адреса транзита - поэтому хостите релей
на доверенной инфраструктуре, если включаете
relay_only. - Рекомендуется всегда выставлять релей наружу через HTTPS (TLS-прокси).