fix28: обновлена production-документация и упаковка docs в deb
This commit is contained in:
@@ -1,69 +1,285 @@
|
||||
# AWG2 Harness
|
||||
|
||||
`AWG2 Harness` — host-side multi-orchestrator на Rust для production-сервера с AmneziaWG/AWG 2.0.
|
||||
`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.
|
||||
|
||||
Это не просто перенос bash-скриптов на Rust. Целевая система должна воспроизвести и затем постоянно удерживать всё состояние, которое сейчас создаёт `Amnezia limits (old bash)`: discovery контейнера и интерфейса, список peers, per-peer traffic shaping в обе стороны, `tc` topology, `ifb0`, auto-healing после рестартов, диагностику, плановый reboot и swap setup, а также опциональный nftables anti-torrent guard через per-peer connection-count limit.
|
||||
Проект разрабатывался и проверялся под AmneziaWG/AWG 2.0 и совместимый legacy-сценарий AmneziaWG/AWG 1.5. Он не заменяет AmneziaVPN, не генерирует ключи клиентов и не меняет продуктовую логику Amnezia. Amnezia сначала ставится официальным способом, после этого устанавливается AWG2 Harness.
|
||||
|
||||
Сервер выделенный: Debian 13 amd64, SSH заранее настроен, рядом нет соседних сервисов, после установки Amnezia доставляется наш бинарь. Поэтому бинарь имеет право и обязан полностью управлять нужными правилами хоста и network namespace Amnezia, а не быть пассивной обёрткой, которая боится менять состояние системы. При этом он не форкает Amnezia и не меняет её продуктовую логику; он управляет инфраструктурным состоянием вокруг неё.
|
||||
|
||||
Текущий репозиторий:
|
||||
## Что ставит пакет
|
||||
|
||||
```text
|
||||
AWG2_harness/
|
||||
├── Amnezia limits (old bash)/ # production reference behavior
|
||||
├── reboot_module/ # production auxiliary binary: awg2-reboot-scheduler
|
||||
├── traffic_core/ # целевая зона для Rust traffic/orchestrator логики
|
||||
└── docs/ # документация по миграции, архитектуре и эксплуатации
|
||||
/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
|
||||
```
|
||||
|
||||
Production reboot path — внешний scheduler service [`awg2-reboot-scheduler.service`](awg2-reboot-scheduler.service).
|
||||
`awg2-harness.service` запускает `ensure-swap` перед стартом daemon, затем в фоне держит drift recovery. Daemon слушает Docker events и дополнительно делает периодический reconcile. `awg2-reboot-scheduler.service` отдельно читает общий config, выбирает случайное время в заданном UTC-окне и запрашивает reboot через `systemctl --no-block reboot`.
|
||||
|
||||
Важно: `Amnezia limits (old bash)` используется как эталон production-поведения, а `reboot_module` ставится как второй production-бинарь.
|
||||
Пакет **не** устанавливает Docker, **не** устанавливает AmneziaVPN, **не** включает сервисы автоматически и **не** создаёт боевой `/etc/awg2-harness/config.toml`. Это сделано намеренно: SSH, Amnezia и боевой config должны быть подготовлены оператором до включения firewall/reconcile.
|
||||
|
||||
## Production deployment model
|
||||
## Репозиторий
|
||||
|
||||
AWG2 Harness собирается на отдельной Debian 13 amd64 build-machine.
|
||||
```text
|
||||
awg2_harness/
|
||||
├── Amnezia limits (old bash)/ # исторический reference старой bash-схемы
|
||||
├── 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
|
||||
```
|
||||
|
||||
Production Amnezia-хост **не должен** требовать Rust, cargo, clippy, source tree и legacy bash-скрипты. На production-хост переносится готовый Debian-пакет и вручную подготовленный `/etc/awg2-harness/config.toml`.
|
||||
`Amnezia limits (old bash)` оставлен как historical reference, а не как runtime-зависимость. На production-хосте после перехода на `.deb` source tree и старые bash-скрипты не нужны.
|
||||
|
||||
Build machine:
|
||||
## Runtime-план production-развёртывания
|
||||
|
||||
Ниже целевой порядок установки. Его смысл простой: сначала безопасный SSH, потом официальная Amnezia, потом AWG2 Harness.
|
||||
|
||||
### 1. Подготовить Debian-хост
|
||||
|
||||
Целевая платформа проекта — Debian 13 amd64 на KVM/полноценной VM или dedicated host. Для Amnezia upstream также указывает Debian 12/13 и Ubuntu 22.04/24.04 как официально поддерживаемые OS, x86-64/amd64, публичный IPv4, SSH-доступ и Docker-based self-hosted deployment через приложение AmneziaVPN.
|
||||
|
||||
Минимальный baseline перед установкой Amnezia:
|
||||
|
||||
```bash
|
||||
apt update
|
||||
apt install -y openssh-server ca-certificates curl
|
||||
```
|
||||
|
||||
### 2. Настроить SSH до установки Amnezia
|
||||
|
||||
Production-пример использует порт `2323` и вход только по ключу. Сначала убедитесь, что публичный ключ уже добавлен в `~root/.ssh/authorized_keys` или в ключевой файл нужного sudo-пользователя.
|
||||
|
||||
```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 -p 2323 root@<server-ip>
|
||||
```
|
||||
|
||||
Если сервер уже переведён на 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-awg)$' | head -n1)"
|
||||
echo "container=$C"
|
||||
docker port "$C"
|
||||
docker exec "$C" wg show
|
||||
```
|
||||
|
||||
Ожидаемые имена контейнера по умолчанию: `amnezia-awg2` или `amnezia-awg`. Ожидаемый интерфейс внутри container netns: обычно `awg0`, fallback-кандидаты описаны в `config.example.toml`.
|
||||
|
||||
### 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
|
||||
./tools/build.sh --package --version 0.1.6
|
||||
sha256sum -c dist/SHA256SUMS
|
||||
dpkg-deb -I dist/awg2-harness_0.1.6_amd64.deb
|
||||
dpkg-deb -c dist/awg2-harness_0.1.6_amd64.deb | sort
|
||||
```
|
||||
|
||||
Копирование на production host:
|
||||
`--version` можно не указывать, если версия в `traffic_core/Cargo.toml` уже соответствует release. Если version override указан, он меняет версию Debian-пакета, а не версию crate в `Cargo.toml`.
|
||||
|
||||
### 5. Перенести `.deb` и config на production
|
||||
|
||||
```bash
|
||||
scp dist/awg2-harness_*_amd64.deb root@vpn-host:/root/
|
||||
scp config.toml root@vpn-host:/root/awg2-harness.config.toml
|
||||
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
|
||||
```
|
||||
|
||||
Production host:
|
||||
Перед установкой отредактируйте `/root/awg2-harness.config.toml`: SSH-порт должен совпадать с реальным sshd, `amnezia_port` — с опубликованным UDP-портом контейнера, `peer_ipv4_cidr` — с подсетью клиентов Amnezia.
|
||||
|
||||
### 6. Установить пакет и config
|
||||
|
||||
```bash
|
||||
cd /root
|
||||
sha256sum -c SHA256SUMS
|
||||
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
|
||||
awg2-harness validate-config --config /etc/awg2-harness/config.toml
|
||||
awg2-harness validate-runtime --config /etc/awg2-harness/config.toml
|
||||
awg2-harness apply-limits --config /etc/awg2-harness/config.toml
|
||||
awg2-harness apply-firewall --config /etc/awg2-harness/config.toml
|
||||
awg2-harness status --config /etc/awg2-harness/config.toml
|
||||
systemctl enable --now awg2-harness.service
|
||||
systemctl enable --now awg2-reboot-scheduler.service
|
||||
```
|
||||
|
||||
В production запускаются оба сервиса: [`awg2-harness.service`](awg2-harness.service) и [`awg2-reboot-scheduler.service`](awg2-reboot-scheduler.service).
|
||||
Пакет ставит пример config в `/usr/share/doc/awg2-harness/repo/config.example.toml`, но не копирует его в `/etc` автоматически.
|
||||
|
||||
Основная документация:
|
||||
### 7. Ручная preflight-проверка
|
||||
|
||||
- [`docs/MIGRATION.md`](docs/MIGRATION.md) — исправленная миграционная стратегия bash → Rust multi-orchestrator.
|
||||
- [`docs/OLD_BASH_BEHAVIOR.md`](docs/OLD_BASH_BEHAVIOR.md) — зафиксированное поведение старой bash-системы по файлам.
|
||||
- [`docs/IMPLEMENTATION_SPEC.md`](docs/IMPLEMENTATION_SPEC.md) — целевая архитектура бинаря и state reconciliation.
|
||||
- [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md) — единый `config.toml` без эксплуатационного мусора.
|
||||
- [`docs/INSTALLATION.md`](docs/INSTALLATION.md) — установка на Debian 13 amd64.
|
||||
```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-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`, `wg`, `docker`, `modprobe`, `nsenter`, а также `nft`, `systemctl`, swap tooling при включённых firewall/reboot/swap.
|
||||
|
||||
`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) — простая анти-торрент защита через nftables `ct count`.
|
||||
- [`docs/ANTI_TORRENT.md`](docs/ANTI_TORRENT.md) — connection-count guard.
|
||||
- [`tools/README.md`](tools/README.md) — сборка и упаковка.
|
||||
- [`reboot_module/README.md`](reboot_module/README.md) — внешний reboot scheduler.
|
||||
|
||||
Reference in New Issue
Block a user