Aster Открыть веб

Руководство · слепой релей · Ubuntu 24.04

Установка и настройка релея

Как собрать, установить и настроить слепой релей Aster на Ubuntu 24.04 LTS: автозапуск (systemd), запуск и остановка, TLS для браузерных клиентов и — при желании — федеративная сеть (mesh).

Слепой релей: только запечатанные конверты Хранение только в RAM Ubuntu 24.04 · systemd

На этой странице

Что такое релей Aster

Релей — это единственный серверный компонент Aster. Он слепой: хранит и пересылает только непрозрачные запечатанные конверты и публичные подписанные prekey-бандлы. Он не видит ни содержимого, ни отправителя, ни личности получателя (только непрозрачный почтовый ящик), и по умолчанию не пишет логов операций.

  • Только в RAM. Конверты нигде не сохраняются на диск. Единственный файл на диске — статический Noise-ключ релея (см. ниже). Выключенный или упавший сервер не содержит ни сообщений, ни метаданных.
  • Delete-on-fetch + TTL. Конверт удаляется, как только адресат его забрал; невыбранные истекают по TTL (максимум 365 дней, обычно раньше). Глубина одного почтового ящика ограничена (1024), есть периодическая чистка каждые 30 с.
  • Транспорт — Noise. Каждое соединение защищено Noise_NK. Клиент закрепляет (pins) публичный ключ релея при первом подключении (TOFU) — поэтому его нужно выдать клиентам вне сети.
  • Три слушателя (все опциональны, кроме нативного TCP): нативный TCP (Noise, для CLI/десктопа), WebSocket-мост ws/wss (для браузерных клиентов) и mesh-порт (репликация между релеями).
Модель доверия Релей остаётся слепым независимо от оператора. Отдельная граница доверия — доставка веб-клиента: тот, кто отдаёт браузеру страницу, теоретически может подменить код. Оператор, который держит только релей и позволяет клиентам закрепить его ключ, к этой границе отношения не имеет.

Требования

КомпонентЗначение
ОСUbuntu 24.04 LTS (подойдёт любой systemd-дистрибутив)
Rust≥ 1.74 (edition 2021). Ставится через rustup ниже
Сборочные пакетыbuild-essential, pkg-config, git, curl
RAMот 256 МБ на сам процесс; больше — под трафик (всё в памяти)
Порты (по умолчанию)9099/tcp — браузерный мост, 9977/tcp — нативный, 9097/tcp — mesh (если включён)
Праваsudo для установки юнита; сам сервис работает под непривилегированным пользователем

1Rust и системные пакеты

Установите инструменты сборки и Rust-тулчейн. Ставить Rust лучше под тем пользователем, под которым будете собирать (не root):

# системные пакеты для сборки
sudo apt update
sudo apt install -y build-essential pkg-config git curl

# Rust через rustup (стабильный тулчейн)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source "$HOME/.cargo/env"
rustc --version   # должно быть 1.74 или новее

2Сборка релея

Получите исходники Aster (репозиторий проекта) и соберите только серверный крейт в release-режиме:

# перейдите в каталог с исходниками Aster
cd aster

# собрать ТОЛЬКО бинарь релея (оптимизированный)
cargo build --release -p aster-server

Готовый бинарь появится по пути target/release/aster-server. Это самодостаточный исполняемый файл — его можно скопировать на сервер, где Rust не нужен.

Быстрый локальный запуск (для проверки) В репозитории есть scripts/run-relay.sh — он собирает и поднимает релей на [::]:9977 (нативный) + [::]:9099 (ws-мост), dual-stack IPv4+IPv6. Удобно, чтобы убедиться, что всё собирается и слушает, перед установкой в systemd.

3Установка бинаря и юнита

Скопируйте бинарь в /opt/aster и установите готовый закалённый systemd-юнит deploy/aster-relay.service:

# бинарь → /opt/aster/aster-server (executable)
sudo install -Dm755 target/release/aster-server /opt/aster/aster-server

# юнит → /etc/systemd/system/
sudo cp deploy/aster-relay.service /etc/systemd/system/

Что делает этот юнит из коробки:

  • Запускает релей под эфемерным непривилегированным пользователем (DynamicUser=yes) — uid меняется при каждом старте, нет домашнего каталога и оболочки.
  • Хранит только Noise-ключ в /var/lib/aster (StateDirectory, режим 0700) — никогда конверты.
  • Слушает нативный TCP на [::]:9977 (dual-stack IPv4+IPv6). Строки для ws/wss/mesh закомментированы — их вы включите на шаге 4.
  • Применяет строгий sandbox (ProtectSystem=strict, запрет new-privs, seccomp-фильтр, MemoryDenyWriteExecute и т.д.), запрещает core-dump и разрешает mlockall(), чтобы секреты не уходили в swap.

4Настройка (правка юнита)

Откройте юнит и настройте ExecStart и строки Environment= под свою задачу:

sudo systemctl edit --full aster-relay
# (или напрямую: sudo nano /etc/systemd/system/aster-relay.service)

Типовой случай — релей для браузерных клиентов (wss на 9099)

Браузер на HTTPS-странице может открыть только wss:// (не ws://). Включите ws-мост и TLS. Для сервера по IP или без своего домена — самоподписанный сертификат (клиент один раз подтвердит исключение):

# /etc/systemd/system/aster-relay.service — секция [Service]
ExecStart=/opt/aster/aster-server [::]:9977 /var/lib/aster/aster-relay.key
Environment=ASTER_WS=[::]:9099       # браузерный WebSocket-мост
Environment=ASTER_WSS=1              # обернуть его в TLS → wss://
Environment=ASTER_WSS_SAN=203.0.113.7  # ваш IP или домен в SAN самоподписанного серта

С доверенным сертификатом (свой домен + Let's Encrypt)

Если есть домен и сертификат — укажите пути к PEM, и тогда wss://<домен>:9099 будет доверенным без предупреждения:

Environment=ASTER_WS=[::]:9099
Environment=ASTER_WSS=1
Environment=ASTER_WSS_CERT=/etc/letsencrypt/live/relay.example.com/fullchain.pem
Environment=ASTER_WSS_KEY=/etc/letsencrypt/live/relay.example.com/privkey.pem
Доступ к сертификату при DynamicUser Сервис работает под эфемерным пользователем и с ProtectSystem=strict. Дайте ему читать сертификат — например, добавьте в юнит ReadOnlyPaths=/etc/letsencrypt и настройте права так, чтобы приватный ключ был читаем группой сервиса, либо кладите PEM-файлы в отдельный каталог с доступом на чтение. Проверяйте journalctl -u aster-relay после старта.

После любой правки юнита перечитайте конфигурацию systemd:

sudo systemctl daemon-reload
sudo systemctl restart aster-relay
Про порядок приоритетов Значения берутся так: переменная окруженияфайл --configпозиционный аргументзначение по умолчанию. Нативный TCP по умолчанию слушает только 127.0.0.1:9977 — чтобы принимать удалённых нативных клиентов, нужен [::]:9977 (как в юните).

5Автозапуск

Включите автозапуск при загрузке и сразу стартуйте сервис одной командой:

sudo systemctl enable --now aster-relay

enable добавляет в автозапуск (WantedBy=multi-user.target), --now — стартует немедленно. Проверьте, что сервис жив:

systemctl is-enabled aster-relay   # → enabled
systemctl is-active  aster-relay   # → active

Убрать из автозапуска (и остановить):

sudo systemctl disable --now aster-relay

Запуск, остановка, перезапуск

ДействиеКоманда
Запуститьsudo systemctl start aster-relay
Остановитьsudo systemctl stop aster-relay
Перезапуститьsudo systemctl restart aster-relay
Статусsystemctl status aster-relay
В автозапускsudo systemctl enable aster-relay
Из автозапускаsudo systemctl disable aster-relay
Логи (в реальном времени)journalctl -u aster-relay -f
Последние 50 строкjournalctl -u aster-relay -n 50 --no-pager
Перезапуск сбрасывает все сообщения в пути Релей хранит конверты только в RAM. restart/stop стирает всё, что ещё не было забрано адресатами. Это by design (ничего не остаётся на диске), но перезапускайте осознанно. Noise-ключ на диске переживает перезапуск — закреплённый клиентами идентификатор релея не меняется.

Ключ релея для клиентов

При первом старте релей генерирует статический Noise-ключ (файл /var/lib/aster/aster-relay.key) и печатает его публичную часть в лог. Именно этот 64-символьный hex клиенты закрепляют. Достаньте его:

journalctl -u aster-relay --no-pager | grep -m1 'server key'
# Aster blind relay
#   listening:  [::]:9977
#   server key: 937ee3c4…<всего 64 hex>
#   (clients pin this key; give it to them as <server_pubhex>)

Выдайте пользователям адрес релея вместе с этим ключом. В веб-клиенте сервер добавляется в Настройки → Серверы строкой вида:

wss://relay.example.com:9099?key=<server_pubhex>

Ключ фиксируется по TOFU при первом соединении: если позже кто-то на пути подменит ключ, клиент это не проглотит молча, а покажет баннер с двумя отпечатками — пользователь сверяет новый ключ вне сети и только тогда перезакрепляет.

Файрвол (ufw)

Откройте только те порты, которые реально используете:

sudo ufw allow 9099/tcp   # браузерный wss-мост (нужен почти всегда)
sudo ufw allow 9977/tcp   # нативный TCP — только если обслуживаете CLI/десктоп напрямую
sudo ufw allow 9097/tcp   # mesh — ТОЛЬКО если объединяете релеи (лучше ограничить IP пиров)
sudo ufw reload
Mesh-порт стоит открывать не всему миру, а только адресам релеев-пиров: sudo ufw allow from <peer-ip> to any port 9097 proto tcp. Линки mesh и так закрыты взаимной аутентификацией Noise_XX + allowlist, но сузить поверхность полезно.

Проверка работоспособности

# релей слушает нужные порты?
ss -ltnp | grep -E ':9099|:9977|:9097'

# стартовый баннер + ключ в логе
journalctl -u aster-relay -n 20 --no-pager

# локальная проверка TLS-рукопожатия ws-моста (для wss)
openssl s_client -connect 127.0.0.1:9099 -servername localhost </dev/null 2>/dev/null | head

Финальная проверка — добавить релей в клиент (wss://…:9099?key=…) и увидеть индикатор связи «в сети». Оператор не видит содержимого — это ожидаемо.

Обновление и откат

Обновление = пересобрать бинарь, положить новый и перезапустить. Ключ-файл трогать нельзя, иначе у всех клиентов сломается закреплённый идентификатор.

# на сборочной машине
cargo build --release -p aster-server

# на сервере: бэкап текущего бинаря (точка отката) и атомарная замена
sudo cp -a /opt/aster/aster-server /opt/aster/aster-server.bak.$(date +%Y%m%d-%H%M%S)
sudo install -m755 aster-server /opt/aster/aster-server.new
sudo mv -f /opt/aster/aster-server.new /opt/aster/aster-server
sudo systemctl restart aster-relay

# проверить, что ключ НЕ изменился (первые 8 hex должны совпасть с прежними)
journalctl -u aster-relay --no-pager | grep -m1 'server key'
Никогда не удаляйте /var/lib/aster/aster-relay.key Это закреплённый клиентами идентификатор релея. Если ключ пропадёт, релей сгенерирует новый, и клиенты откажутся подключаться до ручного перезакрепления (TOFU-mismatch). Откат: верните aster-server.bak.* и перезапустите сервис.

Справочник: переменные окружения

Все читаемые релеем переменные (задаются строками Environment= в юните). Флаги: 1/true/yes/on = включено, 0/false/no/off/пусто = выключено.

ПеременнаяНазначениеПример / по умолчанию
ASTER_ADDRАдрес нативного TCP-слушателя (Noise). Перекрывает 1-й позиционный аргумент.[::]:9977 · умолч. 127.0.0.1:9977
ASTER_KEYFILEПуть к статическому Noise-ключу (создаётся при первом старте). Перекрывает 2-й аргумент./var/lib/aster/aster-relay.key
ASTER_WSАдрес браузерного WebSocket-моста. Не задан = мост выключен.[::]:9099
ASTER_WSSОбернуть ws-мост в TLS (wss://) — нужно для HTTPS-страниц.1
ASTER_WSS_CERTPEM цепочка доверенного сертификата (Let's Encrypt). Вместе с ASTER_WSS_KEY.…/fullchain.pem
ASTER_WSS_KEYPEM приватного ключа к сертификату выше.…/privkey.pem
ASTER_WSS_SANSAN-имена/IP для самоподписанного серта (через запятую), чтобы wss://<ip> совпал.203.0.113.7,relay.local · умолч. localhost
ASTER_TLSTLS-камуфляж поверх нативного TCP (Noise внутри TLS 1.3).1 · умолч. выкл.
ASTER_MESHАдрес mesh-слушателя (федерация). Не задан = mesh-слушатель выключен.[::]:9097
ASTER_PEERSСписок пиров через запятую, куда дозваниваться (см. раздел Федерация).tcp://[2001:db8::2]:9097?key=<hex>
ASTER_MESH_QUEUE_MAXЛимит исходящей mesh-очереди на пира (RAM-бэкстоп, drop-oldest).умолч. 20000
ASTER_LOGПодробные пооперационные debug-логи. По умолчанию выкл. (минимум метаданных).1
ASTER_WAKE_URLОпциональный хук фонового пуша к нотифайеру (HTTP POST /wake). По умолчанию выкл.http://127.0.0.1:8790/wake
ASTER_WAKE_SECRETHMAC-секрет для этого хука.строка

Справочник: порты

ПортСлушательДля когоВключается
9977/tcpНативный TCP (Noise)CLI и десктоп-клиенты по нативному транспортувсегда (позиционный/ASTER_ADDR)
9099/tcpWebSocket-мост ws/wssБраузерные и PWA/веб-клиентыASTER_WS (+ASTER_WSS)
9097/tcpMesh (Noise_XX)Другие релеи (репликация)ASTER_MESH / ASTER_PEERS

Номера портов — соглашение, а не жёсткая привязка: адрес каждого слушателя задаётся своей переменной, можно выбрать любые порты. [::] = dual-stack IPv4+IPv6 в одном сокете; 0.0.0.0 = только IPv4.

Справочник: файл конфигурации

Вместо переменных окружения можно передать TOML-файл: aster-server --config /etc/aster/relay.toml. Приоритет: env > файл > позиционные аргументы > умолчания.

# /etc/aster/relay.toml
listen      = "[::]:9977"                 # нативный TCP (Noise)
keyfile     = "/var/lib/aster/aster-relay.key"
ws          = "[::]:9099"                 # браузерный мост (убрать = выключить)
wss         = true                        # TLS на мосту
tls         = false                       # TLS-камуфляж на нативном TCP
mesh_listen = "[::]:9097"                 # mesh-слушатель (убрать = выключить)
peers       = ["tcp://[2001:db8::2]:9097?key=<peer-pubhex>"]

Чтобы использовать файл в systemd, поменяйте строку запуска: ExecStart=/opt/aster/aster-server --config /etc/aster/relay.toml.

TLS-сертификаты

Самоподписанный (по умолчанию)

Если ASTER_WSS=1, а ASTER_WSS_CERT/KEY не заданы — релей создаёт постоянный самоподписанный сертификат рядом с ключ-файлом (в каталоге keyfile). Он переживает перезапуски, поэтому принятое браузером исключение не сбрасывается. Укажите свой IP/домен в ASTER_WSS_SAN, чтобы wss://<ip>:9099 проходил проверку имени (после одного предупреждения о самоподписи).

Доверенный (Let's Encrypt)

Есть домен → выпустите сертификат (например, certbot certonly --standalone -d relay.example.com, предварительно освободив 80-й порт) и укажите пути в ASTER_WSS_CERT/ASTER_WSS_KEY. Тогда wss://relay.example.com:9099 будет доверенным без предупреждений. Не забудьте про доступ DynamicUser к файлам (см. врезку в шаге 4) и про автопродление certbot.

TLS-камуфляж нативного TCP

ASTER_TLS=1 заворачивает нативный Noise-транспорт в TLS 1.3 — чтобы трафик внешне выглядел как обычный HTTPS. Это независимо от ws-моста.

Федерация: объединение релеев (mesh)

Релеи можно связать в сеть: тогда сообщение дойдёт до адресата, даже если отправитель и получатель на разных релеях или релей получателя был офлайн в момент отправки. Mesh реплицирует только непрозрачные конверты и публичные бандлы (слепота сохраняется), с delete-on-fetch и анти-энтропией.

Как это работает

  • Конверт расходится store-and-forward gossip-флудом с ограничением в 4 хопа + контентный дедуп; анти-энтропия (сверка каждые 30 с) догоняет то, что пропустил офлайн-релей.
  • Когда клиент забирает конверт с любого релея, тот рассылает Ack, останавливая повторные пересылки; авторитетное удаление — локальный delete-on-fetch на каждом релее (форжить чужой Ack бесполезно — это защита от цензуры).
  • Каждый линк — взаимный Noise_XX + статический allowlist ключей пиров; на входе — token-bucket от флуда, очереди на пира ограничены по RAM.

Настройка (на каждом релее)

Формат спецификации пира: tcp://[<ipv6>]:<port>?key=<server_pubhex> (можно и IPv4 без скобок). Ключ пира — это его server key из лога. Пиринг должен быть взаимным: пропишите друг друга на обеих сторонах.

# Релей A ([2001:db8::1]) — знает B и C
Environment=ASTER_MESH=[::]:9097
Environment=ASTER_PEERS=tcp://[2001:db8::2]:9097?key=<B-pubhex>,tcp://[2001:db8::3]:9097?key=<C-pubhex>

# Релей B ([2001:db8::2]) — знает A и C (взаимно!)
Environment=ASTER_MESH=[::]:9097
Environment=ASTER_PEERS=tcp://[2001:db8::1]:9097?key=<A-pubhex>,tcp://[2001:db8::3]:9097?key=<C-pubhex>

Откройте mesh-порт между релеями (ограничьте IP пиров) и перезапустите сервис. В стартовом логе появится строка mesh: enabled (N peer(s), listen=…).

Важно Mesh — это про асинхронные сообщения / бандлы / каналы. Реалтайм-звонки идут через отдельный conduit и работают в пределах одного релея (нет server-to-server пересылки живого аудио) — обоим участникам звонка нужен общий релей.

Безопасность и закалка

  • Готовый юнит уже применяет sandbox (DynamicUser, ProtectSystem=strict, seccomp @system-service, запрет new-privs, MemoryDenyWriteExecute, запрет core-dump, mlock). Если релей не стартует из-за слишком строгого SystemCallFilter — временно закомментируйте эту строку, проверьте journalctl, затем верните.
  • Встроенные лимиты процесса: до 4096 соединений всего, ≤64 с одного IP, ≤120 новых соединений с IP за 10 с, таймаут рукопожатия 10 с, idle-таймаут 180 с — защита от флуда и slow-loris.
  • Держите ASTER_LOG выключенным на проде (по умолчанию так) — это минимизирует метаданные в логах.
  • Раздавайте server key клиентам по доверенному каналу вне сети — на нём держится закрепление (pinning).
Честная формулировка Релей проверяемо слеп к содержимому и метаданным сообщений и держит их только в RAM. Это не делает всю систему «неуязвимой»: остаются граница доставки веб-клиента, анализ трафика на сетевом уровне и доверие к тому, кто выдал вам ключ релея. Формулируйте гарантии как проверяемые свойства, без абсолютов.

Диагностика

СимптомЧто смотреть
Сервис не стартуетjournalctl -u aster-relay -n 50 --no-pager; частая причина — слишком строгий seccomp или недоступный сертификат
Порт не слушаетсяss -ltnp | grep 9099; проверьте ASTER_WS и что daemon-reload сделан после правки юнита
Браузер не подключается по wssсамоподписанный серт без вашего IP в ASTER_WSS_SAN; смешанный контент (страница на http); файрвол на 9099
Клиент показал баннер смены ключаключ релея изменился (пересоздан keyfile или подмена на пути) — сверьте отпечаток вне сети
mesh не поднялсяв логе нет mesh: enabled; проверьте формат ASTER_PEERS, взаимность пиринга и открытость порта 9097

Aster — слепой RAM-only релей. Документ описывает установку на Ubuntu 24.04 LTS. Значения по умолчанию и переменные соответствуют бинарю aster-server и юниту deploy/aster-relay.service.