Руководство · слепой релей · 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
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 |
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
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'
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_CERT | PEM цепочка доверенного сертификата (Let's Encrypt). Вместе с ASTER_WSS_KEY. | …/fullchain.pem |
ASTER_WSS_KEY | PEM приватного ключа к сертификату выше. | …/privkey.pem |
ASTER_WSS_SAN | SAN-имена/IP для самоподписанного серта (через запятую), чтобы wss://<ip> совпал. | 203.0.113.7,relay.local · умолч. localhost |
ASTER_TLS | TLS-камуфляж поверх нативного 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_SECRET | HMAC-секрет для этого хука. | строка |
Справочник: порты
| Порт | Слушатель | Для кого | Включается |
|---|---|---|---|
9977/tcp | Нативный TCP (Noise) | CLI и десктоп-клиенты по нативному транспорту | всегда (позиционный/ASTER_ADDR) |
9099/tcp | WebSocket-мост ws/wss | Браузерные и PWA/веб-клиенты | ASTER_WS (+ASTER_WSS) |
9097/tcp | Mesh (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=…).
Безопасность и закалка
- Готовый юнит уже применяет 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).
Диагностика
| Симптом | Что смотреть |
|---|---|
| Сервис не стартует | 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.