Files
AuraVPN/docs/deployment.md
T
xah30 e0e53665f1 feat(crypto,cli,docs): russian SNI palette + RF-billing deployment scenario
Adds a way to make the outer-TLS SNI rotate among popular Russian-language
domains so that Russian carriers — who may start metering "foreign traffic"
separately — see the user's first hop as a domestic CDN/site request, not
as an exotic foreign destination.

- aura-crypto::masks:
  - SNI_PALETTE_RUSSIAN (15 real domains: mail.yandex.ru, vk.com, www.ozon.ru,
    dzen.ru, ya.ru, www.gosuslugi.ru, www.wildberries.ru, rutube.ru,
    news.rambler.ru, hh.ru, www.tinkoff.ru, lenta.ru, www.kinopoisk.ru,
    afisha.yandex.ru, music.yandex.ru).
  - enum SniPalette { Default, Russian, Mixed } (Default = v2 behavior).
  - derive_mask_for_msk_date_with_palette(...): pick from chosen palette,
    Mixed flips ~50/50 by HKDF okm[8]&1. Old derive_mask_for_msk_date kept
    as a thin wrapper -> byte-for-byte unchanged Default.
- aura-cli::masks::MaskRotator gains new_with_palette(...); the spawn loop
  uses the stored palette. Old new() preserves Default.
- aura-cli config: [transport.masks] palette = "default"|"russian"|"mixed"
  (serde rename_all = "lowercase", default Default).
- server.rs/client.rs read cfg.transport.masks.palette and pass it to the
  rotator at startup; logged at INFO so the operator sees the choice.
- docs/deployment.md: new §7 "Сервер в РФ против тарификации иностранного
  трафика" — context, ASCII topology, recommended RF providers, full
  server.toml + client.toml examples wiring [server.relay] + russian
  palette + LE outer cert + multi-hop, plus an honest list of what this
  does and does not give.
- config/{server,client}.toml.example updated with palette = "default".

Workspace: 284 tests passed (+8 new = 4 crypto + 2 cli masks + 2 config),
clippy -D warnings clean, fmt clean. 276 baseline tests untouched.
Backward-compatible: configs without palette default to Default, identical
to v2 wire behavior.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 20:29:18 +03:00

682 lines
39 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Развёртывание Aura VPN
Этот документ — пошаговое руководство, по которому вы поднимаете сервер Aura на удалённой машине,
провижините на нём сертификат для клиента и подключаете клиент (десктоп) к этому серверу. Все
команды и поля конфигов взяты из фактического кода и поставляемых примеров в `config/`.
> Полезные сопутствующие документы: [`protocol.md`](protocol.md) (wire-протокол),
> [`pki.md`](pki.md) (CA и сертификаты), [`split-tunnel.md`](split-tunnel.md) (правила
> маршрутизации), [`sing-box.md`](sing-box.md) (интеграция с sing-box, план).
---
## 1. Обзор схемы
Сервер Aura на удалённой машине провижинит сертификат для клиента (десктопа или, в будущем,
телефона через sing-box), отдаёт клиенту бандл сертификатов и трастового якоря, и клиент
подключается к серверу по протоколу AuraVPN.
На проводе по умолчанию используется **собственный UDP-транспорт Aura с пост-квантовой
криптографией** (без QUIC и без внешнего TLS на основном пути); fallback'и — это TCP/443 и QUIC.
Всё рукопожатие пост-квантовое: **гибридное X25519 + ML-KEM-768** с взаимной X.509-аутентификацией.
Для данных используется AEAD **ChaCha20-Poly1305** с explicit-nonce. Обфускация — это паддинг
датаграмм до «корзин» размера, характерных для HTTPS.
```
[клиент-десктоп] [удалённый сервер aura]
client.toml + PEM-бандл server.toml + PKI (CA + server leaf)
| |
| UDP (основной) / TCP/443 / QUIC |
| гибридное PQ-рукопожатие |
| ChaCha20-Poly1305 |
+--------------------------------------->
AuraVPN
```
---
## 2. Сервер (удалённый хост)
### 2.1. Установка бинаря
В корне репозитория:
```bash
cargo build --release
# -> target/release/aura
```
Скопируйте получившийся бинарь `target/release/aura` на сервер (например в `/usr/local/bin/aura`)
либо соберите его прямо на сервере (требуется Rust toolchain).
### 2.2. Поднять PKI
Эти три команды создают CA и выпускают листовые сертификаты для сервера и клиента. Все они
проверены против реализации в `crates/aura-pki/src/{ca,cert,store}.rs` и
`crates/aura-cli/src/pki.rs`.
```bash
# 1) Создать CA Aura.
aura pki init --ca-name "Aura Root CA" --out /etc/aura/pki
# -> /etc/aura/pki/ca.crt
# -> /etc/aura/pki/ca.key # секрет, защищайте правами файловой системы
# 2) Выпустить сертификат сервера. --domain должен совпадать с тем именем,
# которое клиент будет ожидать в [client] sni (это же имя проверяется по SAN).
aura pki issue-server \
--domain vpn.example.com \
--out /etc/aura/pki/server \
--ca /etc/aura/pki
# -> /etc/aura/pki/server/server.crt
# -> /etc/aura/pki/server/server.key # секрет
# 3) Выпустить сертификат клиента (по одному на устройство).
# --id становится Common Name'ом и проверенным peer_id, который видит сервер.
aura pki issue-client \
--id phone-1 \
--out /etc/aura/clients/phone-1 \
--ca /etc/aura/pki
# -> /etc/aura/clients/phone-1/client.crt
# -> /etc/aura/clients/phone-1/client.key # секрет
```
Подробности (включая `aura pki revoke` / `list`) — см. [`pki.md`](pki.md).
### 2.3. `server.toml`
Раскладка ниже взята из `config/server.toml.example` и поставляемых serde-структур
(`crates/aura-cli/src/config.rs`). Скопируйте пример и поправьте под себя.
```toml
[server]
# Человекочитаемое имя (также внутренняя identity сервера в рукопожатии).
name = "aura-edge-1"
# UDP/TCP listen-сокет. ":443" мимикрирует под HTTPS; для его биндинга нужны привилегии.
# IP отсюда переиспользуется как listen-IP для каждого включённого транспорта.
listen = "0.0.0.0:443"
# Число accept-воркеров (в v1 носит совещательный характер).
workers = 4
[pki]
# Trust anchor (Aura CA) и листовая пара сервера, все PEM.
ca_cert = "/etc/aura/pki/ca.crt"
cert = "/etc/aura/pki/server/server.crt"
key = "/etc/aura/pki/server/server.key"
[tunnel]
# Адресный пул для клиентов; в v1 на сервере один общий TUN в этой сети.
pool_cidr = "10.7.0.0/24"
# MTU TUN-устройства (запас под QUIC + framing Aura).
mtu = 1420
# DNS, анонсируемый клиентам (в v1 информационно).
dns = "10.7.0.1"
[mimicry]
# Hostname, под который мимикрирует внешний TLS-слой (для QUIC).
sni = "cdn.example.com"
# Паддинг для размытия размеров пакетов под «корзины» HTTPS.
padding = true
[transport]
# Набор и порядок транспортов, биндящихся одновременно. UDP — основной; TCP/443 и
# QUIC (мимикрия H3) — fallback'и. При отсутствии всей секции включаются udp/tcp/quic
# на 443/443/444.
order = ["udp", "tcp", "quic"]
# UDP-транспорт и QUIC оба используют UDP, поэтому udp_port и quic_port ДОЛЖНЫ
# различаться. TCP может занимать тот же номер порта (другой протокол).
udp_port = 443
tcp_port = 443
quic_port = 444
# UDP: дополнять датаграммы до «корзин» размера HTTPS, чтобы размыть распределение размеров.
obfuscate = true
# TCP: добавлять минимальный HTTP/1.1-преамбулу (Host = [mimicry] sni), чтобы открытие
# выглядело как обычный HTTP.
masquerade = true
```
Пути могут начинаться с `~` (раскрывается в домашнюю директорию).
### 2.4. Сеть на сервере
#### Файрвол
Откройте те порты, которые перечислены у вас в `[transport]`. С приведённой выше конфигурацией:
- UDP **443** — основной транспорт Aura.
- TCP **443** — fallback Aura поверх TCP.
- UDP **444** — fallback Aura поверх QUIC.
Важно: UDP-транспорт и QUIC — это **оба UDP**, поэтому их порты обязательно должны различаться
(в примере: udp_port=443, quic_port=444). Конфиг-валидатор `transport.modes()` отвергает совпадение.
#### IP-форвардинг и NAT (для выхода клиентов в интернет)
В v1 настройка egress на стороне сервера — **обязательный ручной шаг**. На Linux:
```bash
# 1) Включить IP-форвардинг.
sudo sysctl -w net.ipv4.ip_forward=1
# (для постоянства добавьте в /etc/sysctl.conf или /etc/sysctl.d/*)
# 2) MASQUERADE для исходящего трафика клиентов на интернет-интерфейсе (например eth0).
sudo iptables -t nat -A POSTROUTING \
-s 10.7.0.0/24 \
-o eth0 \
-j MASQUERADE
```
Подставьте свой `pool_cidr` и имя интернет-интерфейса.
### 2.5. Запуск сервера
```bash
sudo aura server --config /etc/aura/server.toml
```
`sudo` нужен для создания TUN-устройства и для биндинга привилегированных портов (`:443`).
Можно опционально указать путь admin-сокета:
```bash
sudo aura server \
--config /etc/aura/server.toml \
--admin-socket /var/run/aura-admin.sock
```
По умолчанию admin-сокет — `/tmp/aura-admin.sock`.
---
## 3. Что вы получаете для клиента (бандл)
Отдайте клиенту **три PEM-файла**:
- `ca.crt` (из `/etc/aura/pki/ca.crt`) — trust anchor;
- `client.crt` (из `/etc/aura/clients/<id>/client.crt`) — листовой сертификат клиента;
- `client.key` (из `/etc/aura/clients/<id>/client.key`) — **секрет**, приватный ключ клиента.
И сообщите ему два параметра:
- **Адрес сервера** (например `203.0.113.10`).
- **`sni`** — то DNS-имя, которое вы указали в `aura pki issue-server --domain`. Оно же
ожидается в SAN серверного сертификата и проверяется в `verify_server_cert`.
Эти три файла плюс два параметра — это всё, что нужно клиенту для подключения.
---
## 4. Клиент (десктоп)
Путь для телефона — через sing-box; пока нативного клиента нет, см. раздел 6 ниже.
### 4.1. `client.toml`
Раскладка взята из `config/client.toml.example` и `crates/aura-cli/src/config.rs`.
```toml
[client]
# Человекочитаемое имя/id клиента.
name = "laptop"
# UDP-сокет сервера. IP отсюда переиспользуется как server-IP для каждого транспорта.
server_addr = "203.0.113.10:443"
# Внешний TLS-SNI (hostname-камуфляж), предъявляемый серверу. Он же проверяется
# внутри рукопожатия Aura против SAN серверного сертификата.
sni = "cdn.example.com"
[pki]
# Trust anchor (Aura CA) и листовая пара клиента, все PEM.
ca_cert = "~/.aura/ca.crt"
cert = "~/.aura/client.crt"
key = "~/.aura/client.key"
[tunnel]
# Запрошенное имя TUN-интерфейса (на macOS совещательно — ядро назначает utunN).
tun_name = "aura0"
# Локальный адрес для TUN и длина префикса.
local_ip = "10.7.0.2"
prefix = 24
# MTU TUN.
mtu = 1420
# DNS, используемый туннельным резолвером (в v1 информационно; реально используется
# системный резолвер).
dns = "10.7.0.1"
# Split-tunnel: действие по умолчанию плюс точечные правила.
[tunnel.split]
default = "VPN"
[[tunnel.split.direct]]
cidr = "192.168.0.0/16"
[[tunnel.split.direct]]
cidr = "10.0.0.0/8"
[[tunnel.split.direct]]
domain = "intranet.example.com"
# Более узкий префикс возвращает поддиапазон обратно в VPN (longest-prefix бьёт /8).
[[tunnel.split.vpn]]
cidr = "10.7.0.0/24"
[mimicry]
padding = false
[transport]
# Порядок fallback'а (handover), пробуется слева направо: первый удавшийся побеждает.
# При отсутствии всей секции — ["udp","tcp","quic"] на 443/443/444.
order = ["udp", "tcp", "quic"]
udp_port = 443
tcp_port = 443
quic_port = 444
obfuscate = true
masquerade = true
```
Подробности про `[tunnel.split]` — в [`split-tunnel.md`](split-tunnel.md).
### 4.2. Запуск клиента
```bash
sudo aura client --config client.toml
```
`sudo` нужен для поднятия TUN-устройства. Клиент:
1. Загружает PEM-файлы из `[pki]` и строит `aura_proto::ClientConfig`.
2. Строит таблицу маршрутизации из `[tunnel.split]`.
3. Дозванивается до сервера, перебирая транспорты в `[transport] order`
(handover UDP → TCP → QUIC); первый, который удался, побеждает.
4. Разрезолвит доменные правила split-tunnel'а в host-маршруты (best-effort).
5. Создаёт TUN, передаёт его маршрутизатору и начинает гонять трафик.
В логе при успехе вы увидите строку с выбранным транспортом:
```
INFO connected and authenticated to server peer=Some("cdn.example.com") mode=udp
```
`mode` принимает значения `udp`, `tcp` или `quic`.
### 4.3. Управление на лету
После запуска клиента (или сервера) admin-сокет позволяет менять правила и смотреть статус без
перезапуска:
```bash
# Добавить CIDR на лету.
aura route add --cidr 8.8.8.0/24 --action direct
# Завернуть домен через VPN.
aura route add --domain example.com --action vpn
# Перечислить правила.
aura route list
# Удалить CIDR-правило.
aura route remove --cidr 8.8.8.0/24
# Статус и счётчики.
aura status
# Aura tunnel status
# peer: cdn.example.com
# default: vpn
# rules: 2
# rx packets: 0
# tx packets: 0
```
Если сокет лежит не там, добавьте `--admin-socket <PATH>` к каждой команде. Полная спецификация
команд и wire-протокола admin'а — в [`split-tunnel.md`](split-tunnel.md).
---
## 5. Что идёт по проводу (резюме)
- **Основной**: собственный UDP-транспорт Aura (в примере — `443/udp`). Один UDP-сокет несёт
обе фазы, различимые по первому байту:
- `0x01` HS — рукопожатие с надёжным DTLS-подобным слоем поверх (повторы, ack, упорядочивание);
- `0x02` DATA — датаграммы данных с explicit-nonce AEAD; обфускация = паддинг до «корзин»
HTTPS (`[64, 128, 256, 512, 1024, 1280, 1460]`).
- **Fallback TCP/443**: настоящий **outer TLS-443** (rustls) поверх TCP — на проводе неотличимо
от валидного HTTPS, ALPN `[h2, http/1.1]`. Внутри TLS — тот же Aura-handshake. Клиент
использует `AcceptAnyServerCert` (security гарантирует только внутренний Aura-handshake).
- **Fallback QUIC**: внешний TLS-камуфляж под HTTP/3 + внутреннее Aura-рукопожатие.
- Клиент пробует транспорты по `order`, переключается при отказе или таймауте подключения
(по умолчанию 8 с). Сервер слушает все включённые транспорты одновременно (`MultiServer`).
Подробный wire-протокол — в [`protocol.md`](protocol.md).
---
## 6. v2 — что устранено и что остаётся
### Устранено в v2 (по сравнению с v1)
-**Мульти-клиент UDP-сервер.** `UdpServer` теперь демультиплексирует датаграммы по адресу
пира: один сокет обслуживает много клиентов параллельно, каждый со своим `ReliableHsAdapter` и
своим `UdpConnection`. `MultiServer::accept` выдаёт по соединению на каждого нового клиента
(в любом из включённых транспортов).
-**IP-пул + per-client маршрутизация на сервере.** Новая секция `[server.pool]`
(`cidr`, `strategy`, `static`) выдаёт каждому клиенту IP при accept; `ServerRouter` держит
карту `client_ip → Arc<dyn PacketConnection>`, читает с TUN, диспатчит пакеты по `dst_ip` в
нужное подключение, а параллельные per-conn-задачи пишут входящий трафик обратно в TUN.
-**`send_direct` устранён.** Новое `[tunnel.os_routes]` (по умолчанию `enabled = true`)
программирует **системную таблицу маршрутов**: DIRECT-цели идут мимо TUN через изначальный
default-gateway, через TUN попадает только VPN-трафик. RAII-guard откатывает все добавленные
маршруты при остановке клиента.
-**Настоящий TLS-443 в TCP-транспорте.** Вместо лёгкой HTTP/1.1-преамбулы — полный outer
rustls handshake (ALPN `[h2, http/1.1]`); клиент с `AcceptAnyServerCert`, поэтому SNI на
внешнем слое не верифицируется (это камуфляж), а вся реальная аутентификация — внутри
Aura-рукопожатия. На проводе неотличимо от валидного HTTPS.
-**Авто-NAT на сервере.** `[server.nat] {auto, egress_iface, dry_run}` поднимает
IP-форвардинг + MASQUERADE на старте (Linux: `sysctl ip_forward` + `iptables -t nat
MASQUERADE`; macOS: `sysctl ip.forwarding` + `pfctl`). RAII-guard откатывает изменения при
остановке. Опциональный `dry_run = true` логирует команды без выполнения — для отладки.
-**Privilege drop.** `[server]/[client] run_as = "nobody"` — после поднятия TUN и
привилегированных портов euid/gid сбрасываются в нерутового пользователя (Linux:
`setresuid/setresgid`; macOS: `setgid` + `setuid` permanent drop). Минимизирует время
процесса под root.
-**Admin-сокет на Windows.** Cfg-gated транспорт: на Unix — Unix socket
(`/tmp/aura-admin.sock`), на Windows — Tokio named pipe (`\\.\pipe\aura-admin`).
JSON-протокол и команды (`route add/list/remove`, `status`) идентичны.
-**In-band CRL.** Сервер сразу после handshake пушит подписанный CA CRL клиенту
через мультиплексированный control-envelope с magic-префиксом
`[0xAA,0xAA,0xC0,0x01]` (не конфликтует с IPv4/v6, которые начинаются с
`0x4X`/`0x6X`). Клиент проверяет подпись ECDSA-P256 против CA, применяет к
`AuraCertVerifier`, кэширует на диск. Конфиг `[pki] crl_push = true` /
`accept_pushed_crl = true` (по умолчанию).
-**Анти-надзор v2 (NEW в ответ на дрегнет операторов):**
- **Port-knocking** на UDP-транспорте: сервер молчит на скан-зондах, отвечает
только на валидный 16-байтный HMAC-SHA256 «стук» с ±1-минутным окном (ключ
из CA fingerprint). Сканер видит закрытый порт. `[transport.knock]
enabled = true`.
- **Cover traffic / chaff**: при простое UDP-соединение шлёт `Ping` каждые
~500мс±50% (jitter). Defeats volume/timing-fingerprinting. Под нагрузкой
подавляется автоматически. `[transport.cover] enabled = true`.
-**Автоматизация развёртывания:**
- `aura server-init --domain ... --pki-dir ...` — одна команда: CA +
серверный cert + готовый `server.toml` (с авто-определением egress-iface).
- `aura provision-client --id <UUID> --out <dir>` — выпускает client cert и
собирает готовый бандл (`ca.crt` + `client.crt` + `client.key` +
`client.toml`). `--id` опционален — дефолт UUID v4 (имя пользователя не
привязано к сертификату).
-**Минимизация идентификаторов:**
- `[server] no_logs = true` / `[client] no_logs = true` — поля `peer_id`,
`client_ip`, `source_addr`, `client_id`, `local_ip`, `user`, `id`,
`assigned_ip` редактируются из tracing-вывода через field-level фильтр
(события фиксируются, идентификаторы вычищаются).
- `[client] bridges = [...]` — список запасных серверов, клиент пробует
случайный порядок. Блокировка одного IP не убивает доступ.
-**НОВОЕ: ежедневная ротация масок в 05:00 МСК.** Внешний фингерпринт (SNI/UA/Server-
header/UDP padding-профиль) детерминированно меняется раз в сутки. И сервер, и клиент
выводят одинаковый `MaskSet` из общего seed (SHA-256 от CA-сертификата) + UTC-даты через
HKDF-SHA256, без сетевой координации. Конфиг: `[transport.masks] enabled = true` (по
умолчанию). Новые подключения берут текущую маску; уже установленные остаются на своих.
Палитры: 16 SNI default + 15 SNI russian, 10 User-Agent, 5 Server-headers, 4 padding-профиля;
профиль 0 байт-в-байт совместим с v1-паддингом (бэк-совместимость). v3.2 добавляет
`palette = "default" | "russian" | "mixed"` для случая, когда нужно, чтобы outer SNI выглядел
как обращение к российскому сайту (см. сценарий в §7).
-**Multi-hop / onion routing v3.1 + v3.2.** Цепочка из 2-3 хопов: client →
entry-relay → (опционально middle) → exit. Entry-relay не знает destination, exit-узел не
знает клиентский IP. v3.2: per-hop client cert (CN entry и exit различаются — нельзя
слинковать handshakes по identity), cell padding (constant-size cells устраняют per-packet
size-fingerprinting), CIDR whitelist на relay'е. Конфиг — `[client.circuit]` /
`[server.relay]`. См. сценарий §7 для деплоймента «российский entry, иностранный exit».
-**Let's Encrypt outer-TLS cert.** `[server.outer_cert] cert_path / key_path` — outer-TLS
слой QUIC и TCP использует настоящий CA-trusted сертификат вместо self-signed Aura cert;
внутренний Aura mutual-auth handshake продолжает аутентификацию против Aura CA.
### Остающиеся честные ограничения
- **TUN всё ещё требует root** для **создания** интерфейса (это OS-уровень). Privilege drop
минимизирует окно работы под root, но саму операцию обойти нельзя.
- **IPv6 в OS-маршрутах и iptables MASQUERADE** не реализован — только IPv4 (план v3.3).
- **Windows OS-маршруты** — заглушка с лог-warning (план v3.3). Windows admin pipe **работает**.
- **Нативного Go-клиента для телефона нет** — через sing-box (Option B нативный Go-outbound,
по `protocol.md` + KAT из Rust, см. [`sing-box.md`](sing-box.md)). Сейчас доступен только
десктоп-клиент / process-bridge. Это явно исключённый из v2 пункт.
- **Bridge-discovery без хардкода IP в конфиге** — план v3.3. Сейчас `[client] bridges`
хардкодит список запасных IP; если их все заблокируют (включая российские entry-узлы из
сценария §7), восстановление требует обновления конфига клиента вручную.
---
## 7. Сценарий: российский entry-узел против тарификации иностранного трафика
### 7.1. Контекст и угроза
Российские операторы связи могут начать тарифицировать «иностранный трафик» отдельно: классификация
выполняется по destination IP исходящего пакета пользователя. Если первый IP, к которому
обращается устройство, — российский, биллинг считает соединение «российским», даже если внутри
этого соединения трафик уходит дальше за рубеж. Цель в этом сценарии — добиться того, чтобы
оператор биллил трафик пользователя как «российский», при этом сохраняя VPN-выход за рубежом.
Решение опирается на три компонента, уже реализованные в AuraVPN:
1. **Multi-hop / onion routing v3.1+** (`[client.circuit]` / `[server.relay]`) — entry-узел в РФ
не знает destination, exit-узел за рубежом не знает клиентский IP.
2. **Палитра SNI «russian»** (v3.2) — `[transport.masks] palette = "russian"` ротирует outer-TLS
SNI среди крупных российских доменов (`vk.com`, `www.ozon.ru`, `mail.yandex.ru`, ...).
3. **OS-уровень kill-switch** (`[tunnel.os_routes] enabled = true`) — гарантия, что системный
трафик (push-уведомления, OS-сервисы) не обходит туннель и не попадает напрямую к иностранным
серверам в обход entry-узла.
### 7.2. Топология
```
[устройство]
|
| весь трафик через TUN (kill-switch)
v
[оператор] <-- видит только UDP/443 на RU_VPS_IP, SNI = "vk.com"
|
v
[Russian VPS / entry-relay] <-- v3.1 relay: forward to next hop, never decodes IP packets
|
| inner Aura handshake (PQ-encrypted, opaque)
v
[Foreign VPS / exit] <-- настоящий VPN-выход в интернет
|
v
[internet]
```
Оператор видит только трафик до **entry-узла**: один UDP-поток с SNI крупного российского сайта.
Внутри этого потока — зашифрованный многохоп; entry-relay не имеет ключей внутреннего рукопожатия
и видит только AEAD-ciphertext, который он форвардит на exit. Exit видит только IP entry-узла, а
не IP клиентского устройства.
### 7.3. Что покупать
**Подходящие провайдеры для entry-узла в РФ** (юрисдикция РФ, IP в российских AS):
- **Selectel** (Москва, СПб).
- **Beget** (СПб).
- **Yandex.Cloud** (Москва).
- **VK Cloud** (бывш. Mail.ru Cloud Solutions).
- **Timeweb Cloud**.
**Неподходящие для роли entry-узла в РФ**:
- **Hetzner** (Германия/Финляндия) — IP классифицируется как «иностранный».
- **DigitalOcean / Vultr / Linode** (США/EU) — то же самое.
- **AWS / GCP / Azure** даже с российскими DC-локациями — IP-блоки за пределами российских AS у
большинства операторов.
Для **exit-узла** наоборот — берите любой удобный иностранный VPS (Hetzner, DigitalOcean, Vultr,
любой подходящий по юрисдикции и пропускной способности).
### 7.4. Конфиг сервера в РФ (entry-relay)
`server.toml` на российском VPS (например, Selectel с IP `RUSSIAN_VPS_IP`):
```toml
[server]
name = "aura-ru-entry-1"
listen = "0.0.0.0:443"
[pki]
ca_cert = "/etc/aura/pki/ca.crt"
cert = "/etc/aura/pki/server/server.crt"
key = "/etc/aura/pki/server/server.key"
[tunnel]
# Pool нужен формально (для v1-fallback-пути), но в роли чистого relay он не используется —
# bridged-клиенты не получают IP из пула и не регистрируются в ServerRouter.
pool_cidr = "10.7.0.0/24"
mtu = 1420
# v3.1: relay-режим. Принимаем ExtendBridge от клиента и сплайсим на foreign exit.
[server.relay]
enabled = true
allow_extend_to = ["EXIT_FOREIGN_IP:443"] # IP вашего иностранного exit-узла
# v3.2 cell padding: relay сам не декодирует — это сквозной байт-форвардинг. Знаки опции тут
# для симметрии конфига; реальный декод цельных ячеек — на exit'е.
cell_padding = true
cell_size = 1280
[transport.masks]
enabled = true
# v3.2: outer-TLS SNI крутится среди крупных российских доменов. Каждый день — другой домен.
palette = "russian"
# Опционально: настоящий outer-TLS сертификат (Let's Encrypt) поверх UDP/QUIC и TCP. Без него
# работает self-signed Aura, но с настоящим LE-сертификатом outer-handshake становится
# неотличим от обычного HTTPS на CA-trusted сайт.
[server.outer_cert]
cert_path = "/etc/letsencrypt/live/relay.example.ru/fullchain.pem"
key_path = "/etc/letsencrypt/live/relay.example.ru/privkey.pem"
```
И аналогичный `server.toml` на **иностранном exit-узле** — обычный VPN-сервер БЕЗ `[server.relay]`,
но с `cell_padding_for_circuit_clients = true` в секции `[server]`, чтобы он понимал
constant-size cells от клиента:
```toml
[server]
name = "aura-exit-1"
listen = "0.0.0.0:443"
# v3.2: exit для cell-padded клиентов — декодирует ячейки внутреннего рукопожатия.
cell_padding_for_circuit_clients = true
[pki]
ca_cert = "/etc/aura/pki/ca.crt"
cert = "/etc/aura/pki/server/exit.crt"
key = "/etc/aura/pki/server/exit.key"
[tunnel]
pool_cidr = "10.7.0.0/24"
[server.nat]
auto = true # включить IP-форвардинг и MASQUERADE на egress-интерфейсе
egress_iface = "eth0"
[transport.masks]
# На exit'е SNI палитра не критична (клиент видит exit только через relay) — оставим default.
palette = "default"
```
### 7.5. Конфиг клиента
```toml
[client]
name = "laptop"
server_addr = "RUSSIAN_VPS_IP:443" # entry-узел в РФ; именно этот IP видит оператор
sni = "relay.example.ru" # SAN серверного outer-TLS сертификата (если есть LE)
[pki]
ca_cert = "~/.aura/ca.crt"
cert = "~/.aura/client.crt"
key = "~/.aura/client.key"
[tunnel]
tun_name = "aura0"
local_ip = "10.7.0.2"
prefix = 24
mtu = 1420
[tunnel.split]
default = "VPN"
# КРИТИЧНО: kill-switch — весь трафик через TUN, OS-уровень. Без этого push-уведомления и
# OS-сервисы могут уйти напрямую в иностранные сервера в обход entry-узла, и оператор
# зачтёт это как «иностранный» трафик.
[tunnel.os_routes]
enabled = true
# v3.1 / v3.2: цепочка хопов client -> RU_entry -> foreign_exit.
[client.circuit]
enabled = true
cell_padding = true
cell_size = 1280
[[client.circuit.hops]]
addr = "RUSSIAN_VPS_IP:443" # entry в РФ — то, что видит оператор
cert_path = "~/.aura/circuit/entry.crt"
key_path = "~/.aura/circuit/entry.key"
[[client.circuit.hops]]
addr = "EXIT_FOREIGN_IP:443" # exit за рубежом, к которому привязаны DNS/маршруты внутри VPN
cert_path = "~/.aura/circuit/exit.crt"
key_path = "~/.aura/circuit/exit.key"
[transport.masks]
enabled = true
# Должно совпадать с palette = "russian" на entry-узле — иначе SNI в логах двух сторон
# не будут симметричны (на проводе это не ошибка, но удобнее для отладки).
palette = "russian"
```
Сертификаты двух хопов — разные (`entry.crt` != `exit.crt`). Это v3.2 identity-unlinkability:
entry-relay видит только клиентский cert для роли entry, exit-узел видит только cert для роли
exit, и они не пересекаются (см. `aura provision-client --circuit-hops 2 ...`).
### 7.6. Что это даёт
- **Оператор биллит как «российский».** На проводе оператор видит один UDP-поток на
`RUSSIAN_VPS_IP:443` — это российский IP в российской AS, классификатор биллинга его не
обозначает как иностранный.
- **SNI выглядит как обращение к российскому сайту.** В пакетах outer-TLS / outer-QUIC
hostname-камуфляж берётся из `SNI_PALETTE_RUSSIAN`: каждый день — другой домен (`vk.com`,
`www.ozon.ru`, `mail.yandex.ru`, ...). DPI видит «нормальный HTTPS на крупный российский
сайт».
- **Реальный VPN-выход — за рубежом.** Внутри multi-hop клиент дозванивается до иностранного
exit-узла; именно его IP видят внешние ресурсы. Entry-узел в РФ форвардит зашифрованный
трафик, не зная destination и не имея ключей внутреннего рукопожатия.
- **Kill-switch предотвращает обход.** `[tunnel.os_routes] enabled = true` программирует
системную таблицу маршрутов так, что весь трафик идёт через TUN — push-уведомления, OS-сервисы
и любые «прямые» обращения в обход VPN заблокированы, поэтому ничто из устройства не уйдёт
напрямую к иностранному IP в обход entry-узла.
### 7.7. Что это НЕ даёт (честное ограничение)
- **Не скрывает сам факт VPN-использования** от российских органов. DPI с deep-inspection может
по статистическим паттернам трафика (timing, размеры, поведение в течение сессии) узнать
Aura-протокол; ротация масок и `palette = "russian"` маскирует пассивного наблюдателя, но не
активного аналитика. Для дополнительной защиты включайте `[transport.knock]` и
`[transport.cover]` (port-knocking + cover traffic).
- **Не освобождает от ответственности за заходы на запрещённые ресурсы.** Кто и за что отвечает
при заходе на запрещённый ресурс через VPN — вопрос юрисдикции exit-узла и применимого
законодательства, не технический.
- **Не защищает от блокировки самого entry-IP.** Если СОРМ-система или Роскомнадзор начнут
активно блокировать конкретные VPS-IP, придётся ротировать IP / bridges. Сейчас это решается
через `[client] bridges = [...]` — список запасных российских entry-узлов; клиент пробует их
в случайном порядке при отказе primary. Полноценный bridge-discovery (без хардкода IP в
конфиге) — план v3.3.
- **Cell padding не скрывает наличие туннеля.** Constant-size cells устраняют per-packet
size-fingerprinting внутри multi-hop, но не делают сам поток неотличимым от HTTPS — общий
объём и временные паттерны остаются. Это компромисс между обфускацией и накладными расходами.
### 7.8. Что менять при ротации
При смене IP entry-узла (например, при блокировке текущего) обновите три места:
1. `[[client.circuit.hops]] addr` первого хопа → новый `RUSSIAN_VPS_IP:443`.
2. `[client] server_addr` → тот же новый IP.
3. На новом VPS — поднять PKI, выпустить cert для entry-роли, перенести `server.toml` с
`[server.relay]` и `palette = "russian"`.
Перевыпускать сертификаты двух хопов не нужно — они остаются те же, меняется только wire-адрес
entry-узла. На сертификате entry-сервера должен быть SAN, совпадающий с `[client] sni`
(см. `aura pki issue-server --domain relay.example.ru`).