maeneko 1ea2eda04a Keep the session on network errors when restoring it
Only a 401 clears the saved token; a network error or 5xx while the
panel restarts retries every 5 s instead of dropping to the login screen.
2026-10-29 23:49:49 +03:00
2026-09-10 00:24:18 +03:00
2026-07-10 00:19:05 +03:00

Forgetting

Панель управления и API для VPN на базе AmneziaWG

Warning

Данный проект предназначен только для использования в законных целях.

  • VPN-пользователи с ключами vpn:// для AmneziaVPN и мастер-ключи sen:// для SenAWG: одна ссылка на несколько устройств, каждое регистрируется само.
  • Несколько серверов под одной панелью: ноды подключаются к ней сами, панель можно вынести на отдельный сервер без VPN.
  • Журнал подключений: кто, когда и сколько был в VPN, кто давно не подключался.
  • Мониторинг: встроенный Prometheus и графики в панели, метрики для своего Prometheus.
  • Защита от обнаружения: параметры обфускации, порты и пути у каждого сервера свои, а открытые порты отвечают сканеру как пустой веб-сервер.

Содержание

Архитектура

Один статический бинарник 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 — предлагает:

  1. Обновить — новая версия, настройки, пользователи и роль сохраняются. Установке без секретного пути панели он выдаётся, и установщик печатает новый адрес: закладки и адрес внешнего API нужно обновить. Оставить без пути — UI_PREFIX=off перед запуском или пустое UI_PREFIX= в cli.env.
  2. Переустановить — с нуля; пользователей и ключ сервера можно сохранить. Тогда по умолчанию остаются и порты (VPN, панели, подписки, хаба), параметры обфускации, MTU, секретный путь, логин и пароль панели — они зашиты в выданные ключи, ссылки и закладки. Прежняя установка убирается только после ответа «да» на «Продолжить?».
  3. Удалить — полностью (без меню: 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:

  1. На новом сервере — установка с ролью «Только панель».
  2. На новой панели — код переноса awgmove://…; на старой — вставить его (или awg-ctrl migrate export на старом и awg-ctrl migrate import <архив> на новом).
  3. Старый сервер становится нодой #0 новой панели и пересылает туда свои прежние порты: ссылки sen://, ноды и внешний API продолжают работать, закладки панели — тоже (новая панель принимает и свой секретный путь, и старый).
  4. Когда раздел «Перенос» покажет, что новый адрес знают все устройства и ноды, старый сервер можно выключать. Ноды, переехавшие вручную, — 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.0" } — без авторизации, панель берёт отсюда вордмарк на экране логина
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

S
Description
No description provided
Readme MIT
1.5 MiB
v0.3.3
Latest
2026-09-27 13:23:02 +00:00
Languages
TypeScript 42.4%
Go 41%
Shell 8.1%
CSS 6.9%
JavaScript 1.5%