Claude ea07914249 awg-ctrl: update, reinstall and uninstall from the menu
The awg-ctrl menu only started, stopped and changed the panel login; updating
or removing an installation meant finding and running install.sh by hand. The
menu gets "Обновить", "Переустановить" and "Удалить" (7–9), and the same as
`awg-ctrl update | reinstall | uninstall`.

The work stays in install.sh, which now takes ACTION=update|reinstall|uninstall
to skip its own menu. The CLI fetches it — the latest from INSTALLER_URL
(GitHub by default) for update and reinstall, the copy shipped in the release
archive for uninstall, so removal works offline — writes it to a temp file and
execs bash on it in the same terminal. It must not run from /opt/awg-control or
via `bash -c`: kill_related kills every process whose command line holds the
install path, and would kill the installer itself. The CLI passes its original
environment, not the one with cli.env loaded, or the installer would take
UI_PORT, SERVER_NAME and the rest as explicit overrides. The installer deletes
its temp copy on start.

The release archive now includes install.sh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013bNGYiDst62wH3ZGTRPFLJ
2026-10-28 12:50:00 +00:00
2026-09-10 00:24:18 +03:00
2026-10-27 21:52:55 +03:00
2026-10-27 21:52:55 +03:00
2026-10-27 21:52:55 +03:00
2026-10-27 21:52:55 +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.4.7" }
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)

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.3 MiB
v0.3.3
Latest
2026-09-27 13:23:02 +00:00
Languages
TypeScript 42.3%
Go 41%
Shell 8.1%
CSS 6.9%
JavaScript 1.6%