From 69c737bcf4d295077a6d4bafd03a428edda1cf53 Mon Sep 17 00:00:00 2001 From: Crimson Date: Tue, 12 May 2026 16:56:36 +0500 Subject: [PATCH] =?UTF-8?q?fix28:=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20production-=D0=B4=D0=BE=D0=BA=D1=83=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B8=20=D1=83?= =?UTF-8?q?=D0=BF=D0=B0=D0=BA=D0=BE=D0=B2=D0=BA=D0=B0=20docs=20=D0=B2=20de?= =?UTF-8?q?b?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 288 ++++++++++++++++++++++++++++++----- docs/ACCEPTANCE_CHECKLIST.md | 4 +- docs/ANTI_TORRENT.md | 8 +- docs/CONFIGURATION.md | 8 +- docs/INSTALLATION.md | 158 +++++++++++++++---- docs/MIGRATION.md | 2 +- docs/README.md | 22 ++- reboot_module/README.md | 49 ++++-- tools/README.md | 90 +++++------ tools/build.sh | 9 +- 10 files changed, 488 insertions(+), 150 deletions(-) diff --git a/README.md b/README.md index b9710f1..76c877b 100644 --- a/README.md +++ b/README.md @@ -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@ +``` + +Если сервер уже переведён на 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@:/root/ +scp -P 2323 dist/SHA256SUMS root@:/root/ +scp -P 2323 config.example.toml root@:/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 +``` + +`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:` и `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. diff --git a/docs/ACCEPTANCE_CHECKLIST.md b/docs/ACCEPTANCE_CHECKLIST.md index 8523c69..a39115e 100644 --- a/docs/ACCEPTANCE_CHECKLIST.md +++ b/docs/ACCEPTANCE_CHECKLIST.md @@ -4,7 +4,7 @@ - [ ] Хост — Debian 13 amd64. - [ ] Сервер выделенный, без соседних сервисов. -- [ ] AmneziaWG/AWG 2.0 установлена официальным способом. +- [ ] AmneziaWG/AWG 2.0 или AmneziaWG/AWG 1.5 установлена официальным способом. - [ ] Контейнер `amnezia-awg2` или `amnezia-awg` запущен. - [ ] `docker ps` видит контейнер. - [ ] Можно получить PID контейнера. @@ -102,7 +102,7 @@ - [ ] Есть chain `forward_antitorrent` с hook `forward` и policy `accept`. - [ ] Правило ограничивает `ip saddr `, default `10.8.1.0/24`. - [ ] Лимит считается per source VPN IP через meter/set, а не глобально по всей подсети. -- [ ] Порог совпадает с `anti_torrent.max_connections_per_peer`, default `100`. +- [ ] Порог совпадает с `anti_torrent.max_connections_per_peer`; текущий пример config использует `150`, более строгий вариант — `100`. - [ ] Drop counter виден в `status`. - [ ] На first-run без table `awg2-harness apply-firewall` создаёт `table inet awg2_harness`, а не падает. - [ ] При превышении порога новые flows дропаются, established flows ниже порога не ломаются. diff --git a/docs/ANTI_TORRENT.md b/docs/ANTI_TORRENT.md index dabb900..1d75af6 100644 --- a/docs/ANTI_TORRENT.md +++ b/docs/ANTI_TORRENT.md @@ -65,18 +65,18 @@ table inet awg2_harness { ## 4. Threshold -Рекомендуемый default: +Рекомендуемый стартовый production baseline: ```toml [anti_torrent] enabled = true -max_connections_per_peer = 100 +max_connections_per_peer = 150 ``` Практические варианты: -- `100` — production default, более строгий режим. -- `150` — мягче, если есть жалобы на false positives. +- `100` — более строгий режим. +- `150` — текущий рекомендуемый стартовый baseline, мягче к обычному browsing/mobile traffic. - `200/250` — ещё более permissive варианты. - `70` — агрессивный режим только после наблюдения реального трафика. diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index e912ee0..022acd8 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -1,6 +1,6 @@ # Конфигурация AWG2 Harness -Конфиг живёт в `/etc/awg2-harness/config.toml`. Он общий для всего пакета и должен содержать только эксплуатационно значимые параметры. +AWG2 Harness разрабатывался для self-hosted AmneziaWG/AWG 2.0 и совместимого legacy-сценария AmneziaWG/AWG 1.5. Конфиг живёт в `/etc/awg2-harness/config.toml`. Он общий для всего пакета и должен содержать только эксплуатационно значимые параметры. ## Рекомендуемый `config.toml` @@ -30,7 +30,7 @@ default_input_policy = "drop" [anti_torrent] enabled = true -max_connections_per_peer = 100 +max_connections_per_peer = 150 peer_ipv4_cidr = "10.8.1.0/24" apply_in_amnezia_netns = true @@ -75,7 +75,7 @@ swappiness = 1 `host_firewall.enabled` — включает host-level INPUT firewall в отдельной AWG2-owned таблице `inet awg2_host_firewall`. -`host_firewall.ssh_port` — SSH порт хоста, который обязательно должен быть открыт. Production default: `2323`. +`host_firewall.ssh_port` — SSH порт хоста, который обязательно должен быть открыт. Production default/example: `2323`. Значение обязано совпадать с реально слушающим sshd портом до применения `apply-firewall`. `host_firewall.amnezia_port` — внешний UDP/TCP порт Amnezia, который AWG2 открывает в host `INPUT` (в зависимости от `host_firewall.amnezia_protocols`). Значение должно совпадать с портом, указанным в панели/инсталляторе AmneziaWG. В старых инсталляциях это мог быть `44344`, в новой целевой конфигурации default — `443`. @@ -91,7 +91,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. Default `100`; `250` — более мягкий вариант. +`anti_torrent.max_connections_per_peer` — максимум одновременных conntrack flows на один VPN peer IP. Текущий пример использует `150`: это мягче, чем строгий `100`, и обычно безопаснее как первый production baseline. `100` можно использовать как более жёсткий режим; `200/250` — более permissive варианты. `anti_torrent.peer_ipv4_cidr` — подсеть, на которую распространяется правило. Обычно должна совпадать с `amnezia.peer_ipv4_cidr`. diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md index efc3ae2..972ce99 100644 --- a/docs/INSTALLATION.md +++ b/docs/INSTALLATION.md @@ -1,78 +1,182 @@ # Installation +Этот документ описывает production-порядок установки AWG2 Harness. Подробный runtime-план с SSH hardening и Amnezia preflight находится в корневом [`README.md`](../README.md). + ## Deployment contract -- Build выполняется на отдельной Debian 13 amd64 build-machine. -- Production-хост получает готовый Debian-пакет. -- На production-хосте не требуются Rust/cargo/source tree. -- Amnezia должна быть уже установлена и работать через Docker. -- Production-конфиг создаётся вручную; [`config.example.toml`](../config.example.toml) не копируется автоматически как боевой конфиг. +- Целевой production-хост: Debian 13 amd64. +- Amnezia ставится до AWG2 Harness официальным self-hosted способом через приложение AmneziaVPN. +- Проект рассчитан на AmneziaWG/AWG 2.0 и compatible legacy-сценарий AmneziaWG/AWG 1.5. +- SSH должен быть заранее настроен. Production-пример: порт `2323`, вход по ключу, password login disabled. +- Production-хост получает готовый Debian-пакет; Rust/cargo/source tree на нём не требуются. +- `/etc/awg2-harness/config.toml` создаётся вручную. `config.example.toml` не копируется автоматически как боевой config. +- Пакет не устанавливает Docker/Amnezia и не включает services автоматически. ## A. Build machine -### A1. Подготовка build environment +### A1. Подготовить build environment ```bash +cd awg2_harness +chmod +x tools/build.sh ./tools/build.sh --prepare-build-env --bootstrap-rust --yes ``` -### A2. Build и тесты +### A2. Проверить код + +```bash +cargo fmt --manifest-path Cargo.toml --all --check +cargo clippy --locked --workspace --all-targets --manifest-path Cargo.toml -- -D warnings +cargo test --locked --workspace --release --manifest-path Cargo.toml +``` + +То же самое выполняет build helper: ```bash ./tools/build.sh --build ``` -### A3. Сборка пакета +### A3. Собрать Debian-пакет ```bash -./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 ``` -## B. Transfer artifacts +`--version` можно опустить, если версия в `traffic_core/Cargo.toml` уже равна release version. Version override влияет только на metadata `.deb`. + +## B. Подготовить production-хост + +### B1. SSH + +Production-пример: ```bash -scp dist/awg2-harness_*_amd64.deb root@vpn-host:/root/ -scp config.toml root@vpn-host:/root/awg2-harness.config.toml +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' ``` -## C. Production host - -### C1. Install package +Обязательно проверьте вход с нового терминала: ```bash +ssh -p 2323 root@ +``` + +### B2. Amnezia + +Установите AmneziaWG/AWG через официальное приложение AmneziaVPN в режиме self-hosted server. Вводите в приложении тот SSH host/port/user/private key, который реально работает после B1. + +Проверка после установки: + +```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 +``` + +Если контейнер называется иначе или интерфейс не `awg0`, отразите это в `/etc/awg2-harness/config.toml`. + +## C. Transfer artifacts + +```bash +scp -P 2323 dist/awg2-harness_*_amd64.deb root@:/root/ +scp -P 2323 dist/SHA256SUMS root@:/root/ +scp -P 2323 config.example.toml root@:/root/awg2-harness.config.toml +``` + +Перед установкой отредактируйте `/root/awg2-harness.config.toml`. Минимально проверьте: + +- `[host_firewall].ssh_port` совпадает с реальным SSH-портом (`2323` в production-примере); +- `[host_firewall].amnezia_port` совпадает с published UDP port Amnezia; +- `[amnezia].peer_ipv4_cidr` совпадает с подсетью clients; +- `[anti_torrent].peer_ipv4_cidr` обычно равен `[amnezia].peer_ipv4_cidr`; +- `peer_limit` и `root_rate` отражают нужную traffic policy. + +## D. Production install + +```bash +cd /root +sha256sum -c SHA256SUMS apt install ./awg2-harness_*_amd64.deb -``` - -### C2. Install config - -```bash install -d -m 0755 /etc/awg2-harness install -m 0644 /root/awg2-harness.config.toml /etc/awg2-harness/config.toml +systemctl daemon-reload ``` -### C3. Validate and apply +## E. Preflight before enable ```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-limits 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 ``` -When `swap.enabled=true`, AWG2 Harness will disable all other active swap entries and rewrite `/etc/fstab` swap entries to a single managed swapfile. +Expected healthy result: -### C4. Enable services +```text +Traffic actual: + drift: no +Host firewall: + drift: no +Anti-torrent: + drift: no +Swap: + drift: no +``` + +If there are no peers yet, `apply-limits` may print `no peers found, skip tc apply`. That is healthy for an empty server. + +When `swap.enabled=true`, AWG2 Harness intentionally makes swap exclusive: one managed swapfile, one fstab swap entry, configured swappiness. + +## F. Enable services ```bash 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 ``` -## D. Manual source-tree install (staging/debug only) +After 30–60 seconds: -Режим [`./tools/build.sh --install`](../tools/build.sh) предназначен для staging/debug с checkout-репозиторием. +```bash +awg2-harness --config /etc/awg2-harness/config.toml status +``` -Это **не** основной production deployment path. +## G. Reboot validation + +```bash +reboot +``` + +After reconnect: + +```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 +``` + +## H. Manual source-tree install + +`./tools/build.sh --install` and `./tools/build.sh --enable` exist for staging/debug. They are not the recommended production path. Use `.deb` on production. diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md index 8be8c70..6cd3c84 100644 --- a/docs/MIGRATION.md +++ b/docs/MIGRATION.md @@ -199,7 +199,7 @@ default_input_policy = "drop" [anti_torrent] enabled = true -max_connections_per_peer = 100 +max_connections_per_peer = 150 peer_ipv4_cidr = "10.8.1.0/24" apply_in_amnezia_netns = true diff --git a/docs/README.md b/docs/README.md index 3643aca..77b7809 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,10 +2,18 @@ Рекомендуемый порядок чтения: -1. [`OLD_BASH_BEHAVIOR.md`](OLD_BASH_BEHAVIOR.md) — что реально делает старая production bash-система. -2. [`MIGRATION.md`](MIGRATION.md) — corrected migration scope: Rust multi-orchestrator, а не механический bash port. -3. [`IMPLEMENTATION_SPEC.md`](IMPLEMENTATION_SPEC.md) — целевая архитектура и state reconciliation. -4. [`CONFIGURATION.md`](CONFIGURATION.md) — единый конфиг. -5. [`ANTI_TORRENT.md`](ANTI_TORRENT.md) — опциональный nftables guard против high-peer-count P2P. -6. [`INSTALLATION.md`](INSTALLATION.md) — установка на Debian 13 amd64. -7. [`ACCEPTANCE_CHECKLIST.md`](ACCEPTANCE_CHECKLIST.md) — критерии production-ready. +1. [`../README.md`](../README.md) — общий runtime-план: SSH, официальная Amnezia, установка пакета, preflight, reboot validation и CLI. +2. [`INSTALLATION.md`](INSTALLATION.md) — сжатый production install flow. +3. [`CONFIGURATION.md`](CONFIGURATION.md) — параметры `/etc/awg2-harness/config.toml`. +4. [`ACCEPTANCE_CHECKLIST.md`](ACCEPTANCE_CHECKLIST.md) — checklist перед production-ready статусом. +5. [`ANTI_TORRENT.md`](ANTI_TORRENT.md) — nftables connection-count guard. +6. [`IMPLEMENTATION_SPEC.md`](IMPLEMENTATION_SPEC.md) — архитектура и state reconciliation. +7. [`OLD_BASH_BEHAVIOR.md`](OLD_BASH_BEHAVIOR.md) — что делала старая bash-система. +8. [`MIGRATION.md`](MIGRATION.md) — контекст миграции с bash на Rust multi-orchestrator. + +Отдельно: + +- [`../tools/README.md`](../tools/README.md) — сборка и упаковка `.deb`. +- [`../reboot_module/README.md`](../reboot_module/README.md) — внешний reboot scheduler. + +Практический порядок для оператора: сначала выполнить root README, затем свериться с acceptance checklist. Остальные документы нужны для понимания design intent и отладки. diff --git a/reboot_module/README.md b/reboot_module/README.md index 099f9ce..7b6e92d 100644 --- a/reboot_module/README.md +++ b/reboot_module/README.md @@ -1,23 +1,40 @@ # awg2-reboot-scheduler -`awg2-reboot-scheduler` — production auxiliary binary в составе пакета AWG2 Harness. +`awg2-reboot-scheduler` — отдельный production-бинарь в составе пакета AWG2 Harness. Его задача узкая: один раз на старте прочитать секцию `[reboot]` из общего `/etc/awg2-harness/config.toml`, выбрать случайный момент внутри заданного UTC-окна, записать план в `/run/awg2-harness/reboot.plan` и в назначенное время запросить reboot через `systemctl --no-block reboot`. -Он читает общий конфиг [`/etc/awg2-harness/config.toml`](../config.example.toml), выбирает случайный момент в окне reboot и запрашивает перезагрузку через `systemctl --no-block reboot`. +Он вынесен отдельно от основного `awg2-harness daemon`, чтобы плановый reboot не зависел от traffic/firewall reconciliation loop. -## Production model +## Runtime paths -- binary: `/usr/sbin/awg2-reboot-scheduler` -- unit: [`/lib/systemd/system/awg2-reboot-scheduler.service`](../awg2-reboot-scheduler.service) -- config: `/etc/awg2-harness/config.toml` -- runtime plan file: `/run/awg2-harness/reboot.plan` - -Сервис ставится и управляется общим packaging flow [`tools/build.sh`](../tools/build.sh), вручную в `/opt/...` ничего не раскладывается. - -## Проверка на host - -```bash -awg2-reboot-scheduler --config /etc/awg2-harness/config.toml -systemctl status awg2-reboot-scheduler -journalctl -u awg2-reboot-scheduler -f +```text +binary: /usr/sbin/awg2-reboot-scheduler +unit: /lib/systemd/system/awg2-reboot-scheduler.service +config: /etc/awg2-harness/config.toml +plan file: /run/awg2-harness/reboot.plan ``` +## Конфигурация + +```toml +[reboot] +enabled = true +window_start_utc = "01:00" +window_end_utc = "02:00" +``` + +Если `enabled = false`, процесс печатает `disabled by config` и завершается без reboot. + +## Проверка на production host + +```bash +systemctl status awg2-reboot-scheduler.service --no-pager -l +journalctl -u awg2-reboot-scheduler.service --since '10 minutes ago' --no-pager +cat /run/awg2-harness/reboot.plan +awg2-harness --config /etc/awg2-harness/config.toml status +``` + +## Ручной запуск для диагностики + +```bash +/usr/sbin/awg2-reboot-scheduler --config /etc/awg2-harness/config.toml +``` diff --git a/tools/README.md b/tools/README.md index 10f2154..6831582 100644 --- a/tools/README.md +++ b/tools/README.md @@ -1,72 +1,62 @@ # AWG2 Harness builder -Основной скрипт: [`build.sh`](build.sh). -Целевой crate: [`traffic_core`](../traffic_core/Cargo.toml). -Unit: [`awg2-harness.service`](../awg2-harness.service). -Пример конфига: [`config.example.toml`](../config.example.toml). +`tools/build.sh` — единый build/package helper для AWG2 Harness. Он предназначен в первую очередь для build-machine. Production-хост обычно получает только готовый `.deb` и `/etc/awg2-harness/config.toml`. -## Supported host +Скрипт собирает workspace из двух бинарей: -- Debian/Ubuntu (apt-based) -- amd64/x86_64 +```text +traffic_core -> awg2-harness +reboot_module -> awg2-reboot-scheduler +``` -## Purpose +И при `--package` создаёт Debian-пакет `dist/awg2-harness__amd64.deb` с checksum-файлом `dist/SHA256SUMS`. -Скрипт используется на build-machine для проверки, сборки и упаковки AWG2 Harness. +## Поддерживаемая build-среда -## Default mode +- Debian/Ubuntu с `apt`. +- amd64/x86_64. +- Rust toolchain из `rust-toolchain.toml` (`1.95.0` в текущем дереве). +- `Cargo.lock` обязателен: build gate работает в `--locked` режиме. + +## Быстрый production build + +```bash +cd awg2_harness +chmod +x tools/build.sh +./tools/build.sh --prepare-build-env --bootstrap-rust --yes +./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 +``` + +## Что делает default запуск ```bash ./tools/build.sh ``` -Дефолтный запуск **не изменяет систему**. Он: +Если не указан ни один action flag, включается `--build`. -- проверяет prereqs; -- запускает `fmt/clippy/test/build` в locked-режиме; -- печатает `file`, `ldd`, `sha256` для собранного бинаря. - -## Flags - -- `--prepare-build-env` — установить недостающие build-пакеты; -- `--prepare-runtime-env` — установить недостающие runtime-пакеты; -- `--bootstrap-rust` — установить rustup и pinned toolchain; -- `--build` — запустить build gate явно; -- `--package` — собрать Debian-пакет в `dist/`; -- `--dist-dir ` — директория для release artifacts; -- `--version ` — переопределить версию пакета; -- `--install` — установить бинарь + systemd unit (без enable/start); -- `--enable` — `systemctl enable --now awg2-harness.service`; -- `--yes` — подтверждение системных изменений (apt/rustup); -- `--skip-fmt` — пропустить `cargo fmt --check`; -- `--help` — справка. - -## Build machine flow +## Проверка пакета перед переносом ```bash -./tools/build.sh --prepare-build-env --bootstrap-rust --yes -./tools/build.sh --build -./tools/build.sh --package +sha256sum -c dist/SHA256SUMS +dpkg-deb -I dist/awg2-harness__amd64.deb +dpkg-deb -c dist/awg2-harness__amd64.deb | sort ``` -## Production host flow - -В нормальном production deployment **не нужно** клонировать репозиторий на целевой хост. -Ставится сгенерированный пакет: +## Production transfer ```bash -apt install ./awg2-harness_*_amd64.deb +scp -P 2323 dist/awg2-harness__amd64.deb root@:/root/ +scp -P 2323 dist/SHA256SUMS root@:/root/ ``` -## Manual source-tree install +## Что скрипт намеренно не делает -`--install` и `--enable` оставлены для staging/debug из checked-out source tree. - -Это **не рекомендуемый** production path. - -## What the script intentionally does not do - -- не устанавливает Docker автоматически; -- не генерирует production config из example; -- не включает сервис без явного `--enable`; -- не управляет установкой AmneziaWG. +- не устанавливает AmneziaVPN; +- не генерирует client keys/configs; +- не копирует `config.example.toml` в `/etc/awg2-harness/config.toml`; +- не включает services без `--enable`; +- не управляет SSH hardening. diff --git a/tools/build.sh b/tools/build.sh index 99cc9a1..d119e14 100644 --- a/tools/build.sh +++ b/tools/build.sh @@ -329,6 +329,7 @@ package_deb() { install -d -m 0755 "$staging/usr/share/doc/awg2-harness/repo" install -d -m 0755 "$staging/usr/share/doc/awg2-harness/repo/docs" install -d -m 0755 "$staging/usr/share/doc/awg2-harness/repo/tools" + install -d -m 0755 "$staging/usr/share/doc/awg2-harness/repo/reboot_module" install -m 0755 "$TARGET_BIN" "$staging/usr/sbin/awg2-harness" install -m 0755 "$REBOOT_BIN" "$staging/usr/sbin/awg2-reboot-scheduler" @@ -336,10 +337,12 @@ package_deb() { install -m 0644 "$ROOT_DIR/awg2-reboot-scheduler.service" "$staging/lib/systemd/system/awg2-reboot-scheduler.service" install -m 0644 "$ROOT_DIR/config.example.toml" "$staging/usr/share/doc/awg2-harness/repo/config.example.toml" install -m 0644 "$ROOT_DIR/README.md" "$staging/usr/share/doc/awg2-harness/repo/README.md" - install -m 0644 "$ROOT_DIR/docs/INSTALLATION.md" "$staging/usr/share/doc/awg2-harness/repo/docs/INSTALLATION.md" - install -m 0644 "$ROOT_DIR/docs/CONFIGURATION.md" "$staging/usr/share/doc/awg2-harness/repo/docs/CONFIGURATION.md" - install -m 0644 "$ROOT_DIR/docs/ACCEPTANCE_CHECKLIST.md" "$staging/usr/share/doc/awg2-harness/repo/docs/ACCEPTANCE_CHECKLIST.md" + local doc + for doc in "$ROOT_DIR"/docs/*.md; do + install -m 0644 "$doc" "$staging/usr/share/doc/awg2-harness/repo/docs/$(basename "$doc")" + done install -m 0644 "$ROOT_DIR/tools/README.md" "$staging/usr/share/doc/awg2-harness/repo/tools/README.md" + install -m 0644 "$ROOT_DIR/reboot_module/README.md" "$staging/usr/share/doc/awg2-harness/repo/reboot_module/README.md" cat >"$staging/DEBIAN/control" <