feat: support AmneziaWG 3.1

This commit is contained in:
2026-08-28 00:28:26 +05:00
parent 3912b91bc4
commit 185991504a
16 changed files with 282 additions and 110 deletions
+12 -4
View File
@@ -4,8 +4,8 @@
- [ ] Хост — Debian 13 amd64.
- [ ] Сервер выделенный, без соседних сервисов.
- [ ] AmneziaWG/AWG 2.0 или AmneziaWG/AWG 1.5 установлена официальным способом.
- [ ] Контейнер `amnezia-awg2` или `amnezia-awg` запущен (`amnezia-awg3` — резерв на будущее, в AmneziaVPN 5.0 такого типа контейнера ещё нет).
- [ ] AmneziaWG 3.1 установлена официальным self-hosted способом через AmneziaVPN 5.0.1.5 или новее.
- [ ] Контейнер `amnezia-awg2` запущен; `amnezia-awg` допустим только как осознанный legacy fallback.
- [ ] `docker ps` видит контейнер.
- [ ] Можно получить PID контейнера.
- [ ] `/proc/<pid>/ns/net` существует.
@@ -15,6 +15,12 @@
## B. Обнаружение peers
- [ ] `C=amnezia-awg2` соответствует фактически запущенному контейнеру.
- [ ] `docker exec "$C" awg --version` зафиксирован в acceptance evidence.
- [ ] `docker exec "$C" ip -o link show awg0` находит основной интерфейс.
- [ ] `docker exec "$C" ip -d link show awg0` фиксирует фактический kernel/userspace runtime без требования конкретной реализации.
- [ ] `docker exec "$C" awg show all dump | awk -F '\t' '{print NR, NF, $1}'` для reference AWG 3.1 tools показывает 30 полей interface-row и 9 полей peer-row.
- [ ] Width используется только как acceptance evidence; parser не определяет по нему версию и не классифицирует peer.
- [ ] `awg2-harness status` показывает найденный контейнер.
- [ ] `awg2-harness status` показывает PID/netns контейнера.
- [ ] `awg2-harness status` показывает найденный интерфейс.
@@ -171,7 +177,8 @@
- [ ] Есть chain `forward_antitorrent` с hook `forward` и policy `accept`.
- [ ] Правило ограничивает `ip saddr <peer_ipv4_cidr>`, default `10.8.1.0/24`.
- [ ] Лимит считается per source VPN IP через meter/set, а не глобально по всей подсети.
- [ ] Порог совпадает с `anti_torrent.max_connections_per_peer`; текущий пример config использует `150`, более строгий вариант — `100`.
- [ ] Порог совпадает с `anti_torrent.max_connections_per_peer`; shipped production baseline — `500`.
- [ ] В фактической nft rule присутствует `ct count over 500` для shipped config.
- [ ] Drop counter виден в `status`.
- [ ] На first-run без table `awg2-harness apply-firewall` создаёт `table inet awg2_harness`, а не падает.
- [ ] При превышении порога новые flows дропаются, established flows ниже порога не ломаются.
@@ -193,6 +200,7 @@
- [ ] Package собирается на отдельной Debian 13 amd64 build-machine.
- [ ] Production host не требует Rust/cargo/source tree.
- [ ] `./tools/build.sh --package` создаёт `dist/awg2-harness_<version>_amd64.deb`.
- [ ] Release package без `--version` получает версию `0.3.1` из `traffic_core/Cargo.toml`.
- [ ] `dist/SHA256SUMS` валидирует checksum пакета.
- [ ] Пакет ставит бинарь в `/usr/sbin/awg2-harness`.
- [ ] Пакет ставит unit в `/lib/systemd/system/awg2-harness.service`.
@@ -219,7 +227,7 @@
- [ ] AmneziaDNS установлен из приложения AmneziaVPN.
- [ ] Контейнер `amnezia-dns` в состоянии healthy.
- [ ] `docker inspect amnezia-dns` показывает `"53/tcp":null` и `"53/udp":null`.
- [ ] `amnezia-dns` и активный AWG-контейнер (`amnezia-awg2`, `amnezia-awg3` или `amnezia-awg`) подключены к одной Amnezia DNS Docker-сети.
- [ ] `amnezia-dns` и активный AWG-контейнер (`amnezia-awg2` или осознанный legacy `amnezia-awg`) подключены к одной Amnezia DNS Docker-сети.
- [ ] Публичный DNS-запрос к `<server-public-ip>:53` не резолвит домены; допустимы `connection refused`, `timeout` или `no servers could be reached`.
- [ ] DNS-резолвинг у VPN-клиента работает при активном подключении.
- [ ] AWG2 host firewall не открывает `53/tcp` и `53/udp`.
+5 -10
View File
@@ -4,7 +4,7 @@
## 1. Цель
Не детектить BitTorrent как протокол. Цель проще: ограничить количество одновременных conntrack flows на один VPN peer IP. Торрент-клиенты обычно пытаются держать сотни TCP/UDP peer-сессий, DHT/uTP/trackers. Лимит в диапазоне 100–250 одновременных flows заметно ухудшает P2P-поведение, но почти не затрагивает обычные сценарии при корректной настройке.
Не детектить BitTorrent как протокол. Цель проще: ограничить количество одновременных conntrack flows на один VPN peer IP. Торрент-клиенты обычно пытаются держать сотни TCP/UDP peer-сессий, DHT/uTP/trackers. Штатный baseline `500` сохраняет мягкий connection guard, не вмешиваясь в нормальный повседневный профиль по результатам эксплуатационных измерений проекта.
Это мягкий технический барьер, а не abuse-система со страйками.
@@ -54,7 +54,7 @@ table inet awg2_harness {
type filter hook forward priority filter; policy accept;
ip saddr 10.8.1.0/24 ct state new \
meter awg2_peer_connlimit_v4 { ip saddr ct count over 100 } \
meter awg2_peer_connlimit_v4 { ip saddr ct count over 500 } \
counter name antitorrent_dropped_v4 \
drop
}
@@ -70,15 +70,10 @@ table inet awg2_harness {
```toml
[anti_torrent]
enabled = true
max_connections_per_peer = 150
max_connections_per_peer = 500
```
Практические варианты:
- `100` — более строгий режим.
- `150` — текущий рекомендуемый стартовый baseline, мягче к обычному browsing/mobile traffic.
- `200/250` — ещё более permissive варианты.
- `70` — агрессивный режим только после наблюдения реального трафика.
`500` — production baseline, выбранный по прикладным и нагрузочным измерениям проекта. Connection guard остаётся включённым, но порог не должен мешать обычному browsing/mobile/application traffic. Любое значение ниже `500` является более агрессивной операторской политикой и требует отдельной проверки на реальных клиентах. Значение остаётся конфигурируемым и не зашито в алгоритм.
## 5. Почему это должно быть в orchestrator
@@ -92,7 +87,7 @@ max_connections_per_peer = 150
## 6. Conntrack и производительность
`ct count` использует conntrack. На текущем масштабе это нормально: даже 23 peers × 100 flows = около 2300 активных flows до ограничения. Это не выглядит опасно для production-хоста само по себе.
`ct count` использует conntrack. Для примера 23 peers × 500 flows дают до 11 500 потенциальных flow slots перед ограничением каждого peer. Само по себе это не является доказательством достаточной ёмкости конкретного хоста, поэтому фактическое состояние conntrack обязательно наблюдается.
Что надо мониторить:
+8 -10
View File
@@ -1,6 +1,6 @@
# Конфигурация AWG2 Harness
AWG2 Harness разрабатывался для self-hosted AmneziaWG/AWG 2.0 и совместимого legacy-сценария AmneziaWG/AWG 1.5. Конфиг живёт в `/etc/awg2-harness/config.toml`. Он общий для всего пакета и должен содержать только эксплуатационно значимые параметры.
Основной target AWG2 Harness 0.3.1 — self-hosted AmneziaWG 3.1. AWG 3.0/2.x и `amnezia-awg` сохраняются как regression/legacy compatibility. Точная upstream-база описана в [`UPSTREAM_COMPATIBILITY.md`](UPSTREAM_COMPATIBILITY.md). Конфиг живёт в `/etc/awg2-harness/config.toml`, общий для всего пакета и содержит только эксплуатационно значимые параметры.
## Создание runtime config
@@ -24,9 +24,9 @@ nano /etc/awg2-harness/config.toml
Discovery-команды:
```bash
docker port amnezia-awg2 2>/dev/null || docker port amnezia-awg3 2>/dev/null || docker port amnezia-awg
docker port amnezia-awg2 2>/dev/null || docker port amnezia-awg
C="$(docker ps --format '{{.Names}}' | grep -E '^(amnezia-awg2|amnezia-awg3|amnezia-awg)$' | head -n1)"
C="$(docker ps --format '{{.Names}}' | grep -E '^(amnezia-awg2|amnezia-awg)$' | head -n1)"
docker exec "$C" ip -4 addr
docker exec "$C" awg show
```
@@ -35,7 +35,7 @@ docker exec "$C" awg show
```toml
[amnezia]
container_names = ["amnezia-awg2", "amnezia-awg3", "amnezia-awg"]
container_names = ["amnezia-awg2", "amnezia-awg"]
interface_candidates = ["awg0", "wg0", "amnezia0", "tun0"]
interface_patterns = ["awg*", "wg*", "amnezia*", "tun*"]
wg_binaries = ["awg", "wg"]
@@ -73,7 +73,7 @@ default_input_policy = "drop"
[anti_torrent]
enabled = true
max_connections_per_peer = 150
max_connections_per_peer = 500
peer_ipv4_cidr = "10.8.1.0/24"
apply_in_amnezia_netns = true
@@ -92,9 +92,7 @@ swappiness = 1
## Пояснения
`amnezia.container_names` — имена контейнеров, которые считаются Amnezia/AWG. Порядок важен, сопоставление точное. По текущему production-снимку основной вариант — `amnezia-awg2`, fallback — `amnezia-awg`.
`amnezia-awg3` перечислен на будущее и **не является подтверждённым официальным именем**: в проверенной версии AmneziaVPN `5.0.0.5` поддержка AWG 3.0 добавлена, но варианты контейнера по-прежнему представлены как `Awg` и `Awg2`, отдельного типа `Awg3` нет. Имя оставлено в примере потому, что несовпавшее имя не стоит ничего — поиск просто идёт дальше по списку, — тогда как отсутствующее в списке имя даст молчаливое «контейнер не найден». Если Amnezia введёт другое имя, его нужно будет дописать сюда.
`amnezia.container_names` — упорядоченный список точных имён контейнеров Amnezia/AWG. Основной официальный вариант — `amnezia-awg2`, затем проверяется legacy `amnezia-awg`. Отдельного официального типа `amnezia-awg3` в зафиксированной upstream-версии нет. Другое имя можно явно добавить в runtime config; неизвестные имена автоматически не угадываются.
`amnezia.interface_candidates` — точные имена интерфейса, которые пробуются первыми.
@@ -102,7 +100,7 @@ swappiness = 1
`amnezia.wg_binaries` — утилита чтения peer state внутри контейнера, пробуется по порядку до первого успеха. Default — `["awg", "wg"]`. В официальном образе AmneziaWG реальный бинарь `/usr/bin/awg`, а `/usr/bin/wg` — symlink на него, поэтому `awg` идёт первым; `wg` остаётся для контейнеров с чистым WireGuard. Значения выполняются внутри контейнера и валидируются как имена команд: непустые, без пробелов и без разделителей пути. Параметр опциональный — конфиги, созданные до его появления, продолжают работать с default.
Хостовый `wireguard-tools` не нужен и не проверяется в preflight. Peer state читается только через `docker exec`: AmneziaWG — userspace-реализация, её UAPI-сокет находится в `RUNSTATEDIR/amneziawg/` внутри mount namespace контейнера, а `nsenter -n` входит только в network namespace, поэтому хостовый `wg` до него не достаёт.
Хостовый `wireguard-tools` не нужен и не проверяется в preflight. Peer state читается через `docker exec` официальным `awg` внутри контейнера. Это единая container-side точка доступа для kernel `amneziawg` и fallback `amneziawg-go`, не зависящая от версии host-side tools.
`amnezia.peer_ipv4_cidr` — подсеть VPN peers. Production default — `10.8.1.0/24`; значение конфигурируемое.
@@ -177,7 +175,7 @@ swappiness = 1
`host_firewall.default_input_policy` — политика INPUT chain (`drop` или `accept`). Для production рекомендуется `drop`.
`anti_torrent.max_connections_per_peer` — максимум одновременных conntrack flows на один VPN peer IP. Текущий пример использует `150`: это мягче, чем строгий `100`, и обычно безопаснее как первый production baseline. `100` можно использовать как более жёсткий режим; `200/250` — более permissive варианты.
`anti_torrent.max_connections_per_peer` — максимум одновременных conntrack flows на один VPN peer IP. Штатный production baseline — `500`, выбранный по эксплуатационным измерениям проекта так, чтобы connection guard оставался включённым и не вмешивался в нормальный повседневный профиль. Значение ниже `500` является сознательно более агрессивной политикой и требует проверки на реальных клиентах. Поле обязательное и не скрыто в Rust default.
`anti_torrent.peer_ipv4_cidr` — подсеть, на которую распространяется правило. Обычно должна совпадать с `amnezia.peer_ipv4_cidr`.
+7 -7
View File
@@ -9,7 +9,7 @@ Production-пакет AWG2 Harness содержит два Rust-бинаря:
- `awg2-harness` — host-side оркестратор traffic/firewall/status/swap;
- `awg2-reboot-scheduler` — отдельный сервис планировщика перезагрузки.
`awg2-harness` остаётся основным host-side мульти-оркестратором для выделенного сервера Debian 13 amd64 с AmneziaWG/AWG 2.0.
`awg2-harness` остаётся основным host-side мульти-оркестратором для выделенного сервера Debian 13 amd64. Основной upstream target релиза 0.3.1 — self-hosted AmneziaWG 3.1; AWG 3.0/2.x сохраняются как regression compatibility. Версии и source contract зафиксированы в [`UPSTREAM_COMPATIBILITY.md`](UPSTREAM_COMPATIBILITY.md).
Он владеет инфраструктурным состоянием, которое нужно VPN-сервису:
@@ -236,7 +236,7 @@ struct PeerTrafficStatus {
Это снижает эксплуатационный риск: если контейнер Amnezia перестанет содержать `tc` или `iproute2`, host-side утилиты всё равно применят правила внутри его netns.
Чтение состояния peers — единственное исключение, и его нельзя выполнять host-side бинарём. AmneziaWG — userspace-реализация, её UAPI-сокет находится в `RUNSTATEDIR/amneziawg/<iface>.sock` внутри mount namespace контейнера, тогда как хостовый `wireguard-tools` ищет сокет в `/var/run/wireguard/`. `nsenter -n` входит только в network namespace, поэтому хостовый `wg` не достаёт ни до сокета, ни до kernel-устройства и всегда возвращает пустой список peers. Поэтому обнаружение peers использует исключительно `docker exec`, а `wireguard-tools` не является зависимостью хоста и не проверяется в preflight.
Чтение состояния peers — единственное исключение: harness намеренно использует официальный container-side `awg` через `docker exec`. `awg-quick` сначала пробует kernel interface типа `amneziawg`, а при его отсутствии запускает `amneziawg-go`. Container-side CLI является общей точкой доступа для обеих реализаций и изолирует harness от наличия и версии host-side `awg`/`wg`. Поэтому `wireguard-tools` не является зависимостью хоста и не проверяется в preflight.
## 6. Порядок discovery
@@ -290,10 +290,10 @@ Fallback-парсер разбирает текстовый вывод, извл
Классификация строк `show all dump`:
- строка считается peer-строкой, только если в ней не менее 9 tab-колонок, колонка 5 (allowed ips) равна `(none)` или является списком CIDR через запятую, а колонки 6–8 (handshake, rx, tx) целиком парсятся как целые;
- **количество колонок не является дискриминатором и не должно им становиться.** Ширину interface-строки определяет версия `amneziawg-tools`, которая её печатает, а не то, какие параметры протокола реально настроены в туннеле: AWG 3.0-утилиты печатают расширенную строку и для конфигурации AWG 2.0, просто с нулевыми или пустыми новыми полями. Любое правило вида «N колонок означает версию X» неверно по построению;
- **количество колонок не является дискриминатором и не должно им становиться.** Исторически WireGuard/AWG 2.x/AWG 3.0/AWG 3.1 tools печатают interface-row шириной 5/14/28/30 полей, а текущий peer-row содержит 9. Ширину определяет producer `amneziawg-tools`, а не настроенная версия параметров: новые tools могут печатать широкую строку для старой конфигурации с нулевыми или пустыми новыми полями. Любое правило вида «N колонок означает версию X» неверно по построению;
- interface-строка к тому же *длиннее* peer-строки, а на позициях handshake/rx/tx у неё стоят размеры junk-пакетов, которые тоже парсятся как целые, поэтому и эти колонки не разделяют два случая;
- это важно не только для корректности: колонка 2 interface-строки — приватный ключ устройства, и ошибочно классифицированная interface-строка выдала бы его как public key peer;
- AWG 3.0 печатает протокольные таймеры диапазонами (`20-30`). Колонка keepalive у peer не читается, и диапазон в ней не должен ломать разбор.
- AWG 3.x печатает протокольные таймеры диапазонами (`20-30`). AWG 3.1 tools `v3.1.20260812` дополнительно печатают `RandomTrailers` и `DisableCookies` перед `fwmark`. Колонка keepalive у peer не читается, и диапазон в ней не должен ломать разбор.
Политика выполнения для production:
@@ -426,7 +426,7 @@ table inet awg2_harness {
Целевой namespace — тот же Amnezia network namespace, где применяется `tc` shaping. Нельзя предполагать, что начальный host namespace видит исходные source-адреса peers. Если Amnezia выполняет NAT внутри namespace контейнера, host Docker bridge может видеть только адрес контейнера, а не `10.8.1.x`.
Порог в примере конфигурации — `150` одновременных flows на peer IP. `100` — более строгий режим. `70` агрессивнее и применяется только после наблюдения реального трафика. `200`/`250` — более permissive варианты.
Порог в примере конфигурации — `500` одновременных flows на peer IP. Это production baseline по эксплуатационным измерениям проекта: guard остаётся включённым, но не должен вмешиваться в нормальный повседневный профиль. Значение ниже `500` является более агрессивной политикой и требует отдельной проверки на реальных клиентах. Порог передаётся из config и не зашит в алгоритм.
Размещение правила: hook `forward` с приоритетом `filter` или любым приоритетом после conntrack lookup. Оценка ограничивается `ct state new`, чтобы установленные flows продолжали работать и дропались только новые попытки сверх порога.
@@ -696,10 +696,10 @@ inode = 123456
Модульные тесты:
- валидация конфига, включая форму `amnezia.wg_binaries`;
- разбор `config.example.toml` в актуальную схему;
- разбор `config.example.toml` в актуальную схему с точным default-порядком контейнеров, `awg`/`wg` и anti-torrent baseline `500`;
- парсер `awg|wg show all allowed-ips`, включая несколько allowed ips через пробел;
- fallback-парсер `awg|wg show`;
- классификация peer/interface строк `awg|wg show all dump` против interface-строк AWG 3.0 с включённой и с выключенной защитой заголовка, AWG 2.0, чистого WireGuard, а также конфигурации AWG 2.0, прочитанной утилитами AWG 3.0;
- классификация peer/interface строк `awg|wg show all dump` против двух 30-полевых AWG 3.1 fixtures, AWG 3.0 с включённой и выключенной защитой заголовка, AWG 2.x, чистого WireGuard, а также конфигурации AWG 2.0, прочитанной tools AWG 3.0;
- разбор dump с несколькими интерфейсами, с интерфейсом без peers и с повреждёнными строками;
- порядок выбора бинаря wg и ошибка при отсутствии всех кандидатов;
- фильтрация по CIDR;
+10 -8
View File
@@ -5,14 +5,16 @@
## Контракт развёртывания
- Целевой production-хост: Debian 13 amd64.
- Amnezia ставится до AWG2 Harness официальным self-hosted способом через приложение AmneziaVPN.
- Проект рассчитан на AmneziaWG/AWG 2.0 и compatible legacy-сценарий AmneziaWG/AWG 1.5.
- Amnezia ставится до AWG2 Harness официальным self-hosted способом через AmneziaVPN 5.0.1.5 или новее.
- Основной target релиза 0.3.1 — AmneziaWG 3.1; AWG 3.0/2.x остаются regression compatibility.
- SSH должен быть заранее настроен. Production-пример: порт `2323`, вход по ключу, password login disabled.
- Production-хост получает готовый Debian-пакет; Rust/cargo/source tree на нём не требуются.
- `/etc/awg2-harness/config.toml` создаётся вручную. `config.example.toml` не копируется автоматически как боевой config.
- Пакет не устанавливает Docker/Amnezia и не включает services автоматически.
- `sysctl_tuning` не применяется в `postinst`; применение только на старте daemon или вручную через CLI.
Основной документированный сценарий — clean installation AWG 3.1. Официальный переход с AWG 2.0 требует пересоздания контейнера и перевыпуска пользователей; harness эту миграцию не выполняет. Версии и исходный контракт приведены в [`UPSTREAM_COMPATIBILITY.md`](UPSTREAM_COMPATIBILITY.md).
## A. Сборочная машина
### A1. Подготовить сборочное окружение
@@ -40,10 +42,10 @@ cargo test --locked --workspace --release --manifest-path Cargo.toml
### A3. Собрать Debian-пакет
```bash
./tools/build.sh --package --version 0.3.0
./tools/build.sh --package
(cd dist && sha256sum -c SHA256SUMS)
dpkg-deb -I dist/awg2-harness_0.3.0_amd64.deb
dpkg-deb -c dist/awg2-harness_0.3.0_amd64.deb | sort
dpkg-deb -I dist/awg2-harness_0.3.1_amd64.deb
dpkg-deb -c dist/awg2-harness_0.3.1_amd64.deb | sort
```
`--version` можно опустить, если версия в `traffic_core/Cargo.toml` уже равна release version. Version override влияет только на metadata `.deb`.
@@ -127,7 +129,7 @@ Password or SSH private key:
```bash
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
C="$(docker ps --format '{{.Names}}' | grep -E '^(amnezia-awg2|amnezia-awg3|amnezia-awg)$' | head -n1)"
C="$(docker ps --format '{{.Names}}' | grep -E '^(amnezia-awg2|amnezia-awg)$' | head -n1)"
echo "container=$C"
docker port "$C"
docker exec "$C" awg show
@@ -166,7 +168,7 @@ amnezia-dns amnezia-dns Up ... (healthy) 53/tcp, 53/udp
Проверка публикации портов:
```bash
AWG="$(docker ps --format '{{.Names}}' | grep -E '^(amnezia-awg2|amnezia-awg3|amnezia-awg)$' | head -n1)"
AWG="$(docker ps --format '{{.Names}}' | grep -E '^(amnezia-awg2|amnezia-awg)$' | head -n1)"
echo "AWG=$AWG"
docker inspect -f 'ports={{json .NetworkSettings.Ports}}' amnezia-dns
@@ -195,7 +197,7 @@ Optional deep-check DNS path (если нужна углублённая про
```bash
apt install -y dnsutils
AWG="$(docker ps --format '{{.Names}}' | grep -E '^(amnezia-awg2|amnezia-awg3|amnezia-awg)$' | head -n1)"
AWG="$(docker ps --format '{{.Names}}' | grep -E '^(amnezia-awg2|amnezia-awg)$' | head -n1)"
DNS_IP="$(docker inspect -f '{{range $n,$v := .NetworkSettings.Networks}}{{if $v.IPAddress}}{{println $v.IPAddress}}{{end}}{{end}}' amnezia-dns | head -n1)"
DNS_PID="$(docker inspect -f '{{.State.Pid}}' amnezia-dns)"
AWG_PID="$(docker inspect -f '{{.State.Pid}}' "$AWG")"
+3 -2
View File
@@ -43,7 +43,7 @@ awg2-harness --config /etc/awg2-harness/config.toml status
```bash
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
C="$(docker ps --format '{{.Names}}' | grep -E '^(amnezia-awg2|amnezia-awg3|amnezia-awg)$' | head -n1)"
C="$(docker ps --format '{{.Names}}' | grep -E '^(amnezia-awg2|amnezia-awg)$' | head -n1)"
docker port "$C"
docker exec "$C" awg show
docker inspect -f 'ports={{json .NetworkSettings.Ports}}' amnezia-dns
@@ -55,11 +55,12 @@ docker inspect -f 'ports={{json .NetworkSettings.Ports}}' amnezia-dns
docker exec "$C" readlink -f /usr/bin/wg # ожидается /usr/bin/awg
docker exec "$C" awg --version
docker exec "$C" ip -o link show awg0
docker exec "$C" ip -d link show awg0
docker exec "$C" awg show all allowed-ips
docker exec "$C" awg show all dump | awk -F '\t' '{ print "row=" NR, "fields=" NF, "interface=" $1 }'
```
Interface-строка `awg show all dump` даёт 14 полей на AWG 2.0 и 28 на AWG 3.0, peer-строки — 9. Полный вывод `awg show all dump` передавать нельзя: во второй колонке interface-строки находится приватный ключ устройства.
Reference AWG 3.1 tools `v3.1.20260812` дают 30 полей interface-row и 9 полей peer-row. Исторически WireGuard/AWG 2.x/AWG 3.0 interface-row имели 5/14/28 полей. Width используется только как acceptance evidence: harness не определяет по нему версию и не классифицирует peer. Полный вывод `awg show all dump` передавать нельзя: во второй колонке interface-row находится приватный ключ устройства. Точная upstream-база приведена в [`UPSTREAM_COMPATIBILITY.md`](UPSTREAM_COMPATIBILITY.md).
Проверка, что runtime config создан вручную (ожидаемое поведение):
+6 -5
View File
@@ -3,11 +3,12 @@
Рекомендуемый порядок чтения:
1. [`../README.md`](../README.md) — общий runtime-план: SSH, официальная Amnezia, установка пакета, preflight, проверка перезагрузкой и CLI.
2. [`INSTALLATION.md`](INSTALLATION.md) — сжатый порядок установки на production.
3. [`CONFIGURATION.md`](CONFIGURATION.md) — параметры `/etc/awg2-harness/config.toml`.
4. [`ACCEPTANCE_CHECKLIST.md`](ACCEPTANCE_CHECKLIST.md) — чек-лист приёмки перед статусом production-ready.
5. [`ANTI_TORRENT.md`](ANTI_TORRENT.md) — ограничение числа соединений через nftables.
6. [`IMPLEMENTATION_SPEC.md`](IMPLEMENTATION_SPEC.md) — архитектура и reconciliation состояния.
2. [`UPSTREAM_COMPATIBILITY.md`](UPSTREAM_COMPATIBILITY.md) — канонический контракт совместимости с AmneziaWG.
3. [`INSTALLATION.md`](INSTALLATION.md) — сжатый порядок установки на production.
4. [`CONFIGURATION.md`](CONFIGURATION.md) — параметры `/etc/awg2-harness/config.toml`.
5. [`ACCEPTANCE_CHECKLIST.md`](ACCEPTANCE_CHECKLIST.md) — чек-лист приёмки перед статусом production-ready.
6. [`ANTI_TORRENT.md`](ANTI_TORRENT.md) — ограничение числа соединений через nftables.
7. [`IMPLEMENTATION_SPEC.md`](IMPLEMENTATION_SPEC.md) — архитектура и reconciliation состояния.
Отдельно:
+79
View File
@@ -0,0 +1,79 @@
# Совместимость с upstream AmneziaWG
Этот документ — канонический источник сведений о версиях AmneziaWG, с которыми сверяется AWG2 Harness. Остальная документация не должна дублировать плавающий набор upstream-версий: она ссылается сюда.
## Статус релиза 0.3.1
AWG2 Harness 0.3.1 проверен по официальной документации и исходникам AmneziaWG 3.1 по состоянию на 28 августа 2026 года. Это означает **source-validated against AWG 3.1**, но не заменяет live-приёмку на production-сервере.
Основной сценарий:
- self-hosted AmneziaWG 3.1;
- AmneziaVPN 5.0.1.5 или новее;
- чистая установка AWG 3.1 через AmneziaVPN;
- контейнер `amnezia-awg2`;
- интерфейс `awg0`;
- чтение состояния через `awg`, с fallback на `wg`.
AWG 3.0 и 2.x остаются regression compatibility. Контейнер `amnezia-awg` поддерживается как legacy fallback. Название AWG2 Harness является именем продукта и пакета, а не ограничением на версию протокола.
## Зафиксированная upstream-база
| Компонент | Версия или ревизия | Назначение |
|---|---|---|
| AmneziaVPN | `5.0.1.5`, tag `7d4f3e0f5090b74903609179653d1f669d2ad08a` | Self-hosted deployment AWG 3.1 и container contract |
| `amneziawg-tools` | `v3.1.20260812`, commit `ee0f0a9aa34ff0a0da4b3433b9512781cfe02843` | CLI, `awg-quick`, формат `show all dump` |
| `amneziawg-go` | `v3.1.20260814`, commit `1b86b2ae0e493e7ea93f8c1a0f0cb6735b1551f1` | userspace fallback и reference container image |
Официальные источники:
- [FAQ: установка AWG 3.1 на self-hosted-сервер](https://docs.amnezia.org/ru/faq/);
- [поддерживаемые серверные ОС и архитектуры](https://docs.amnezia.org/ru/documentation/supported-linux-os-for-vps/);
- [отображение `DockerContainer::Awg2` в `amnezia-awg2`](https://github.com/amnezia-vpn/amnezia-client/blob/7d4f3e0f5090b74903609179653d1f669d2ad08a/client/core/utils/containers/containerUtils.cpp);
- [`show all dump` в tools v3.1.20260812](https://github.com/amnezia-vpn/amneziawg-tools/blob/v3.1.20260812/src/show.c);
- [kernel-first и userspace fallback в `awg-quick`](https://github.com/amnezia-vpn/amneziawg-tools/blob/v3.1.20260812/src/wg-quick/linux.bash);
- [Dockerfile `amneziawg-go v3.1.20260814`](https://github.com/amnezia-vpn/amneziawg-go/blob/v3.1.20260814/Dockerfile).
Клиентский Dockerfile AmneziaVPN использует `amneziavpn/amneziawg-go:latest`. Поэтому перечисленные теги являются воспроизводимой reference/source baseline, но не обещанием, что любой будущий контейнер с тегом `latest` содержит те же сборки. Фактические версии проверяются во время live-приёмки.
## Контракт контейнера и tools
Default discovery имеет такой порядок:
```toml
container_names = ["amnezia-awg2", "amnezia-awg"]
wg_binaries = ["awg", "wg"]
```
Отдельного официального типа или имени `amnezia-awg3` в зафиксированной версии клиента нет. Оператор может вручную указать другое корректное имя контейнера в `amnezia.container_names`.
Reference image содержит `/usr/bin/awg`, `/usr/bin/awg-quick` и symlinks `/usr/bin/wg -> /usr/bin/awg`, `/usr/bin/wg-quick -> /usr/bin/awg-quick`.
## Kernel и userspace
`awg-quick` сначала выполняет `ip link add <interface> type amneziawg`. Если kernel implementation недоступна, запускается `amneziawg-go`.
Harness не выбирает реализацию и не требует конкретную из них. Peer state читается через `docker exec` официальным `awg` внутри контейнера. Это единая container-side точка доступа для kernel и userspace вариантов и не создаёт зависимости от версии host-side tools.
## Контракт `show all dump`
Исторические widths являются диагностикой:
| Producer | Interface-row | Peer-row |
|---|---:|---:|
| WireGuard tools | 5 | 9 |
| AWG 2.x tools | 14 | 9 |
| AWG 3.0 tools | 28 | 9 |
| AWG 3.1 tools `v3.1.20260812` | 30 | 9 |
В AWG 3.1 поля `RandomTrailers` и `DisableCookies` добавлены перед `fwmark`. Peer representation осталось девятиполевым.
**Количество колонок interface-row никогда не используется harness для определения версии протокола или классификации peer.** Версия tools определяет ширину interface-row, а новые tools могут печатать широкую строку и для конфигурации со старыми параметрами. Parser классифицирует peer семантически по allowed IPs и числовым handshake/RX/TX полям.
Полный interface-row нельзя публиковать в отчётах: во второй колонке находится приватный ключ устройства. Для диагностики выводятся только номер строки, число полей и имя интерфейса.
## Переход с AWG 2.0
Официальная модель перехода на AWG 3.1 — удалить AmneziaWG с сервера, установить заново новый контейнер, повторно создать пользователей и выпустить новые connection keys/configuration files.
Harness не выполняет эту миграцию, не читает и не меняет `awg0.conf`, не генерирует ключи и не управляет протокольными параметрами. Основной документированный путь для 0.3.1 — clean installation. Live acceptance выполняется после того, как AmneziaVPN завершила установку AWG 3.1.