Files
AWG2_harness/docs/INSTALLATION.md
T
founder d98ade42ce docs: unify language contract to Russian and reconcile the spec with the code
The docs folder had drifted into a mixed-language contract: IMPLEMENTATION_SPEC.md was
entirely in English while the rest was Russian with English headings. Prose is now
Russian throughout; English is kept only where it is technically load-bearing (commands,
tool output, config keys, file/module/table names, tc handles) and for terms with no
settled Russian equivalent in this context (drift, reconcile, peer, namespace, handshake).
docs/README.md now states that contract explicitly.

Rewriting the spec surfaced several places where it described intent rather than the
code. Corrected against traffic_core/src:

- module layout: the spec showed traffic/ and firewall/ as directories with
  model/inspect/apply submodules. They are single files, and sysctl_tuning.rs was
  missing from the tree entirely.
- data model: Peer was documented as carrying public key, handshake and counters. It
  carries only ipv4; runtime state lives in a separate PeerRuntime, and there is no
  desired-state struct at all - it is derived inline from config plus sorted peers.
  RuntimeTarget.netns_path is a String, not a PathBuf.
- interface detection: the spec listed a third step taking the first non-loopback
  interface with an IPv4 address. No such fallback exists; detection bails with an
  explicit error, which is safer and is now documented as deliberate.
- reconcile: the pseudo-flow folded firewall into reconcile_traffic. They are two
  independent reconciles with separate locks.
- locking: only traffic.lock was documented. There are three locks, and
  sysctl_tuning.lock has a 30s timeout rather than 10s. Stale-lock recovery via
  /proc/<pid> was undocumented.
- sysctl_tuning: the module also manages /etc/modules-load.d/90-awg2-harness-bbr.conf
  when BBR is active, and refuses to touch either managed file without its marker.
  Both docs and the acceptance checklist claimed only the sysctl.d file was written.
- status contract: the documented output was outdated. All 15 printed sections are now
  listed in the order status.rs emits them, including the degraded path when no container
  is found, and the fact that the Network tuning block is printed between the System
  service line and the container lines.
- swap: size was documented as a constant 2048 MB instead of swap.size_mb, and the
  /etc/fstab.awg2-harness.bak backup was undocumented.
- apply/verify: the tolerated-error lists are now the actual closed sets from the code.

Acceptance checklist gained checks for the daemon startup failure policy (sysctl/swap
fatal, traffic/firewall not), lock contention and stale-lock recovery, degraded status,
the modules-load file, and the marker guard. The stale host wg requirement was dropped
from its host-tools item.

Every path, table, counter and log string quoted in the docs was verified to exist in
the source. cargo test --workspace: 110 + 4 passed.
2026-08-06 16:45:00 +05:00

12 KiB
Raw Blame History

Установка

Этот документ описывает production-порядок установки AWG2 Harness. Подробный runtime-план с SSH hardening и Amnezia preflight находится в корневом README.md.

Контракт развёртывания

  • Целевой 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 автоматически.
  • sysctl_tuning не применяется в postinst; применение только на старте daemon или вручную через CLI.

A. Сборочная машина

A1. Подготовить сборочное окружение

cd awg2_harness
chmod +x tools/build.sh
./tools/build.sh --prepare-build-env --bootstrap-rust --yes

A2. Проверить код

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:

./tools/build.sh --build

A3. Собрать Debian-пакет

./tools/build.sh --package --version 0.1.6
(cd dist && sha256sum -c SHA256SUMS)
dpkg-deb -I dist/awg2-harness_0.1.6_amd64.deb
dpkg-deb -c dist/awg2-harness_0.1.6_amd64.deb | sort

--version можно опустить, если версия в traffic_core/Cargo.toml уже равна release version. Version override влияет только на metadata .deb.

B. Подготовить production-хост

B1. SSH

Сначала сгенерируйте отдельную пару ключей для Amnezia на Windows (RSA PEM):

ssh-keygen -t rsa -b 4096 -m PEM -f %USERPROFILE%\.ssh\amnezia_key

Дальше разделяйте ключи строго:

  • на сервер в /root/.ssh/authorized_keys кладётся содержимое %USERPROFILE%\.ssh\amnezia_key.pub;
  • в AmneziaVPN в поле Password or SSH private key вставляется содержимое %USERPROFILE%\.ssh\amnezia_key (без .pub).

.pub нельзя вставлять в поле private key в AmneziaVPN.

Установка .pub на сервер:

install -d -m 0700 /root/.ssh
nano /root/.ssh/authorized_keys
chmod 0600 /root/.ssh/authorized_keys

Production-пример:

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 -i %USERPROFILE%\.ssh\amnezia_key -p 2323 root@<server-ip>

Проверить содержимое ключей в Windows:

type %USERPROFILE%\.ssh\amnezia_key.pub
type %USERPROFILE%\.ssh\amnezia_key

B2. Amnezia

Установите AmneziaWG/AWG через официальное приложение AmneziaVPN в режиме self-hosted server.

Заполнение полей в интерфейсе AmneziaVPN:

Configure your server:

Server IP address [:port]:
<server-ip>:2323

SSH Username:
root

Password or SSH private key:
полное содержимое приватного ключа %USERPROFILE%\.ssh\amnezia_key

Важно: в это поле не вставляется .pub. Файл .pub нужен только для /root/.ssh/authorized_keys на сервере.

Проверка после установки:

docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
C="$(docker ps --format '{{.Names}}' | grep -E '^(amnezia-awg2|amnezia-awg3|amnezia-awg)$' | head -n1)"
echo "container=$C"
docker port "$C"
docker exec "$C" awg show

Если контейнер называется иначе или интерфейс не awg0, отразите это в /etc/awg2-harness/config.toml.

awg — реальный бинарь в официальном образе AmneziaWG; wg внутри контейнера является symlink на него и тоже сработает. На хосте wireguard-tools устанавливать не нужно: обвязка читает peer state только через docker exec.

B3. Установить AmneziaDNS

Установите AmneziaDNS из desktop-приложения AmneziaVPN:

Servers → <server> → Services → AmneziaDNS → Install

Затем включите его для подключения:

Settings → Connection → DNS servers → Use AmneziaDNS

Ожидаемое состояние Docker:

docker ps -a --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'

Ожидаемая строка для DNS-контейнера:

amnezia-dns    amnezia-dns    Up ... (healthy)   53/tcp, 53/udp

Проверка публикации портов:

AWG="$(docker ps --format '{{.Names}}' | grep -E '^(amnezia-awg2|amnezia-awg3|amnezia-awg)$' | head -n1)"
echo "AWG=$AWG"

docker inspect -f 'ports={{json .NetworkSettings.Ports}}' amnezia-dns
docker inspect -f 'networks={{range $n,$v := .NetworkSettings.Networks}}{{printf "%s=%s " $n $v.IPAddress}}{{end}}' amnezia-dns
docker inspect -f 'networks={{range $n,$v := .NetworkSettings.Networks}}{{printf "%s=%s " $n $v.IPAddress}}{{end}}' "$AWG"

Ожидаемый результат по портам:

ports={"53/tcp":null,"53/udp":null}

Это означает, что DNS не опубликован на публичном host-интерфейсе и остаётся доступным только через VPN/Docker path.

Negative-check публичного DNS:

nslookup example.com <server-public-ip>

Ожидаемое поведение: публичный DNS-запрос не должен успешно резолвиться. Типичные безопасные варианты ответа: connection refused, timeout или no servers could be reached.

Optional deep-check DNS path (если нужна углублённая проверка):

apt install -y dnsutils

AWG="$(docker ps --format '{{.Names}}' | grep -E '^(amnezia-awg2|amnezia-awg3|amnezia-awg)$' | head -n1)"
DNS_IP="$(docker inspect -f '{{range $n,$v := .NetworkSettings.Networks}}{{if $v.IPAddress}}{{println $v.IPAddress}}{{end}}{{end}}' amnezia-dns | head -n1)"
DNS_PID="$(docker inspect -f '{{.State.Pid}}' amnezia-dns)"
AWG_PID="$(docker inspect -f '{{.State.Pid}}' "$AWG")"

echo "AWG=$AWG"
echo "DNS_IP=$DNS_IP"
nsenter -t "$DNS_PID" -n ss -lntup
nsenter -t "$AWG_PID" -n ip route
nsenter -t "$AWG_PID" -n dig @"$DNS_IP" example.com A +short

C. Передача артефактов

Ниже два production-сценария установки.

C1. Вариант A: конфиг передаётся вместе с .deb

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.

C2. Вариант B (основной): конфиг создаётся на production после установки

scp -P 2323 dist/awg2-harness_*_amd64.deb root@<server-ip>:/root/
scp -P 2323 dist/SHA256SUMS root@<server-ip>:/root/

D. Установка на production

D1. Вариант A

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
systemctl daemon-reload

D2. Вариант B (основной)

cd /root
sha256sum -c SHA256SUMS
apt install ./awg2-harness_*_amd64.deb
install -d -m 0755 /etc/awg2-harness
cp /usr/share/doc/awg2-harness/repo/config.example.toml /etc/awg2-harness/config.toml
nano /etc/awg2-harness/config.toml
systemctl daemon-reload

Перед первым apply-firewall обязательно перепроверьте:

  • [host_firewall].ssh_port совпадает с реально слушающим sshd портом;
  • [host_firewall].amnezia_port совпадает с published Docker UDP port;
  • [amnezia].peer_ipv4_cidr совпадает с peer-подсетью;
  • [anti_torrent].peer_ipv4_cidr обычно тот же CIDR.

E. Preflight до включения сервисов

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

Ожидаемый здоровый результат:

Traffic actual:
  drift: no
Host firewall:
  drift: no
Anti-torrent:
  drift: no
Swap:
  drift: no

Если peers ещё нет, apply-limits напечатает no peers found, skip tc apply. Для пустого сервера это здоровое состояние.

При swap.enabled = true AWG2 Harness намеренно делает swap эксклюзивным: один управляемый swapfile, одна swap-запись в /etc/fstab, заданный swappiness.

F. Включение сервисов

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 секунд:

awg2-harness --config /etc/awg2-harness/config.toml status

G. Проверка перезагрузкой

reboot

После восстановления подключения:

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. Ручная установка из дерева исходников

./tools/build.sh --install и ./tools/build.sh --enable существуют для staging и отладки. Это не рекомендуемый production-путь: на production используйте .deb.