fix28: обновлена production-документация и упаковка docs в deb

This commit is contained in:
2026-05-12 16:56:36 +05:00
parent a9bac8fdad
commit 69c737bcf4
10 changed files with 488 additions and 150 deletions
+252 -36
View File
@@ -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.
+2 -2
View File
@@ -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 <peer_ipv4_cidr>`, 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 ниже порога не ломаются.
+4 -4
View File
@@ -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` — агрессивный режим только после наблюдения реального трафика.
+4 -4
View File
@@ -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`.
+131 -27
View File
@@ -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@<server-ip>
```
### 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@<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`. Минимально проверьте:
- `[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.
+1 -1
View File
@@ -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
+15 -7
View File
@@ -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 и отладки.
+33 -16
View File
@@ -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
```
+40 -50
View File
@@ -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_<version>_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 <path>` — директория для release artifacts;
- `--version <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_<version>_amd64.deb
dpkg-deb -c dist/awg2-harness_<version>_amd64.deb | sort
```
## Production host flow
В нормальном production deployment **не нужно** клонировать репозиторий на целевой хост.
Ставится сгенерированный пакет:
## Production transfer
```bash
apt install ./awg2-harness_*_amd64.deb
scp -P 2323 dist/awg2-harness_<version>_amd64.deb root@<server-ip>:/root/
scp -P 2323 dist/SHA256SUMS root@<server-ip>:/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.
+6 -3
View File
@@ -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" <<EOF
Package: awg2-harness