Files
awg-profiler-golang/README.md
T
2026-07-18 10:02:43 +03:00

316 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 <repo-url> 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 <repo-url> 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
## Расположение файлов
Пути привязаны к каталогу исполняемого файла (`<dir>`, переопределяется
переменной `AWG_PROFILER_DIR` — так собран Docker-образ, где `<dir>=/data`):
| Назначение | Путь |
|---|---|
| Конфиг профилировщика | `<dir>/awg_config` (формат shell `KEY="value"`) |
| Реестр клиентов | `<dir>/data/awg_clients.json` |
| Накопленная статистика трафика | `<dir>/data/awg_stats.json` |
| Профили клиентов | `<dir>/awg_clients/<name>.conf` + `.png` (QR) |
| Флаг «зависимости установлены» | `<dir>/awg_state.json` |
| Interface conf / nft-правила | `/etc/amnezia/amneziawg/<iface>.conf`, `<iface>-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-dir>/<iface>.conf из реестра
клиентов и (по подтверждению) перезапустить службу
CLIENT MANAGEMENT
create <name> Создать клиента: ключи, .conf, QR-код
delete <id> Удалить клиента (файлы + запись в реестре)
disable <id> Перевести клиента в статус DISABLED
enable <id> Перевести клиента в статус 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 <iface> dump` и
сопоставляются с реестром по публичному ключу.
- **Мастер настройки** — если сервер ещё не инициализирован, UI показывает
форму `install-deps``init-server` (неинтерактивные аналоги CLI-команд).
UI построен как одностраничное приложение на «ванильном» JS/CSS (без внешних
зависимостей — работает офлайн), mobile-first, с обновлением статистики каждые
10 c. По умолчанию всегда тёмная тема (см. `--ui-mode` выше).
### Накопление статистики (переживает перезапуск)
`awg show <iface> 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 ./...
```