431732396b
Two release blockers, the first a regression introduced by dd5be47.
1. The anti-torrent batch was applied on the host.
Making the rebuild atomic moved it from run_step(transport, ..) to run_nft_batch(script),
and run_nft_batch spawned `nft` directly with Command::new. An nft transaction belongs to
the network namespace of the process that runs nft, so with the production default
apply_in_amnezia_netns = true the sequence became: inspect inside the container, install
the table on the host, verify inside the container, fail. The guard was silently
ineffective, a stray table accumulated on the host, and the next reconcile could fail on
`add table` because the host copy already existed.
NsTransport gains run_with_stdin, implemented for all three transports - host, nsenter,
and docker exec with -i, which is required or the child sees EOF immediately.
run_nft_batch now takes the transport, and both callers pass the one they inspected
with. A recording fake transport asserts the script goes through the transport rather
than to a host process, which is the regression this could not previously catch.
2. Swap replacement rolled back with the wrong priority and not from every branch.
The rollback reactivated with desired.priority - the value that may be exactly what the
kernel had just rejected - because the previously active priority was dropped at the
match arm and never passed in. The active entry's priority is now carried into
replace_active_swapfile and used by the rollback.
Three early failure branches also returned without undoing anything: a failed swapoff of
the original, a failed rename to .previous, and a failed swapoff of the staging file all
left the staging swap active and the transition half-applied, after which the next
reconcile tried to unlink a file that was still active and could not proceed.
The transition now records what it completed - staging_active, original_active,
original_moved, new_installed - and one rollback undoes exactly that much, in an order
that never leaves the host without swap: restore the original file, reactivate it at its
previous priority, confirm it, and only then release and remove the staging swap. The
returned error carries the original cause plus what the recovery achieved.
Leftovers from a killed process are no longer removed blindly. A .new or .previous that
is still active cannot be unlinked, so it is reported with the swapoff command that
clears it instead of failing the same way on every reconcile.
Also in this commit, from the same audit:
- Requires=docker.service dropped in favour of Wants=. The daemon is built to outlive
Docker being down, but Requires= had systemd stop the harness whenever Docker stopped,
and Restart=on-failure does not cover a dependency-ordered stop - so the reconnect loop
never got to run.
- apply_antitorrent_disabled swallowed every discover_target error, not just "no container
running". Docker being unreachable or a permission error on the socket reported success
for a cleanup that never happened. Only AppError::NotFound is tolerated now.
- FstabTransaction::begin asserts /etc/fstab is a regular non-symlink file. read_to_string
and metadata both follow links, so a symlinked fstab would be read through and then
replaced by the rename, detaching the real file from the path the system boots from.
- append_event serialises its read-modify-write behind a mutex; the reconcile loop and the
Docker events thread both append and could drop an entry.
- tool_exists loses the fallocate, chmod and dd arms, dead since mkswap --file replaced the
allocation chain.
Docs corrected where they no longer matched the code: findmnt is described as mandatory
rather than skippable, the swap creation wording is mkswap --file, and the README package
examples use 0.1.6 to match Cargo.toml. Remaining fallocate mentions are explicitly
historical ("the previous chain"), which is accurate.
Seven tests added: batch routed through the given transport, batch failure reported as
such, rollback state defaults and previous-priority carry, active leftovers reported rather
than deleted, inactive leftovers cleared.
cargo fmt --check, clippy -D warnings, cargo test --locked --workspace --release: 188 + 4
passed.
395 lines
22 KiB
Markdown
395 lines
22 KiB
Markdown
# AWG2 Harness
|
||
|
||
`AWG2 Harness` — host-side orchestrator для выделенного Debian-хоста с self-hosted AmneziaWG. Пакет управляет инфраструктурным состоянием вокруг Amnezia: per-peer traffic shaping, IFB ingress shaping, nftables host firewall, anti-torrent connection guard, managed swap, диагностикой drift и плановым reboot.
|
||
|
||
Проект разрабатывался и проверялся под AmneziaWG/AWG 2.0 и совместимый legacy-сценарий AmneziaWG/AWG 1.5. Он не заменяет AmneziaVPN, не генерирует ключи клиентов и не меняет продуктовую логику Amnezia. Amnezia сначала ставится официальным способом, после этого устанавливается AWG2 Harness.
|
||
|
||
## Что ставит пакет
|
||
|
||
```text
|
||
/usr/sbin/awg2-harness # основной orchestrator
|
||
/usr/sbin/awg2-reboot-scheduler # отдельный reboot scheduler
|
||
/lib/systemd/system/awg2-harness.service
|
||
/lib/systemd/system/awg2-reboot-scheduler.service
|
||
```
|
||
|
||
`awg2-harness.service` запускает только daemon; `ensure-swap` выполняется первым этапом его собственной startup-последовательности, а не отдельным `ExecStartPre`. Дальше daemon в фоне держит drift recovery. Daemon слушает Docker events и дополнительно делает периодический reconcile для `traffic`/`firewall`/`swap`; `sysctl_tuning` применяется только на старте daemon (если включён) или вручную отдельной командой. `awg2-reboot-scheduler.service` отдельно читает общий config, выбирает случайное время в заданном UTC-окне и запрашивает reboot через `systemctl --no-block reboot`.
|
||
|
||
Пакет **не** устанавливает Docker, **не** устанавливает AmneziaVPN, **не** включает сервисы автоматически и **не** создаёт боевой `/etc/awg2-harness/config.toml`. Это сделано намеренно: SSH, Amnezia и боевой config должны быть подготовлены оператором до включения firewall/reconcile.
|
||
|
||
## Репозиторий
|
||
|
||
```text
|
||
awg2_harness/
|
||
├── reboot_module/ # исходники awg2-reboot-scheduler
|
||
├── traffic_core/ # исходники awg2-harness
|
||
├── tools/ # build/package tooling
|
||
├── docs/ # эксплуатационная документация
|
||
├── config.example.toml # пример боевого конфига
|
||
├── awg2-harness.service # основной systemd unit
|
||
└── awg2-reboot-scheduler.service # reboot scheduler unit
|
||
```
|
||
|
||
## Runtime-план production-развёртывания
|
||
|
||
Ниже целевой порядок установки. Его смысл простой: сначала безопасный SSH, потом официальная Amnezia, потом AWG2 Harness.
|
||
|
||
### 1. Подготовить Debian-хост
|
||
|
||
Целевая платформа AWG2 Harness — только Debian 13 amd64 на KVM/полноценной VM или dedicated host.
|
||
|
||
Минимальный baseline перед установкой Amnezia:
|
||
|
||
```bash
|
||
apt update
|
||
apt install -y openssh-server ca-certificates curl
|
||
timedatectl set-timezone Etc/UTC
|
||
```
|
||
|
||
### 2. Настроить SSH до установки Amnezia
|
||
|
||
Production-пример использует порт `2323` и вход только по ключу.
|
||
|
||
Сгенерируйте отдельную пару ключей для Amnezia на Windows (RSA PEM-формат):
|
||
|
||
```cmd
|
||
ssh-keygen -t rsa -b 4096 -m PEM -f %USERPROFILE%\.ssh\amnezia_key
|
||
```
|
||
|
||
Дальше контракт строго такой:
|
||
|
||
- на сервер добавляется **публичный** ключ: содержимое `%USERPROFILE%\.ssh\amnezia_key.pub` в `/root/.ssh/authorized_keys`;
|
||
- в приложении AmneziaVPN в поле **Password or SSH private key** вставляется **приватный** ключ: содержимое `%USERPROFILE%\.ssh\amnezia_key` (без `.pub`).
|
||
|
||
Критично: `.pub` никогда не вставляется в AmneziaVPN как private key.
|
||
|
||
```bash
|
||
install -d -m 0700 /root/.ssh
|
||
nano /root/.ssh/authorized_keys
|
||
chmod 0600 /root/.ssh/authorized_keys
|
||
```
|
||
|
||
Затем включите отдельный drop-in для порта и key-only login:
|
||
|
||
```bash
|
||
install -d -m 0755 /etc/ssh/sshd_config.d
|
||
cat >/etc/ssh/sshd_config.d/99-awg2-production.conf <<'EOF'
|
||
Port 2323
|
||
PermitRootLogin prohibit-password
|
||
PasswordAuthentication no
|
||
KbdInteractiveAuthentication no
|
||
PubkeyAuthentication yes
|
||
EOF
|
||
|
||
sshd -t
|
||
systemctl reload ssh 2>/dev/null || systemctl reload sshd
|
||
ss -ltnp | grep ':2323'
|
||
```
|
||
|
||
Критично: не закрывайте старую SSH-сессию, пока не проверили новый вход с другого терминала:
|
||
|
||
```bash
|
||
ssh -i ~/.ssh/amnezia_key -p 2323 root@<server-ip>
|
||
```
|
||
|
||
Windows-проверки:
|
||
|
||
```cmd
|
||
type %USERPROFILE%\.ssh\amnezia_key.pub
|
||
type %USERPROFILE%\.ssh\amnezia_key
|
||
ssh -i %USERPROFILE%\.ssh\amnezia_key -p 2323 root@<server-ip>
|
||
```
|
||
|
||
Поля в интерфейсе AmneziaVPN:
|
||
|
||
```text
|
||
Server IP address [:port] <server-ip>:2323
|
||
SSH Username root
|
||
Password or SSH private key содержимое %USERPROFILE%\.ssh\amnezia_key
|
||
На сервер содержимое %USERPROFILE%\.ssh\amnezia_key.pub в /root/.ssh/authorized_keys
|
||
```
|
||
|
||
Если сервер уже переведён на 2323 случайно и нужно временно вернуть 22 для тестов, поменяйте `Port 2323` на `Port 22`, выполните `sshd -t`, `systemctl reload ssh` и проверьте `ss -ltnp | grep ':22'`.
|
||
|
||
### 3. Установить AmneziaVPN официальным способом
|
||
|
||
AWG2 Harness не устанавливает Amnezia. Используйте официальный self-hosted flow AmneziaVPN:
|
||
|
||
1. Установите актуальное приложение AmneziaVPN на рабочую машину.
|
||
2. В приложении выберите self-hosted server.
|
||
3. Укажите публичный IPv4 сервера, SSH-порт, SSH-пользователя и приватный ключ.
|
||
4. Установите AmneziaWG/AWG. Для AWG 2.0 нужен актуальный AmneziaVPN, где протокол AmneziaWG 2.0 доступен в списке протоколов.
|
||
5. После установки убедитесь, что контейнер поднят и UDP-порт опубликован.
|
||
|
||
Проверка на сервере:
|
||
|
||
```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)"
|
||
echo "container=$C"
|
||
docker port "$C"
|
||
docker exec "$C" awg show
|
||
```
|
||
|
||
Ожидаемые имена контейнера по умолчанию: `amnezia-awg2` или `amnezia-awg`. `amnezia-awg3` перечислен на будущее — в AmneziaVPN 5.0 такого типа контейнера ещё нет. Ожидаемый интерфейс внутри container netns: обычно `awg0`, fallback-кандидаты описаны в `config.example.toml`.
|
||
|
||
### Совместимость с AmneziaWG 3.0
|
||
|
||
Проверено по исходникам на: AmneziaVPN `5.0.0.5`, `amneziawg-tools` и `amneziawg-go` ветки `master` на момент правки. Утверждения ниже относятся к этим версиям; при более новых релизах их нужно перепроверить, а не считать бессрочными.
|
||
|
||
Обвязка не реализует AWG на уровне пакетов: `tc`, IFB и `nftables` работают с inner-IP уже после декапсуляции, поэтому header protection, content padding и рандомизация таймеров AWG 3.0 её не касаются.
|
||
|
||
Читается только peer state, всегда через `docker exec`. Реальный бинарь в официальном образе — `/usr/bin/awg`, `/usr/bin/wg` является symlink на него; порядок задаётся `amnezia.wg_binaries` (по умолчанию `["awg", "wg"]`). На хосте `wireguard-tools` не требуется и не проверяется в preflight: AmneziaWG — userspace-реализация, её UAPI-сокет лежит в mount namespace контейнера, и хостовый `wg` через `nsenter -n` до него не достаёт.
|
||
|
||
Smoke-проверка после обновления контейнера:
|
||
|
||
```bash
|
||
C="$(docker ps --format '{{.Names}}' | grep -E '^(amnezia-awg2|amnezia-awg3|amnezia-awg)$' | head -n1)"
|
||
|
||
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" awg show all allowed-ips
|
||
docker port "$C"
|
||
|
||
# Структура dump без раскрытия значений:
|
||
docker exec "$C" awg show all dump | awk -F '\t' '{ print "row=" NR, "fields=" NF, "interface=" $1 }'
|
||
```
|
||
|
||
Ожидаемо: `/usr/bin/wg` указывает на `/usr/bin/awg`, интерфейс `awg0` существует, peer-адреса отображаются, серверный порт опубликован по UDP. Peer-строки дают 9 полей.
|
||
|
||
Ширина interface-строки зависит от версии `amneziawg-tools`, а не от версии параметров в конфигурации: утилиты AWG 3.0 печатают расширенную строку и для туннеля, настроенного как AWG 2.0. По количеству колонок определять версию протокола нельзя, и обвязка этого не делает.
|
||
|
||
Полный вывод `awg show all dump` передавать нельзя: во второй колонке interface-строки находится приватный ключ устройства.
|
||
|
||
### 3.1 Установить AmneziaDNS (обязательный production-шаг)
|
||
|
||
Для production-профиля AWG2 установите AmneziaDNS из приложения AmneziaVPN после установки AmneziaWG/AWG:
|
||
|
||
```text
|
||
AmneziaVPN:
|
||
Servers → <server> → Services → AmneziaDNS → Install
|
||
```
|
||
|
||
Затем включите использование DNS для подключения:
|
||
|
||
```text
|
||
Settings → Connection → DNS servers → Use AmneziaDNS
|
||
```
|
||
|
||
Security note:
|
||
|
||
В ожидаемой production-схеме AmneziaDNS слушает `53/tcp` и `53/udp` внутри Docker и не публикуется на host interface. Не открывайте публично `53/tcp` или `53/udp` в host firewall; DNS должен быть доступен только через VPN-path.
|
||
|
||
### 4. Собрать пакет на build-machine
|
||
|
||
На production-хосте не нужны Rust, cargo и source tree. Сборка делается отдельно.
|
||
|
||
```bash
|
||
cd awg2_harness
|
||
./tools/build.sh --prepare-build-env --bootstrap-rust --yes
|
||
./tools/build.sh --package --version 0.1.6
|
||
(cd dist && sha256sum -c SHA256SUMS)
|
||
dpkg-deb -I dist/awg2-harness_0.1.6_amd64.deb
|
||
dpkg-deb -c dist/awg2-harness_0.1.6_amd64.deb | sort
|
||
```
|
||
|
||
`--version` можно не указывать, если версия в `traffic_core/Cargo.toml` уже соответствует release. Если version override указан, он меняет версию Debian-пакета, а не версию crate в `Cargo.toml`.
|
||
|
||
### 5. Перенести `.deb` и config на production
|
||
|
||
Есть два production-сценария установки.
|
||
|
||
#### Вариант A: config передаётся вместе с `.deb`
|
||
|
||
```bash
|
||
scp -P 2323 dist/awg2-harness_*_amd64.deb root@<server-ip>:/root/
|
||
scp -P 2323 dist/SHA256SUMS root@<server-ip>:/root/
|
||
scp -P 2323 config.example.toml root@<server-ip>:/root/awg2-harness.config.toml
|
||
```
|
||
|
||
Перед установкой отредактируйте `/root/awg2-harness.config.toml`: SSH-порт должен совпадать с реальным sshd, `amnezia_port` — с опубликованным UDP-портом контейнера, `peer_ipv4_cidr` — с подсетью клиентов Amnezia.
|
||
|
||
#### Вариант B (основной): config создаётся после установки пакета
|
||
|
||
```bash
|
||
scp -P 2323 dist/awg2-harness_*_amd64.deb root@<server-ip>:/root/
|
||
scp -P 2323 dist/SHA256SUMS root@<server-ip>:/root/
|
||
```
|
||
|
||
### 6. Установить пакет и config
|
||
|
||
Вариант A:
|
||
|
||
```bash
|
||
cd /root
|
||
sha256sum -c SHA256SUMS
|
||
chmod 644 /root/awg2-harness_0.1.6_amd64.deb
|
||
apt install ./awg2-harness_*_amd64.deb
|
||
install -d -m 0755 /etc/awg2-harness
|
||
install -m 0644 /root/awg2-harness.config.toml /etc/awg2-harness/config.toml
|
||
```
|
||
|
||
Пакет ставит пример config в `/usr/share/doc/awg2-harness/repo/config.example.toml`, но не копирует его в `/etc` автоматически.
|
||
|
||
Вариант B (основной):
|
||
|
||
```bash
|
||
cd /root
|
||
sha256sum -c SHA256SUMS
|
||
chmod 644 /root/awg2-harness_0.1.6_amd64.deb
|
||
apt install ./awg2-harness_*_amd64.deb
|
||
install -d -m 0755 /etc/awg2-harness
|
||
cp /usr/share/doc/awg2-harness/repo/config.example.toml /etc/awg2-harness/config.toml
|
||
nano /etc/awg2-harness/config.toml
|
||
```
|
||
|
||
В варианте B после `cp` обязательно проверьте перед первым `apply-firewall`:
|
||
|
||
- `host_firewall.ssh_port` совпадает с реальным sshd-портом;
|
||
- `host_firewall.amnezia_port` совпадает с published Docker UDP port;
|
||
- `amnezia.peer_ipv4_cidr` и `anti_torrent.peer_ipv4_cidr` совпадают с реальной peer-подсетью.
|
||
|
||
### 7. Ручная preflight-проверка
|
||
|
||
```bash
|
||
awg2-harness --config /etc/awg2-harness/config.toml validate-config
|
||
awg2-harness --config /etc/awg2-harness/config.toml validate-runtime
|
||
awg2-harness --config /etc/awg2-harness/config.toml ensure-swap
|
||
awg2-harness --config /etc/awg2-harness/config.toml apply-firewall
|
||
awg2-harness --config /etc/awg2-harness/config.toml apply-limits
|
||
awg2-harness --config /etc/awg2-harness/config.toml status
|
||
```
|
||
|
||
Ожидаемый healthy state:
|
||
|
||
```text
|
||
System:
|
||
service: inactive # до enable --now нормально
|
||
Traffic actual:
|
||
drift: no
|
||
Host firewall:
|
||
drift: no
|
||
Anti-torrent:
|
||
drift: no
|
||
Swap:
|
||
drift: no
|
||
```
|
||
|
||
Если peers ещё нет, `apply-limits` корректно напишет `no peers found, skip tc apply`. Это не ошибка: traffic topology строится, когда есть хотя бы один peer allowed IP в целевой подсети.
|
||
|
||
### 8. Включить systemd services
|
||
|
||
```bash
|
||
systemctl daemon-reload
|
||
systemctl enable --now awg2-harness.service
|
||
systemctl enable --now awg2-reboot-scheduler.service
|
||
|
||
systemctl status awg2-harness.service --no-pager -l
|
||
systemctl status awg2-reboot-scheduler.service --no-pager -l
|
||
journalctl -u awg2-harness.service --since '5 minutes ago' --no-pager
|
||
journalctl -u awg2-reboot-scheduler.service --since '5 minutes ago' --no-pager
|
||
```
|
||
|
||
После 30–60 секунд:
|
||
|
||
```bash
|
||
awg2-harness --config /etc/awg2-harness/config.toml status
|
||
```
|
||
|
||
Healthy daemon показывает `service: active`, `traffic=ok`, `firewall=ok`, `swap=ok` в recent events и пустой `last_error`.
|
||
|
||
### 9. Проверить после reboot
|
||
|
||
```bash
|
||
reboot
|
||
```
|
||
|
||
После возврата:
|
||
|
||
```bash
|
||
systemctl status docker --no-pager -l
|
||
systemctl status awg2-harness.service --no-pager -l
|
||
systemctl status awg2-reboot-scheduler.service --no-pager -l
|
||
awg2-harness --config /etc/awg2-harness/config.toml status
|
||
```
|
||
|
||
Дополнительно можно проверить фактическую `tc` topology внутри network namespace Amnezia:
|
||
|
||
```bash
|
||
C="$(docker ps --format '{{.Names}}' | grep -E '^(amnezia-awg2|amnezia-awg3|amnezia-awg)$' | head -n1)"
|
||
PID="$(docker inspect -f '{{.State.Pid}}' "$C")"
|
||
|
||
nsenter -t "$PID" -n -- tc class show dev awg0
|
||
nsenter -t "$PID" -n -- tc class show dev ifb0
|
||
nsenter -t "$PID" -n -- nft list table inet awg2_harness
|
||
nft list table inet awg2_host_firewall
|
||
```
|
||
|
||
Для default config на одном peer ожидаются классы `1:10` и `2:10` с `rate 50Mbit ceil 50Mbit`, root classes `1:1` и `2:1` с `500Mbit`, host firewall table `inet awg2_host_firewall` и anti-torrent table `inet awg2_harness` внутри Amnezia netns.
|
||
|
||
## CLI команды
|
||
|
||
Все команды принимают `--config`. Если параметр не указан, используется `/etc/awg2-harness/config.toml`.
|
||
|
||
```bash
|
||
awg2-harness --config /etc/awg2-harness/config.toml <command>
|
||
```
|
||
|
||
`validate-config` проверяет TOML и смысловые ограничения: пустые списки, формат rate (`50mbit`, `500mbit`), CIDR, reboot window, swap path, SSH/Amnezia ports, protocol list.
|
||
|
||
`validate-runtime` проверяет host tools, которые реально нужны выбранным модулям: `tc`, `ip`, `docker`, `modprobe`, `nsenter`, а также `nft`, `systemctl`, swap tooling при включённых firewall/reboot/swap. Хостовый `wg` в этот список не входит: peer state читается внутри контейнера через `docker exec` (`amnezia.wg_binaries`).
|
||
|
||
`ensure-swap` приводит swap к desired state: создаёт/проверяет swapfile, включает его с заданным priority, применяет `vm.swappiness`, делает swap state exclusive и переписывает swap entries в `/etc/fstab` под управляемый swapfile.
|
||
|
||
`apply-firewall` делает два reconcile: host INPUT firewall в таблице `inet awg2_host_firewall` и anti-torrent guard в выбранном namespace. Команда не управляет Docker NAT и host `FORWARD`.
|
||
|
||
`apply-limits` находит Amnezia container, заходит в его network namespace, читает peers через `wg`, строит per-peer HTB/fq_codel классы на AWG/WG интерфейсе и IFB ingress path. Если drift не найден, пишет `traffic rules up-to-date, skip apply`.
|
||
|
||
`status` печатает фактическую диагностику: сервис, контейнер, netns, интерфейс, peers, WireGuard runtime, traffic desired/actual, host firewall drift, Docker/Amnezia port path, anti-torrent counters, swap state, conntrack, recent events и planned reboot.
|
||
|
||
`daemon` — режим для systemd. На старте делает startup reconcile, затем слушает Docker events и периодически сверяет traffic/swap/firewall. Вручную обычно не запускается, кроме отладки.
|
||
|
||
`awg2-reboot-scheduler --config /etc/awg2-harness/config.toml` читает только секцию `[reboot]`, пишет план в `/run/awg2-harness/reboot.plan` и ждёт назначенного UTC-времени.
|
||
|
||
## Что происходит под капотом
|
||
|
||
Traffic shaping реализован через `tc` в network namespace контейнера Amnezia. На egress используется root qdisc `htb 1:` на AWG/WG интерфейсе, root class `1:1`, per-peer classes `1:<id>` и `fq_codel` под каждым peer class. На ingress ставится `ingress ffff:` на AWG/WG интерфейс, входящие пакеты перенаправляются через `mirred` в `ifb0`, а там строится отдельная HTB topology `2:` с такими же per-peer лимитами.
|
||
|
||
Peer discovery берётся из WireGuard/AmneziaWG allowed IPs, а не из handshake state. Поэтому offline peer с `allowed ips: 10.8.1.1/32` тоже получает лимит заранее.
|
||
|
||
Host firewall — отдельная AWG2-owned таблица `inet awg2_host_firewall`. Она открывает loopback, established/related, SSH-порт из конфига, Amnezia-порт по указанным протоколам и optionally ICMP/ICMPv6. Docker-managed `FORWARD` и NAT не трогаются.
|
||
|
||
Anti-torrent guard — отдельная AWG2-owned таблица `inet awg2_harness` обычно внутри Amnezia netns. Правило ограничивает число новых conntrack flows per source VPN IP. Это не DPI и не распознавание BitTorrent-протокола; это грубый, дешёвый guard против сотен одновременных P2P-соединений.
|
||
|
||
Swap module намеренно строгий: если `swap.enabled=true`, desired state — один управляемый swapfile. Старые swap entries удаляются из `/etc/fstab`, block-device swap выключается, но block device не удаляется.
|
||
|
||
## Production-границы ответственности
|
||
|
||
AWG2 Harness владеет только собственным state:
|
||
|
||
- `tc` topology на Amnezia interface и configured `ifb_name`;
|
||
- nft table `inet awg2_host_firewall` в host namespace;
|
||
- nft table `inet awg2_harness` для anti-torrent;
|
||
- `/run/awg2-harness/*` runtime state;
|
||
- managed swapfile и swap entries, если `swap.enabled=true`.
|
||
|
||
AWG2 Harness не владеет:
|
||
|
||
- установкой AmneziaVPN;
|
||
- Docker daemon lifecycle;
|
||
- Docker NAT/FORWARD chains;
|
||
- генерацией client configs/keys;
|
||
- политикой пользователя внутри Amnezia app;
|
||
- сторонними firewall-таблицами.
|
||
|
||
## Документация
|
||
|
||
- [`docs/INSTALLATION.md`](docs/INSTALLATION.md) — установка и preflight.
|
||
- [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md) — параметры `config.toml`.
|
||
- [`docs/ACCEPTANCE_CHECKLIST.md`](docs/ACCEPTANCE_CHECKLIST.md) — production checklist.
|
||
- [`docs/ANTI_TORRENT.md`](docs/ANTI_TORRENT.md) — connection-count guard.
|
||
- [`docs/PRODUCTION_EXAMPLE.md`](docs/PRODUCTION_EXAMPLE.md) — эталонный production-пример.
|
||
- [`tools/README.md`](tools/README.md) — сборка и упаковка.
|
||
- [`reboot_module/README.md`](reboot_module/README.md) — внешний reboot scheduler.
|