# Конфигурация AWG2 Harness AWG2 Harness разрабатывался для self-hosted AmneziaWG/AWG 2.0 и совместимого legacy-сценария AmneziaWG/AWG 1.5. Конфиг живёт в `/etc/awg2-harness/config.toml`. Он общий для всего пакета и должен содержать только эксплуатационно значимые параметры. ## Создание runtime config Пакет намеренно **не** создаёт `/etc/awg2-harness/config.toml` автоматически. Это снижает риск случайно применить firewall с неверным SSH-портом или неверным Amnezia-портом. После установки `.deb` создайте runtime config вручную: ```bash 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 ``` Перед первым `apply-firewall`/`apply-limits` оператор обязан сверить: - `host_firewall.ssh_port` — должен совпадать с реально слушающим `sshd` портом; - `host_firewall.amnezia_port` — должен совпадать с published Docker/Amnezia UDP port; - `amnezia.peer_ipv4_cidr` — должен совпадать с реальной peer-подсетью; - `anti_torrent.peer_ipv4_cidr` — обычно тот же CIDR. Discovery-команды: ```bash docker port amnezia-awg2 2>/dev/null || docker port amnezia-awg3 2>/dev/null || docker port amnezia-awg C="$(docker ps --format '{{.Names}}' | grep -E '^(amnezia-awg2|amnezia-awg3|amnezia-awg)$' | head -n1)" docker exec "$C" ip -4 addr docker exec "$C" awg show ``` ## Рекомендуемый `config.toml` ```toml [amnezia] container_names = ["amnezia-awg2", "amnezia-awg3", "amnezia-awg"] interface_candidates = ["awg0", "wg0", "amnezia0", "tun0"] interface_patterns = ["awg*", "wg*", "amnezia*", "tun*"] wg_binaries = ["awg", "wg"] peer_ipv4_cidr = "10.8.1.0/24" [traffic] enabled = true peer_limit = "50mbit" root_rate = "500mbit" reconcile_interval_secs = 15 container_ready_timeout_secs = 120 class_start_id = 10 ifb_name = "ifb0" [sysctl_tuning] enabled = true apply_on_daemon_start = true ip_forward = true tcp_bbr = "auto" # off | auto | require default_qdisc = "fq" # none | fq | fq_codel rmem_max = 67108864 wmem_max = 67108864 netdev_backlog_enabled = true netdev_max_backlog = 50000 udp_rmem_min_enabled = true udp_rmem_min = 8192 [host_firewall] enabled = true ssh_port = 2323 amnezia_port = 443 amnezia_protocols = ["udp"] allow_icmp = true default_input_policy = "drop" [anti_torrent] enabled = true max_connections_per_peer = 150 peer_ipv4_cidr = "10.8.1.0/24" apply_in_amnezia_netns = true [reboot] enabled = true window_start_utc = "01:00" window_end_utc = "02:00" [swap] enabled = true path = "/swapfile" size_mb = 2048 priority = 1 swappiness = 1 ``` ## Пояснения `amnezia.container_names` — имена контейнеров, которые считаются Amnezia/AWG. Порядок важен, сопоставление точное. По текущему production-снимку основной вариант — `amnezia-awg2`, fallback — `amnezia-awg`. `amnezia-awg3` перечислен на будущее и **не является подтверждённым официальным именем**: в проверенной версии AmneziaVPN `5.0.0.5` поддержка AWG 3.0 добавлена, но варианты контейнера по-прежнему представлены как `Awg` и `Awg2`, отдельного типа `Awg3` нет. Имя оставлено в примере потому, что несовпавшее имя не стоит ничего — поиск просто идёт дальше по списку, — тогда как отсутствующее в списке имя даст молчаливое «контейнер не найден». Если Amnezia введёт другое имя, его нужно будет дописать сюда. `amnezia.interface_candidates` — точные имена интерфейса, которые пробуются первыми. `amnezia.interface_patterns` — fallback-паттерны для устойчивости к обновлениям Amnezia. Они нужны для снижения риска переименования интерфейса между `awg0`, `wg0`, `amnezia0`, `tun0`. `amnezia.wg_binaries` — утилита чтения peer state внутри контейнера, пробуется по порядку до первого успеха. Default — `["awg", "wg"]`. В официальном образе AmneziaWG реальный бинарь `/usr/bin/awg`, а `/usr/bin/wg` — symlink на него, поэтому `awg` идёт первым; `wg` остаётся для контейнеров с чистым WireGuard. Значения выполняются внутри контейнера и валидируются как имена команд: непустые, без пробелов и без разделителей пути. Параметр опциональный — конфиги, созданные до его появления, продолжают работать с default. Хостовый `wireguard-tools` не нужен и не проверяется в preflight. Peer state читается только через `docker exec`: AmneziaWG — userspace-реализация, её UAPI-сокет находится в `RUNSTATEDIR/amneziawg/` внутри mount namespace контейнера, а `nsenter -n` входит только в network namespace, поэтому хостовый `wg` до него не достаёт. `amnezia.peer_ipv4_cidr` — подсеть VPN peers. Production default — `10.8.1.0/24`; значение конфигурируемое. `traffic.peer_limit` — per-peer лимит в обе стороны. Текущий production default — `50mbit`. `traffic.root_rate` — верхний HTB-класс, в текущем production default — `500mbit`. `traffic.reconcile_interval_secs` — период фоновой проверки. Он нужен не вместо Docker events, а вместе с ними. `traffic.container_ready_timeout_secs` — сколько ждать появления интерфейса после старта контейнера. `traffic.class_start_id` — первый class id. Production default — `10`, что даёт классы `1:10`, `2:10` и дальше. `traffic.ifb_name` — имя IFB-интерфейса для ingress shaping. Production default — `ifb0`. Этот параметр можно оставить в конфиге, потому что бинарь реально создаёт/удаляет этот интерфейс. `sysctl_tuning` — отдельный host-level модуль управляемого сетевого baseline через `sysctl`: - persistent-файл: `/etc/sysctl.d/90-awg2-harness-vpn.conf`; - модуль `swap` отдельно управляет `/etc/sysctl.d/90-awg2-harness-swap.conf` (только `vm.swappiness`); прежний путь `/etc/sysctl.d/99-awg2-harness.conf` удаляется при первом запуске новой версии, если несёт старый маркер; - дополнительный managed-файл `/etc/modules-load.d/90-awg2-harness-bbr.conf` создаётся только при фактически активном BBR и удаляется, когда BBR неактивен; - оба managed-файла несут в первой строке маркер `# Managed by awg2-harness sysctl_tuning`; файл без маркера не перезаписывается и не удаляется, вместо этого возвращается ошибка; - `net.ipv4.tcp_congestion_control` и `net.core.default_qdisc` управляются только при активном BBR; - runtime apply: только `sysctl -w` и только для drifted keys; - на установке `.deb` модуль не применяется; - на старте daemon модуль применяется, если `enabled=true` и `apply_on_daemon_start=true`; - `tcp_bbr = auto` не валит запуск при недоступном BBR (warning), `require` — валит; - для `sysctl_tuning`: `modprobe` обязателен только для `tcp_bbr = "require"`. Отдельно для всего пакета: - `traffic`-модуль требует `modprobe` для IFB при `traffic.enabled = true`. Совместимость обновлений: - если в существующем runtime-конфиге отсутствует блок `[sysctl_tuning]`, он не включается автоматически (`enabled=false` по default для missing block); - для новых установок рекомендуется явный блок `[sysctl_tuning]` из примера, где `enabled=true`. Ограничения модуля: - не использует `/etc/sysctl.conf`; - не запускает `sysctl --system`; - не меняет `nftables`, Docker bridge и container-local sysctl; - не управляет `net.ipv4.udp_wmem_min` (в Linux документации параметр указан как не имеющий эффекта). При drift orchestrator всегда делает controlled rebuild owned topology. `anti_torrent.enabled` — включает nftables connection-count guard против high-peer-count P2P-нагрузки. Это отдельный AWG2 Harness module и часть текущего production-контракта. `host_firewall.enabled` — включает host-level INPUT firewall в отдельной AWG2-owned таблице `inet awg2_host_firewall`. `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`). В текущей целевой конфигурации default — `443`; значение должно совпадать с реально опубликованным Amnezia UDP/TCP port. Важно: `host_firewall.amnezia_port` — это transport-порт AmneziaWG/AWG (например, `443/udp`). Это не порт AmneziaDNS. - Не задавайте `amnezia_port = 53`. - Не добавляйте DNS/53 в `amnezia_protocols`. - Не открывайте `53/tcp` или `53/udp` в AWG2 host firewall для ожидаемого production-профиля. В expected production layout AmneziaDNS работает как внутренний Docker/VPN сервис и не публикуется на public host interface. Для диагностического блока `Docker/Amnezia port path` в `status` приоритет сопоставления такой: сначала ищется published UDP binding с `HostPort == host_firewall.amnezia_port`, затем fallback на ключ `"/udp"` как container port, затем (если UDP binding ровно один) берётся он. Если UDP bindings несколько и однозначного совпадения нет, статус показывает `published_udp_port: unknown`. Диагностика `FORWARD` в этом блоке является best-effort: сначала используется `iptables -S FORWARD`, затем fallback через `nft list ruleset`; результаты только отображаются в `status` и не изменяют host `FORWARD`/Docker NAT. `host_firewall.amnezia_protocols` — протоколы для порта Amnezia (`udp`, `tcp` или оба). Важно: `awg2-harness` не управляет host `FORWARD`/Docker NAT-цепочками. Проект сознательно не добавляет универсальные правила в `FORWARD` и не меняет Docker-managed forwarding path. `host_firewall.allow_icmp` — разрешать ICMP/ICMPv6 на входе. `host_firewall.default_input_policy` — политика INPUT chain (`drop` или `accept`). Для production рекомендуется `drop`. `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`. `anti_torrent.apply_in_amnezia_netns` — выбор namespace для применения anti-torrent правил: - `true` (default): применять в network namespace контейнера Amnezia; - `false`: применять в host namespace. Для production рекомендуется `true`, если peer source IP (`10.8.1.x`) видны именно внутри netns контейнера. `apply-firewall` в текущей модели делает **оба** reconcile: host firewall (host namespace) и anti-torrent firewall (configured namespace). `reboot.enabled` — включает плановую перезагрузку. `reboot.window_start_utc` / `reboot.window_end_utc` — UTC-окно плановой перезагрузки. Production default/example — `01:00`–`02:00` UTC. `swap.enabled` — включает setup-задачу swap. `swap.path`, `swap.size_mb`, `swap.priority`, `swap.swappiness` — параметры managed swap. При `swap.enabled=true` пакет приводит swap-state к exclusive состоянию: активен ровно один swap (`swap.path`), остальные выключаются и swap-entries в `/etc/fstab` пересобираются в одну managed строку. Рекомендуемый low priority — `1`, `swappiness = 1`. Ограничения `swap.path`: путь должен быть либо `/swapfile`, либо файлом непосредственно в `/var/lib/awg2-harness/`. Дополнительно: абсолютный, без компонентов `.` и `..`, без пробелов, управляющих символов и обратных слэшей; на этапе применения проверяется, что ни один родительский каталог не является symlink. Ограничение корней обязательно, а не косметика. Если родительский каталог доступен на запись кому-то кроме root, между проверкой пути и запуском `mkswap --file` этот пользователь успевает подменить файл на symlink и перенаправить операцию, выполняемую от root. Оба разрешённых корня принадлежат root, поэтому окна не возникает. `/swapfile` оставлен для совместимости с уже развёрнутыми конфигурациями. Владение фиксируется в `/var/lib/awg2-harness/swap-ownership.conf` по `device` + `inode` + пути, а не по маркеру рядом с файлом. Файл, которого нет в этой записи, или файл с тем же путём, но другими `device`/`inode` (то есть подменённый), считается чужим: он никогда не пересоздаётся и не удаляется, вместо этого возвращается ошибка. Чужие активные swap только выключаются — их файлы пакет не удаляет. ## Что не выносить в конфиг Не нужно выносить: - handles `1:`, `2:`, `ffff:`; - имена внутренних Rust-модулей; - формат команд `tc`; - retry micro-tuning; - формат логов; - путь lock-файла, если нет эксплуатационной причины; - hardening systemd; - nftables hook/priority/table names, если нет осознанной причины. Handles и структура `HTB + fq_codel + ingress + ifb` — это contract traffic module, а не настройка оператора.