316 lines
20 KiB
Markdown
316 lines
20 KiB
Markdown
# 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 ./...
|
|||
|
|
```
|