# awg_profiler Инструмент на Go для развёртывания и управления сервером **AmneziaWG** (форк WireGuard с обфускацией трафика): установка зависимостей, инициализация сервера, управление клиентами (CLI и веб-UI) и сбор статистики трафика, переживающей перезапуски. Проект самодостаточен: единственный бинарник `awg_profiler`, встроенный веб-интерфейс (без внешних зависимостей в браузере) и Docker-образы для запуска без установки чего-либо на хост. --- # Quick Start Ниже — два независимых пути развёртывания «с нуля» (Green Field): в контейнере (рекомендуется, не требует ничего кроме Docker) или напрямую на хосте. ## Вариант A — в контейнере (рекомендуется) Требования: Docker + Docker Compose, ядро Linux с включённым модулем `tun` (есть на любом современном дистрибутиве). Контейнер запускает встроенный веб-интерфейс на `:8080` (WEB UI) и слушает VPN-трафик на UDP `:51820`. AmneziaWG-стек (`awg`, `awg-quick`, `amneziawg-go`) собирается внутри образа — на хосте ничего ставить не нужно. ```bash git clone awg_profiler && cd awg_profiler # Сборка и запуск (образ на базе Alpine) docker compose up -d --build # Логи / статус docker compose logs -f ``` По умолчанию порт `8080` публикуется только на `127.0.0.1` хоста (см. `docker-compose.yml`) — веб-UI недоступен по сети, пока вы явно не расширите доступ. На самой машине откройте `http://127.0.0.1:8080`, либо для доступа с другого компьютера прокиньте порт по SSH: `ssh -L 8080:127.0.0.1:8080 user@server` и откройте `http://127.0.0.1:8080` локально. Веб-UI покажет мастер настройки: 1. **install-deps** — пропускается автоматически (зависимости уже в образе). 2. **init-server** — заполните форму (сеть, порт, DNS, MTU — можно оставить значения по умолчанию) и отправьте. Сервер сгенерирует ключи, параметры обфускации и запустится. 3. Создавайте клиентов на вкладке **Clients**, скачивайте `.conf` / QR-код. Чтобы открыть UI на всех интерфейсах (LAN/интернет), **сначала** включите Basic-аутентификацию, иначе панель управления сервером останется без пароля: ```bash # в docker-compose.yml: # 1. раскомментировать блок environment: и задать AWG_WEB_USER=admin AWG_WEB_PASS=длинный-пароль # 2. заменить порт "127.0.0.1:8080:8080" на "8080:8080" docker compose up -d --build ``` Все изменяемые данные (конфиг, реестр клиентов, профили, статистика) живут в именованных томах `awg-data` и `awg-etc` — переживают `docker compose down` без `-v`. **Альтернативный образ (Linux Mint база, вендорские пакеты AmneziaWG вместо собранных из исходников):** ```bash docker compose -f docker-compose.mint.yml up -d --build ``` ## Вариант B — на хосте (без контейнера) Требования: Linux (Ubuntu, Debian, Linux Mint или Alpine), Go ≥ 1.26, root/sudo. `install-deps` сам ставит AmneziaWG: на apt-based дистрибутивах — пакеты `amneziawg`/`amneziawg-tools` из `ppa:amnezia/ppa`; на Alpine, где готового пакета `amneziawg-tools` нет, — собирает `awg`/`awg-quick` из исходников (нужен интернет для `git clone` на этапе install-deps). На Alpine kernel-модуль `amneziawg` при этом не ставится — его нужно предоставить отдельно (DKMS/akmods или готовый модуль под ваше ядро), `install-deps` только предупредит об этом. ```bash git clone awg_profiler && cd awg_profiler # 1. Сборка бинарника export PATH=$PATH:/usr/local/go/bin go build -o awg_profiler . # 2. Установка зависимостей (AmneziaWG, qrencode, nftables, jq) — один раз sudo ./awg_profiler install-deps # 3. Интерактивная инициализация сервера (ключи, обфускация, конфиг, служба) sudo ./awg_profiler init-server # 4. Первый клиент sudo ./awg_profiler create phone # 5. (опционально) веб-UI поверх той же установки sudo ./awg_profiler web --addr 0.0.0.0:8080 ``` `install-deps` и `init-server` — обязательно раздельные шаги и в этом порядке: `init-server` проверяет флаг, оставленный `install-deps`, и отказывается работать, если пакеты ещё не установлены. На вопрос «VPN network CIDR» принимается **только `/24`** (например `10.0.0.0/24` или `192.168.5.0/24`) — весь остальной код (адрес сервера, адреса клиентов, запись в конфиг) жёстко расчитан на /24, другой префикс `init-server` отклонит с ошибкой. Дальше — управление через CLI (`server-status`, `create`, `list`, …) или запущенный `web`; см. полный список команд в [CLI-командах](#cli-команды). --- # Detailed Info ## Расположение файлов Пути привязаны к каталогу исполняемого файла (``, переопределяется переменной `AWG_PROFILER_DIR` — так собран Docker-образ, где `=/data`): | Назначение | Путь | |---|---| | Конфиг профилировщика | `/awg_config` (формат shell `KEY="value"`) | | Реестр клиентов | `/data/awg_clients.json` | | Накопленная статистика трафика | `/data/awg_stats.json` | | Профили клиентов | `/awg_clients/.conf` + `.png` (QR) | | Флаг «зависимости установлены» | `/awg_state.json` | | Interface conf / nft-правила | `/etc/amnezia/amneziawg/.conf`, `-rules.nft` | ## CLI-команды ``` SERVER SETUP install-deps Установить AmneziaWG, jq, qrencode для текущей ОС и записать флаг deps_installed (выполнить ПЕРВЫМ) init-server Интерактивная настройка сервера: проверяет флаг зависимостей, затем генерирует ключи + параметры обфускации, пишет конфиги, включает IP-forwarding и запускает службу (пакеты НЕ ставит) SERVER MANAGEMENT server-status Статус интерфейса и список пиров server-start Запустить службу AmneziaWG server-stop Остановить службу AmneziaWG server-restart Перезапустить службу AmneziaWG show-config Показать текущий конфиг (приватные ключи скрыты) sync-config Пересобрать /.conf из реестра клиентов и (по подтверждению) перезапустить службу CLIENT MANAGEMENT create Создать клиента: ключи, .conf, QR-код delete Удалить клиента (файлы + запись в реестре) disable Перевести клиента в статус DISABLED enable Перевести клиента в статус ACTIVE list Список всех зарегистрированных клиентов WEB UI web [--addr host:port] Запустить веб-UI (по умолчанию 127.0.0.1:8080) [--theme classic|glass] [--ui-mode dark|light|auto] ``` Поддерживаемые ОС: **Ubuntu, Debian, Linux Mint, Alpine Linux** (автоопределение по `/etc/os-release`; на apt-based используется systemd, на Alpine — OpenRC; если систем systemd не является PID 1 — например, в контейнере — используется прямое управление через `awg-quick`). ## Разделение install-deps и init-server Установка пакетов полностью отделена от настройки сервера: 1. **`install-deps`** ставит AmneziaWG и тулинг под текущую ОС и **пишет флаг** `deps_installed=true` в `awg_state.json` (с временем и версией ОС). 2. **`init-server`** пакеты не ставит. Сначала **проверяет флаг**: если `install-deps` не запускался, завершается ошибкой `Dependencies not installed — run 'install-deps' first`. При установленном флаге переходит к генерации ключей, параметров обфускации, конфигов, включению IP-forwarding и запуску службы. В контейнерных образах этот флаг сеется автоматически при старте (`entrypoint.sh` / `entrypoint.mint.sh`), так как AmneziaWG-стек уже запечён в образ на этапе сборки — шаг `install-deps` в UI/CLI внутри контейнера не требуется. ## Web-UI Команда `web` поднимает встроенный веб-интерфейс управления. Он использует ту же логику, что и CLI (общий Go-пакет), поэтому реестр/конфиг/служба остаются совместимыми. Статические ассеты (`webui/`, `webui_glass/`) вшиты в бинарник через `go:embed` — дополнительных файлов при развёртывании не нужно. ```bash sudo ./awg_profiler web # 127.0.0.1:8080 (по умолчанию) sudo ./awg_profiler web --addr 0.0.0.0:8080 # на всех интерфейсах sudo ./awg_profiler web --theme glass # альтернативный дизайн (glassmorphism) sudo ./awg_profiler web --ui-mode auto # следовать светлой/тёмной теме ОС ``` Дизайн выбирается флагом `--theme classic|glass` (env `AWG_WEB_THEME`, по умолчанию `classic`), цвет-режим — `--ui-mode dark|light|auto` (env `AWG_WEB_MODE`, по умолчанию **`dark`** — тёмная форсируется). `glass` — dark-only, `--ui-mode` для неё игнорируется. Возможности UI: - **Дашборд** — статус интерфейса (UP/DOWN), эндпоинт, сеть, публичный ключ, счётчики «всего / активных / онлайн», кнопки `start/stop/restart` и `sync`. - **Клиенты** — список с индикатором онлайна и накопленным трафиком; создание, включение/выключение, удаление, скачивание `.conf` и просмотр QR-кода. - **Статистика по пользователю** — по каждому клиенту показываются накопленные байты (↓ rx / ↑ tx), отметка «Stats since», последний handshake, эндпоинт и признак «онлайн» (handshake ≤ 150 c), а также кнопка **Reset stats** для быстрой очистки. Живые данные берутся из `awg show dump` и сопоставляются с реестром по публичному ключу. - **Мастер настройки** — если сервер ещё не инициализирован, UI показывает форму `install-deps` → `init-server` (неинтерактивные аналоги CLI-команд). UI построен как одностраничное приложение на «ванильном» JS/CSS (без внешних зависимостей — работает офлайн), mobile-first, с обновлением статистики каждые 10 c. По умолчанию всегда тёмная тема (см. `--ui-mode` выше). ### Накопление статистики (переживает перезапуск) `awg show dump` отдаёт счётчики rx/tx, которые **обнуляются при каждом перезапуске** интерфейса — а в контейнере userspace-data-plane `amneziawg-go` рестартует вместе с приложением, поэтому «сырое» чтение после рестарта показывает ноль. Чтобы этого не происходило, трафик накапливается инкрементально и **отдельно по каждому клиенту** в `data/awg_stats.json`: - Значения складываются как **дельты** между замерами. Если счётчик «ушёл назад» (rx стал меньше предыдущего) — это трактуется как сброс, и всё текущее значение засчитывается как новый трафик. Дельты всегда неотрицательны, поэтому итог может только расти. - В каждой записи хранится **базовая точка** (`last_rx/last_tx`) — она тоже пишется на диск. После рестарта итог берётся с диска, а маленькое пост-рестарт чтение корректно распознаётся как сброс. **Перезапуск программы не может уменьшить или обнулить уже накопленную статистику.** - У каждого клиента есть отметка `since` — момент, с которого идёт накопление (при первом появлении пира или после очистки). Трафик, накопленный интерфейсом до начала отслеживания, задним числом не засчитывается. - Замер выполняется фоном (раз в 20 c) и попутно при опросе API, под отдельным мьютексом; запись — атомарно (temp + rename). Битый файл сохраняется как `awg_stats.json.bad`, чтобы ошибка парсинга не затёрла данные. - **`POST /api/clients/{id}/stats/reset`** (кнопка *Reset stats*) обнуляет накопленное для клиента и заново выставляет `since`. Удаление клиента удаляет и его запись статистики. ### Безопасность - Приватные и preshared-ключи **не** передаются в браузер в JSON-списках — секреты покидают сервер только в файле `.conf` при явном скачивании. - По умолчанию сервер слушает `127.0.0.1`. Для доступа извне включите HTTP Basic-аутентификацию, задав переменные окружения: ```bash export AWG_WEB_USER=admin export AWG_WEB_PASS='длинный-пароль' sudo -E ./awg_profiler web --addr 0.0.0.0:8080 ``` (за TLS/публичный доступ отвечает обратный прокси, например nginx/caddy). - Каждая операция сериализуется мьютексом; в веб-режиме внутренние ошибки перехватываются и возвращаются как HTTP-ответ, а не роняют сервер. ## Docker-образы Проект поставляет два независимых образа — оба запускают тот же бинарник и веб-UI, различается только то, откуда берётся сам AmneziaWG-стек: | | `Dockerfile` (по умолчанию) | `Dockerfile.mint` (альтернатива) | |---|---|---| | Базовый образ | `alpine:3.20` (рантайм) | Linux Mint 22 (`linuxmintd/mint22-amd64`) | | `awg` / `awg-quick` | собираются из исходников (`amneziawg-tools`) | пакет из официального `ppa:amnezia/ppa` | | `amneziawg-go` (userspace data-plane) | собирается из исходников | собирается из исходников | | compose-файл | `docker-compose.yml` | `docker-compose.mint.yml` | Оба варианта: - используют **userspace data-plane `amneziawg-go`** вместо kernel-модуля — контейнер не может загрузить модуль ядра, `awg-quick` автоматически переключается на userspace через `/dev/net/tun`, когда `/sys/module/amneziawg` отсутствует; - требуют `cap_add: NET_ADMIN` и проброс `/dev/net/tun` (уже прописано в compose-файлах); - сохраняют состояние в volume'ах: `/data` (конфиг, реестр, профили, статистика) и `/etc/amnezia/amneziawg` (interface `.conf` + nft-правила); - внутри контейнера слушают `51820/udp` (VPN) и `8080/tcp` (веб-UI), команда по умолчанию — `web --addr 0.0.0.0:8080` (переопределяется через `command:` в compose или аргументом `docker run`); наружу же порт `8080` по умолчанию публикуется только на `127.0.0.1` хоста (см. compose-файлы) — расширяйте его на все интерфейсы только вместе с `AWG_WEB_USER`/`AWG_WEB_PASS`. ## Технические особенности реализации - Работа с JSON-реестром клиентов и статистикой — нативно (`encoding/json`), без внешнего `jq`. `jq` всё ещё ставится `install-deps` (используется в ручной отладке конфигов), но в рантайме профилировщика не требуется. - `awg` (genkey/pubkey/genpsk/set/show) и `qrencode` вызываются как внешние бинарники. - Случайные значения (ключи, параметры обфускации) берутся из `crypto/rand`. - Определение публичного IP — нативный HTTP-клиент (IPv4-only), аналог `curl -sf4`. ## Тесты ```bash go test ./... ```