42 KiB
Forgetting
Панель управления и API для VPN на базе AmneziaWG
Warning
Данный проект предназначен только для использования в законных целях.
- VPN-пользователи с ключами
vpn://для AmneziaVPN и мастер-ключиsen://для SenAWG: одна ссылка на несколько устройств, каждое регистрируется само. - Несколько серверов под одной панелью: ноды подключаются к ней сами, панель можно вынести на отдельный сервер без VPN.
- Журнал подключений: кто, когда и сколько был в VPN, кто давно не подключался.
- Мониторинг: встроенный Prometheus и графики в панели, метрики для своего Prometheus.
- Защита от обнаружения: параметры обфускации, порты и пути у каждого сервера свои, а открытые порты отвечают сканеру как пустой веб-сервер.
Содержание
- Архитектура
- Требования
- Установка · Параметры установщика · Обновление и удаление
- Несколько серверов
- Защита от обнаружения
- Журнал подключений
- Мониторинг
- Панель за nginx
- API
- Управление · Настройки
cli.env
Архитектура
Один статический бинарник awg-control (Go) в /opt/awg-control/ — в нём все роли;
команда awg-ctrl — ссылка на него:
| Компонент | Роль |
|---|---|
awg-ctrl (awg-control ctrl) |
Привилегированный REST-бэкенд. Управляет пирами через awg/awg-quick, ведёт SQLite-базу (users.db) и журнал подключений, генерирует vpn:// ключи. Слушает только loopback. |
awg-ui (awg-control ui) |
Веб-панель (React, awg-ui/dist), вход по JWT, прокси к awg-ctrl, публичный API /api/v1, подписка sen://, хаб нод и /metrics. База — ui.db. |
awg-agent (awg-control agent) |
Только на ноде: исходящее WSS-соединение к панели, исполняет её запросы на локальном awg-ctrl. |
cli (awg-ctrl …) |
Менеджер процессов, логин и пароль панели, привязка нод, перенос панели, мониторинг, TUI-меню. |
Внутренняя связь awg-ui → awg-ctrl подписывается асимметрично (Ed25519): приватный ключ только
у awg-ui, awg-ctrl проверяет подпись публичным. Данные — в /etc/amnezia/amneziawg/ (вне
каталога установки, переустановку переживают), настройки сервисов — в
/opt/awg-control/cli/cli.env.
Порты наружу (номера у каждого сервера случайные):
| Порт | Что | Кто открывает |
|---|---|---|
SERVER_PORT/udp |
VPN-клиенты | везде, где есть VPN |
UI_PORT/tcp |
панель и API, под секретным путём | панель |
SUB_PORT/tcp |
подписка sen:// (по умолчанию HTTPS) |
панель |
NODE_PORT/tcp |
хаб нод (WSS) | панель, если принимает ноды |
Нода открывает только UDP для клиентов: к панели она подключается сама.
Требования
- ОС: Ubuntu 24.04+ (тесты проходили на Ubuntu 24.04.4 LTS) или Debian 11–13 (поддержка
экспериментальная: PPA amnezia подключается вручную, серия подбирается по релизу Debian и
переопределяется через
AMNEZIA_PPA_SUITE). - Права: root.
- Виртуализация: KVM или железо (не OpenVZ/LXC/Docker/WSL — нужен загружаемый kernel-модуль AmneziaWG).
- Заголовки ядра под текущее ядро (для сборки DKMS-модуля).
- Архитектура: x86_64 или aarch64.
Совместимость установщик проверяет сам перед любыми изменениями.
Установка
На сервере, от root:
bash <(curl -Ls https://raw.githubusercontent.com/maeneko/forgetting/main/install.sh)
Не от root — через sudo bash -c: sudo bash <(curl …) падает с
/dev/fd/63: No such file or directory, потому что sudo закрывает дескриптор с текстом скрипта.
sudo bash -c "$(curl -Ls https://raw.githubusercontent.com/maeneko/forgetting/main/install.sh)"
Установщик спросит роль сервера:
| Роль | Что ставится |
|---|---|
Панель + VPN (standalone) |
Всё на одной машине; к ней можно подключать ноды |
Только панель (core) |
Панель без VPN; серверы подключаются к ней нодами |
Нода (node) |
VPN без панели; подключается к панели по строке awgjoin://… («Добавить сервер» в панели) |
В конце установщик печатает адрес панели вместе с секретным путём —
http://IP:PORT/<путь>/ — логин и пароль. Без пути панель отвечает 404, поэтому адрес
сохраните целиком; позже его покажут awg-ctrl status и awg-ctrl credentials.
Порты на самом сервере установщик открывает сам (UFW, firewalld или iptables — что активно). Фаервол хостера (панель провайдера, security group) отсюда не виден: открой там порты из итога установки, иначе клиенты не подключатся, а на сервере всё будет выглядеть исправным.
Сервер ставится на AmneziaWG 3.1. Если модуль в ядре старше 3.x или ядро старше 5.5,
установка остановится с диагностикой — поставить на 2.0 можно через AWG_GEN=auto. Перевести
сервер на 3.1 позже можно кнопкой «Перейти на AWG 3.1» в панели: пользователи сохраняются,
ключи перевыпускаются автоматически.
Параметры установщика
Задаются переменными окружения перед запуском, например
ROLE=node JOIN='awgjoin://…' bash <(curl -Ls …/install.sh). Всё необязательно.
| Переменная | Что делает |
|---|---|
ROLE |
standalone, core или node — без вопроса |
JOIN |
строка awgjoin://… для ноды |
AWG_GEN |
3.1 (по умолчанию), auto — 3.1, если ядро позволяет, иначе 2.0; 2.0 — не трогать модуль |
AWG_PIN |
y (по умолчанию) — закрепить версию пакетов AmneziaWG (apt-mark hold) |
AWG_PORT |
UDP-порт VPN вместо случайного |
AWG_MTU |
MTU туннеля вместо случайного (1280–1500) |
UI_PORT, UI_USER, UI_PASS |
порт, логин и пароль панели — без вопросов |
UI_PREFIX |
свой секретный путь панели (8–64 символа A–Z a–z 0–9 _ -); off — без пути |
SERVER_NAME |
имя VPN-сервера — без вопроса |
SUB_PORT, SUB_TLS, NODE_PORT |
порт и HTTPS подписки, порт хаба нод — без вопросов |
ACTION |
update, reinstall или uninstall — действие без меню |
UNINSTALL |
y — удалить без меню и без подтверждения |
AMNEZIA_PPA_SUITE |
серия PPA для Debian (focal/jammy/noble) |
REPO_BASE, REPO_FALLBACK, ARCHIVE_URL, AWG_LOCAL_TARBALL |
откуда брать архив релиза (своё зеркало, локальный файл) |
BRAND, CHANNEL |
имя продукта в баннерах и панели |
Обновление и удаление
Повторный запуск установщика на сервере с установкой — или пункты 7–9 меню awg-ctrl, или
команды awg-ctrl update | reinstall | uninstall — предлагает:
- Обновить — новая версия, настройки, пользователи и роль сохраняются. Установке без
секретного пути панели он выдаётся, и установщик печатает новый адрес: закладки и адрес
внешнего API нужно обновить. Оставить без пути —
UI_PREFIX=offперед запуском или пустоеUI_PREFIX=вcli.env. - Переустановить — с нуля; пользователей и ключ сервера можно сохранить. Тогда по умолчанию остаются и порты (VPN, панели, подписки, хаба), параметры обфускации, MTU, секретный путь, логин и пароль панели — они зашиты в выданные ключи, ссылки и закладки. Прежняя установка убирается только после ответа «да» на «Продолжить?».
- Удалить — полностью (без меню:
UNINSTALL=y, подтверждение «удалить» тогда не спрашивается).
Удаление снимает сервисы и юнит systemd, интерфейс awg1, nft-таблицы шейпинга и блокировки
торрентов, открытые установщиком порты, Prometheus из awg-ctrl monitor install,
/opt/awg-control, /etc/amnezia (пользователи, ключи, базы), команду awg-ctrl, sysctl-файл
и логи установки (в них пароль панели). Перед этим установщик предлагает сохранить копию данных
в /root/forgetting-backup-<время>.tar.gz. AmneziaWG (пакеты, модуль, PPA) — по отдельному
вопросу; общие зависимости (dkms, build-essential, iptables, заголовки ядра) остаются. Ноду
после удаления уберите и из списка серверов панели.
Несколько серверов
Подключить сервер. В панели «Добавить сервер» выдаёт строку awgjoin://… (действует час).
На новом сервере — установщик с ролью «Нода» и этой строкой, или на уже установленном —
awg-ctrl join '<awgjoin://…>'. Агент ноды сам подключается к хабу панели по WSS; доверие —
закреплённый отпечаток сертификата хаба и ключ ноды. В панели нода появляется в списке
серверов, ею управляют так же, как своим. awg-ctrl unjoin — отвязать.
Перенести панель на отдельный сервер (например, без VPN). «Настройки» → «Перенос» или CLI:
- На новом сервере — установка с ролью «Только панель».
- На новой панели — код переноса
awgmove://…; на старой — вставить его (илиawg-ctrl migrate exportна старом иawg-ctrl migrate import <архив>на новом). - Старый сервер становится нодой #0 новой панели и пересылает туда свои прежние порты:
ссылки
sen://, ноды и внешний API продолжают работать, закладки панели — тоже (новая панель принимает и свой секретный путь, и старый). - Когда раздел «Перенос» покажет, что новый адрес знают все устройства и ноды, старый
сервер можно выключать. Ноды, переехавшие вручную, —
awg-ctrl rehome <хост[:порт]>.
awg-ctrl migrate cancel — отменить на старом сервере, пока перенос не завершён.
Защита от обнаружения
Раньше у всех установок были одинаковые порт, параметры обфускации и ответы на запросы — одно правило DPI находило их все. Теперь общего у серверов нет:
VPN. На новой установке случайны:
- UDP-порт (20000–59999), если не задан
AWG_PORT; - параметры обфускации
Jc/Jmin/Jmax,S1–S4(размеры handshake-пакетов разные — по длине тип пакета не узнать),H1–H4(непересекающиеся диапазоны); I1— пакет-маскировка перед handshake: DNS-запрос к случайному популярному домену (формат проверяется до записи — его принимают и kernel-модуль, и amneziawg-go);- MTU в диапазоне 1320–1376.
При переустановке с сохранением данных всё это берётся из прежнего awg1.conf: параметры
зашиты в выданные ключи. Поэтому серверы, поставленные до рандомизации, сохраняют старые общие
значения — чтобы уйти от них, нужна переустановка без сохранения данных и раздача новых
ключей. Исключение — I1: его сервер не сверяет, и если в конфиге его не было, при переустановке
он генерируется новым, не ломая старые ключи.
Открытые порты отвечают тому, кто не доказал право на ответ, как пустой веб-сервер на Go —
404 page not found:
| Порт | Кому отвечает по протоколу |
|---|---|
| Панель | запросам под секретным путём (UI_PREFIX); с loopback — и без него |
Подписка sen:// |
peek/register с секретом мастер-ключа из ссылки; остальным запросам — с подписью ключом устройства |
| Хаб нод | агенту, подписавшему своим ключом сам запрос на WebSocket |
Подробности:
GET /ui/brand(имя и версия) — только после входа; экран логина не показывает имя продукта.- Удалённому устройству подписка отвечает
410(снять конфиг), только если запрос подписан его ключом (revoked_devices); устройства, удалённые до этой версии, получают тихий404. - Пока выдан код переноса,
POST /migrate/v1/importпринимается и без секретного пути. - Агенты нод прежних версий подписи не шлют: хаб пускает их, пока в панели есть нода, ни разу
не подключавшаяся по-новому, и пишет об этом в лог. Обновили все ноды — путь без подписи
закрывается сам (
HUB_LEGACYвcli.env— принудительно). Часы ноды могут расходиться с панелью до суток. - Самоподписанные сертификаты подписки и хаба получают случайное имя вместо общих
sen/awg-node. Клиенты и ноды сверяют ключ, а не имя; прежние сертификаты остаются со старым именем.
Чего это не закрывает. Секретный путь и тихий 404 защищают от активного сканирования.
Панель по умолчанию работает по голому HTTP — её трафик (пути, JSON, токены) виден в сети.
Ставьте её за nginx с TLS (ниже) или заходите по VPN. Подписка sen://
по умолчанию HTTPS, хаб — всегда TLS.
Журнал подключений
Вкладка «Подключения» показывает по выбранному серверу:
- События — кто подключился к VPN и отключился, когда, сколько длилась сессия и сколько скачал и отдал. Поиск — по имени пользователя, мастер-ключу, устройству или внутреннему IP.
- Кто когда был — все пользователи и устройства
sen://сервера: онлайн сейчас, когда были на связи последний раз и кто не подключался ни разу с начала журнала.
Журнал ведёт awg-ctrl каждого сервера (conn_log в users.db, 90 дней). У WireGuard нет событий
подключения, поэтому раз в 30 с он сверяет время handshake и счётчики трафика: «подключился» —
время первого handshake, «отключился» — последняя активность (точность около 30 с). Перезапуск
awg-ctrl сессии не рвёт, падение интерфейса отключением не считается. Внешний IP клиентов не
записывается. Серверы на прежней версии журнала не ведут — вкладка попросит их обновить.
Мониторинг
Встроенный Prometheus. «Настройки» → «Prometheus» → «Установить»: панель просит awg-ctrl
поставить его (awg-ctrl monitor install, только Debian/Ubuntu). Он слушает только
127.0.0.1:9090, хранит 31 день и забирает метрики всех серверов панели. Графики — скорость,
устройства онлайн, нагрузка, CPU и память — появляются через минуту-две. Удалить — там же или
awg-ctrl monitor remove. Графики — во вкладке «Монитор».
У панели без своего VPN Prometheus ставится на ноду (выберите её в шапке панели). Он
забирает метрики у агента на 127.0.0.1, а агент — у панели внутри TLS-соединения с хабом;
панель читает графики через того же агента. Снаружи этот трафик не отличить от обычной связи
ноды с панелью, секретный путь ему не нужен. Агенты старше 0.4.6 этого не умеют.
Свой Prometheus. «Настройки» → «Prometheus» → «Токен метрик»: выдать токен «только метрики»
(он не открывает ни панель, ни API) и скопировать готовый фрагмент prometheus.yml. Адрес в нём
берётся от страницы панели, поэтому уже содержит секретный путь
(metrics_path: /<путь>/metrics) или подпапку nginx. По голому HTTP токен и метрики идут
открытым текстом — скрейпьте через nginx с TLS или по VPN. Метрики по отдельным пирам
выключены (METRICS_PEERS=on в cli.env — включить).
Панель за nginx
Панель работает и в корне домена, и в любой подпапке — пути в ней относительные. Пример для
https://example.com/forgetting/ (39708 — UI_PORT из /opt/awg-control/cli/cli.env):
location = /forgetting { return 301 /forgetting/; }
location ^~ /forgetting/ {
proxy_pass http://127.0.0.1:39708/; # слэш в конце срезает префикс
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
nginx на этой же машине ходит к панели по loopback, поэтому секретный путь ему не нужен —
подпапка в nginx и становится путём панели (выберите неочевидную). Адрес клиента панель берёт
из X-Forwarded-For / X-Real-IP только от доверенного прокси: с loopback — всегда, с других
адресов — если они перечислены в TRUST_PROXY. Без этого все входы шли бы с адреса прокси и
делили один лимит неудачных попыток.
Сам порт панели после этого можно закрыть снаружи (ufw deny <UI_PORT>/tcp). Порты подписки
(SUB_PORT) и хаба нод (NODE_PORT) должны оставаться открытыми: клиенты и ноды ходят на них
напрямую, не через nginx.
API
Наружу смотрят две независимые поверхности. Публичный API /api/v1 — стабильный контракт
для сторонних программ, авторизация по API-ключу. Роуты панели — всё, что умеет
веб-интерфейс, авторизация по JWT.
В примерах HOST:PORT — адрес панели вместе с секретным путём:
http://203.0.113.9:39708/k3f9xQ2mTq8vLw0a. Без пути снаружи любой запрос получает 404.
Warning
Роуты панели отдают приватные поля пиров (
vpn_key,psk_key) — это не публичный контракт, в отличие от/api/v1. По голому HTTP они идут открытым текстом: ставьте панель за TLS.
Публичный API (/api/v1)
Ключ создаётся в «Настройках», на вкладке «API-ключи», и уходит в заголовке X-Api-Key.
Открытое значение показывается один раз при создании — на сервере лежит только
SHA-256 и префикс для показа в списке. Наружу отдаются только публичные поля:
psk_key и pub_key не покидают сервер.
curl -s -X POST http://HOST:PORT/api/v1/users \
-H "X-Api-Key: awgk_xxx" -H "Content-Type: application/json" \
-d '{"name":"alice"}' | jq -r .vpn_key
| Метод | Что делает |
|---|---|
POST /api/v1/users |
Создаёт пира. Тело { "name": "alice" }. 201 с { name, ip, gen, vpn_key }; 400 — имя не прошло валидацию, 409 — уже есть |
GET /api/v1/users |
Список со счётчиками: { users: [{ name, ip, key_gen, online, lastHandshake, rx, tx }] } |
GET /api/v1/users/:name |
{ name, ip, gen, vpn_key }; 404 — не найден |
DELETE /api/v1/users/:name |
{ "success": true, "name": "alice" } |
gen — поколение AmneziaWG, на параметрах которого собран ключ ("2" или "3.1"). Операции
только CRD: у пира нет изменяемых полей, «перевыпустить» ключ = удалить и создать заново.
У ключа — набор серверов, которые он видит (панель → «API-ключи» → шестерёнка; 0 — сервер
самой панели, остальные — подключённые ноды). Пользователи vpn:// заводятся на сервере ключа
по умолчанию; другой сервер из набора выбирается заголовком X-Server-Id: <id>, сервер вне
набора → 404.
Мастер-ключи sen://
Мастер-ключ — ссылка sen://… для приложения SenAWG с лимитом устройств: каждое устройство
само регистрируется по ссылке и получает пира на всех серверах ключа, его приватный ключ сервер
не видит. API-ключ видит и меняет мастер-ключ, только если все его серверы входят в набор
API-ключа; остальные для него не существуют (404).
curl -s -X POST http://HOST:PORT/api/v1/masterkeys \
-H "X-Api-Key: awgk_xxx" -H "Content-Type: application/json" \
-d '{"label":"Семья","device_limit":3}' | jq -r .link
| Метод | Что делает |
|---|---|
POST /api/v1/masterkeys |
Создаёт ключ. Тело { label, device_limit?, servers? } (лимит 1–100, по умолчанию 3; без servers — весь набор API-ключа). 201 с { id, uuid, label, device_limit, devices, servers, created_at, link, tls }; 403 — сервер вне набора, 503 — подписка не настроена (ключ не создаётся) |
GET /api/v1/masterkeys |
Список: { keys: [{ id, uuid, label, device_limit, devices, servers, created_at, deleting? }] }. uuid — постоянный идентификатор ключа: не меняется ни при перевыпуске ссылки, ни при правке метки. Везде, где в пути :id, можно передать и uuid |
GET /api/v1/masterkeys/:id |
Ключ, ссылка и устройства одним запросом: те же поля + link, tls, device_list (devices — счётчик) |
PATCH /api/v1/masterkeys/:id |
{ label?, device_limit?, servers? } — смена серверов сразу добавляет/снимает пиров устройств |
POST /api/v1/masterkeys/:id/rotate |
Новая ссылка { id, link, tls }; старая не принимает новые устройства, подключённые работают дальше |
POST /api/v1/masterkeys/:id/rekey |
Все устройства сменят ключи WireGuard при следующем опросе (IP и PSK сохраняются) |
DELETE /api/v1/masterkeys/:id |
{ success, id, pending } — ключ и устройства отключаются сразу; pending — серверы (ноды не в сети), которые ещё не сняли пиров, до тех пор ключ в списке с deleting |
GET /api/v1/masterkeys/:id/devices |
{ devices: [{ id, device_name, platform, version, online, lastHandshake, rx, tx, last_seen, servers_ok, servers_total, … }] } — статистика по всем серверам ключа |
DELETE /api/v1/masterkeys/:id/devices/:device |
Отвязывает устройство, место освобождается |
POST /api/v1/masterkeys/:id/devices/:device/rekey |
Устройство сменит ключ при следующем опросе |
POST /api/v1/masterkeys/:id/devices/:device/psk |
Новый PSK: { id, pending } — pending серверов ждут ноду |
| Код | Когда |
|---|---|
401 {"error":"API key required"} |
заголовка нет или он не начинается с awgk_ |
401 {"error":"Invalid API key"} |
ключ не найден — удалён или неверен |
502 {"error":"awg-ctrl недоступен"} |
awg-ui посредничает, а awg-ctrl не отвечает |
Ключи лежат в собственной БД панели (/etc/amnezia/amneziawg/ui.db), поэтому переустановка их
не трогает. Сама awg-ctrl про внешние ключи ничего не знает: awg-ui ходит к ней своей
внутренней авторизацией. Управлять ключами можно и без панели, по JWT: GET/POST /ui/apikeys
(с полем servers), PATCH /ui/apikeys/:id { "servers": [0, 2] } — сменить набор, не
перевыпуская ключ, и DELETE /ui/apikeys/:id.
Авторизация панели
TOKEN=$(curl -s -X POST http://HOST:PORT/login \
-H "Content-Type: application/json" \
-d '{"user":"admin","pass":"***"}' | jq -r .token)
| Метод | Ответ и ошибки |
|---|---|
POST /login |
{ "token": "<JWT>" }, срок 24 часа. 401 — неверная пара; 429 — больше 5 неудачных попыток с одного IP за 15 минут |
POST /logout |
{ "ok": true }, токен отзывается немедленно |
Дальше в каждый запрос: Authorization: Bearer $TOKEN; сервер — заголовком X-Server-Id
(без него — сервер по умолчанию). Ниже — роуты, которые дёргает сама панель; в отличие от
/api/v1 их форма может меняться.
Состояние
| Метод | Ответ |
|---|---|
GET /ui/brand |
{ "brand": "Forgetting", "channel": "Beta", "version": "0.5.2" } — имя и версия панели для вордмарка; за авторизацией, чтобы сканер не опознал панель |
GET /health |
{ "status", "server", "ip", "gen", "awg": { "status", "peers", "module", "tools" } }. 200, если интерфейс поднят, иначе 503 и status: "degraded" |
GET /awg/status |
{ "up": true, "peers": 3, "publicKey": "…" } |
gen — поколение AmneziaWG, на параметрах которого сейчас работает интерфейс: "2" или
"3.1". Оно выводится из awg1.conf, а не хранится отдельно.
Пользователи
| Метод | Что делает |
|---|---|
POST /api/users |
Создаёт пира. Тело { "name": "alice" }, имя — a–z A–Z 0–9 _ -, до 32 символов. 201 с { name, ip, pub_key, psk_key, vpn_key, key_gen, vpn_key_prev }; 400 — имя не прошло валидацию, 409 — уже есть |
GET /api/users |
Список: { users: [{ name, ip, pub_key, vpn_key, key_gen, online, lastHandshake }] } |
GET /api/users/stats |
То же без ключей, но со счётчиками: { users: [{ name, ip, key_gen, online, lastHandshake, rx, tx }] } |
POST /api/users/:name |
Возвращает пользователя целиком, включая vpn_key. Метод именно POST, чтобы ключ не оседал в логах и истории как параметр GET. 404 — не найден |
DELETE /api/users/:name |
{ "success": true, "name": "alice" } |
POST /api/users/reissue |
Пересобирает vpn:// всем на текущих параметрах: { total, reissued, regenerated: [], backup }. IP и ключевая пара сохраняются, клиентам нужно заново импортировать ключ; backup — путь к снимку базы, снятому перед проходом |
curl -s -X POST http://HOST:PORT/api/users \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"name":"alice"}' | jq -r .vpn_key
Имея vpn_key, конфиг .conf можно получить локально: убрать префикс vpn://,
base64url-декодировать, отбросить первые 4 байта (длина), распаковать zlib inflate → JSON;
текст конфига лежит в last_config.config.
Журнал подключений
| Метод | Ответ |
|---|---|
GET /ui/connlog |
Журнал сервера из X-Server-Id: { events: [{ id, at, event, name, owner, ip, key?, device?, duration?, rx?, tx? }], peers: [{ name, owner, ip, online, last_seen, key?, device? }], since, keep_days }. event — connect или disconnect (у него duration, rx, tx — со стороны сервера); key/device — мастер-ключ и устройство sen://. Параметры: limit (до 500), before=<id> — следующая страница, q — поиск по имени, владельцу, IP. 501 — сервер старой версии |
Без имён sen:// тот же журнал отдаёт awg-ctrl: GET /api/connlog.
Интерфейс AWG
| Метод | Что делает |
|---|---|
POST /awg/start |
Поднимает интерфейс, если он лежит; возвращает его статус |
POST /awg/restart |
awg-quick down/up + ресинк пиров, { "success": true }. Соединения клиентов кратковременно рвутся |
POST /awg/upgrade |
Переводит сервер с 2.0 на 3.1: правит awg1.conf, перезапускает интерфейс и перевыпускает все ключи. { gen, backup, bumpedS: [], reissue: { total, reissued, … } } |
POST /awg/upgrade отвечает 409, если сервер уже на 3.1, модуль в ядре не 3.x или ядро
старше 5.5, и 500 с текстом причины, если ядро не приняло 3.1-конфиг — в этом случае прежний
конфиг возвращается из копии, а интерфейс поднимается обратно на 2.0.
Мастер-ключи
Те же операции, что в /api/v1/masterkeys, но без ограничения набором серверов.
| Метод | Что делает |
|---|---|
GET /ui/masterkeys |
{ enabled, tls, keys: [{ id, uuid, label, device_limit, devices, servers, created_at, deleting? }], defaults }; :id в путях — id или uuid; defaults — серверы новых ключей или null |
POST /ui/masterkeys |
{ label, device_limit?, servers? } → 201; без servers — defaults, а нет их — сервер по умолчанию |
POST /ui/masterkeys/servers |
«Серверы для всех»: { add?, remove?, defaults?, dry_run? } — add появляются у всех живых ключей, remove снимаются у всех, прочие серверы ключей не трогаются; defaults (null — сбросить) — набор новых ключей. → { changed, total, hidden: [{ id, label, keys }] }, hidden — ключи API, которые перестанут видеть столько мастер-ключей (сервер вне их области). 409, если у ключа не останется серверов |
PATCH /ui/masterkeys/:id |
{ label?, device_limit?, servers? } |
GET /ui/masterkeys/:id/link |
{ link, tls } — ссылка sen://… |
GET /ui/masterkeys/:id/devices |
Устройства со статусом и трафиком |
POST /ui/masterkeys/:id/rotate, /rekey |
Новая ссылка / смена ключей у всех устройств |
DELETE /ui/masterkeys/:id |
{ success, id, pending } |
DELETE /ui/devices/:id |
Отвязать устройство |
POST /ui/devices/:id/rekey, /psk |
Смена ключа / PSK у устройства |
Метрики
| Метод | Что делает |
|---|---|
GET /ui/metrics-token |
{ exists, prefix?, created_at?, last_used?, per_peer } — токен для своего Prometheus |
POST /ui/metrics-token |
Выпустить или перевыпустить: 201 с token (показывается один раз); старый перестаёт работать |
DELETE /ui/metrics-token |
Отозвать |
GET /metrics |
Экспозиция Prometheus по всем серверам; Authorization: Bearer awgm_… |
Управление
awg-ctrl # меню
awg-ctrl start|stop|restart|status # status показывает и адрес панели с путём
awg-ctrl credentials [user|pass] # логин и пароль панели, адрес
awg-ctrl join '<awgjoin://…>' [--no-panel] / unjoin
awg-ctrl rehome <хост[:порт]> # нода: панель переехала на новый адрес
awg-ctrl peers [drop <область>] # пиры sen:// на этом сервере по панелям
awg-ctrl monitor install|status|remove # встроенный Prometheus
awg-ctrl migrate export [файл] # перенос панели (см. «Несколько серверов»)
awg-ctrl migrate import <архив>
awg-ctrl migrate cancel
awg-ctrl update | reinstall | uninstall # обновить, переустановить, удалить (через install.sh)
awg-ctrl panel [path new|off|<путь>] # адрес панели; новый, свой или без секретного пути
awg-ctrl log [<поиск>] [-n N] # журнал VPN-подключений этого сервера
awg-ctrl log seen # кто когда был: онлайн, последний раз, не подключался
awg-ctrl metrics [token|revoke] # токен и prometheus.yml для своего Prometheus
awg-ctrl hub [legacy on|off|auto] # ноды хаба: кто с подписью, кто ещё старый
awg-ctrl check # что на сервере выдаёт его сканеру и DPI
В меню awg-ctrl те же возможности — пункты 10–13: адрес и секретный путь панели, журнал,
«кто когда был» и проверка скрытности.
update и reinstall скачивают свежий установщик (INSTALLER_URL в cli.env — своё
зеркало), uninstall берёт его копию из установки и работает без сети.
Через systemd (автозапуск на загрузке):
systemctl start|stop|restart awg-control
Настройки cli.env
/opt/awg-control/cli/cli.env пишет установщик; после правки — awg-ctrl restart. Чаще всего
нужны:
| Переменная | Что делает |
|---|---|
UI_PORT, UI_USER, UI_PASS |
порт, логин и пароль панели (awg-ctrl credentials) |
UI_PREFIX |
секретный путь панели; пусто — без пути |
UI_PREFIX_MOVED |
путь панели, переехавшей сюда: принимается вместе со своим |
SUB_PORT, SUB_TLS, SUB_HOST |
подписка sen://: порт, HTTPS, адрес в ссылках |
NODE_PORT |
хаб нод; пусто — ноды не принимаются |
HUB_LEGACY |
on / off — пускать ли агентов нод без подписи; пусто — пока не обновлены все |
TRUST_PROXY |
IP или сети reverse-proxy, кроме loopback: от них верим X-Forwarded-For |
METRICS_PEERS |
on — метрики по отдельным пирам |
AUDIT |
off — выключить периодический аудит пиров |
INSTALLER_URL |
откуда awg-ctrl update/reinstall берут установщик (своё зеркало) |
Лицензия
MIT © 2026 Ivan Vasilev