maeneko 21c7409017 Check every push with CI
Nothing verified a push to main: the only workflow triggers on v* tags, so an
incomplete commit — one whose new files were never staged, leaving an import
pointing at a file that does not exist — sat on main for two days without a
signal.

This runs on every branch push and pull request: bash -n on the installer,
tsc across awg-ctrl, awg-ui and cli, and the Vite build. awg-ui's tsconfig
covers server.ts, so the missing-module case is exactly what the awg-ui step
reports. The same workflow is added for both hosts, since releases are now
published from GitHub and Gitea alike.

awg-ctrl's tsconfig had `include: [""]`, which matches no files at all
(TS18003) — the awg-ctrl step would have failed on the config rather than on
real errors, so it now points at index.ts.
2026-08-29 03:21:40 +03:00
2026-08-29 03:21:40 +03:00
2026-08-29 03:21:40 +03:00
2026-07-10 00:19:05 +03:00
2026-07-10 00:19:05 +03:00
2026-08-29 03:08:51 +03:00

Forgetting

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

Warning

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

Архитектура

Три компонента, устанавливаются в /opt/awg-control/:

Компонент Роль
awg-ctrl Привилегированный REST-бэкенд. Управляет пирами через awg/awg-quick, ведёт SQLite-базу, генерирует vpn:// ключи. Слушает только loopback.
awg-ui Express + React. Веб-панель, аутентификация (JWT), интеграция с API MA7, прокси к awg-ctrl. Единственный сервис, доступный по сети.
cli Менеджер процессов: start/stop/restart/status, смена логина/пароля панели, интерактивное TUI-меню.

Внутренняя связь awg-ui → awg-ctrl подписывается асимметрично (Ed25519): приватный ключ только у awg-ui, awg-ctrl проверяет подпись публичным.

Требования

  • ОС: Ubuntu 24.04+ (Тесты проходили на Ubuntu 24.04.4 LTS)
  • Права: root.
  • Ядро: kvm (не OpenVZ/LXC/Docker/WSL — нужен загружаемый kernel-модуль AmneziaWG).
  • Заголовки ядра под текущее ядро (для сборки DKMS-модуля).
  • Node.js 20.x (ставится установщиком автоматически).

Совместимость установщик проверяет сам перед любыми изменениями.

Установка

На сервере, от root:

bash <(curl -Ls https://git.ma7neko.ru/maeneko/forgetting/raw/branch/main/install.sh)

Установщик по умолчанию ставит сервер на AmneziaWG 3.1. Если модуль в ядре старше 3.x или ядро старше 5.5, установка остановится с диагностикой — поставить на 2.0 можно так:

AWG_GEN=auto bash <(curl -Ls https://git.ma7neko.ru/maeneko/forgetting/raw/branch/main/install.sh)

Перевести такой сервер на 3.1 позже можно кнопкой «Перейти на AWG 3.1» в панели — переустановка не нужна, пользователи сохраняются, ключи перевыпускаются автоматически.

Свой источник и своё имя

В коде не зашиты ни репозиторий, ни бренд — всё задаётся окружением до запуска:

Переменная По умолчанию Зачем
REPO_BASE https://git.ma7neko.ru/maeneko/forgetting основной источник архива релиза
REPO_FALLBACK https://github.com/maeneko/forgetting запасной, если в основном релиза ещё нет
ARCHIVE_URL — полный URL архива, перекрывает оба варианта
BRAND из .env имя продукта в баннерах, systemd-юните и панели

Путь релиза у Gitea и GitHub одинаковый (<repo>/releases/download/v<версия>/awgcontrol-<версия>.tar.gz), так что подходит любой из них. Если архив не найден в основном источнике, установщик предупреждает и берёт его из запасного.

Архив собирается по тегу v*: на GitHub — .github/workflows/release.yml, в Gitea — .gitea/workflows/release.yml (сборка та же, публикация через API Gitea). Для запуска в Gitea репозиторий не должен быть pull-зеркалом, Actions включены, а runner зарегистрирован с меткой ubuntu-latest.

REPO_BASE=https://git.example.org/me/vpn BRAND="My VPN" \
  bash <(curl -Ls https://git.example.org/me/vpn/raw/branch/main/install.sh)

Имя панели, канал и версия лежат в .env в корне проекта (едет в архиве релиза, на сервере — /opt/awg-control/.env):

BRAND=Forgetting
CHANNEL=Beta
VERSION=0.2.0

Оттуда их читают CLI (баннер меню) и панель (вордмарк, GET /ui/brand). BRAND= при установке перекрывает значение из файла.

Сама панель и её API к домену не привязаны: работают по адресу того сервера, куда установлены, внешних сервисов не требуют.

Управление

awg-ctrl 

Через systemd (автозапуск на загрузке):

systemctl start|stop|restart awg-control

Интеграция с MA7

Этот сервер персональный — принадлежит одному абоненту MA7 (сервиса VPN-подписки). Панель ничем не управляет в MA7 и не отдаёт наружу свой API: вкладка «Профиль» только читает баланс своего владельца. Секрет MA7 живёт только в awg-ui (cli.env) и в браузер не попадает — фронт ходит на свой бэкенд, тот читает MA7.

Нужные переменные (задаются при установке или руками в cli.env):

Переменная Назначение
MA7_API_BASE_URL адрес API MA7, например https://amnesia.ma7neko.ru
MA7_JWT_SECRET секрет, которым панель сама подписывает X-Bot-Token (эндпоинта, выдающего токен, в MA7 нет)
MA7_LOGIN логин владельца этого сервера в MA7 (ma7_xxxxxx)

Вкладка «Профиль» просто показывает текущий баланс MA7_LOGIN. При установке MA7_LOGIN заодно предлагается как логин панели (UI_USER) — сервер персональный, и заказчик входит тем же именем, что знает по MA7; при желании логин панели можно задать свой. Это разные переменные: UI_USER решает, кого пускать в панель, MA7_LOGIN — чей баланс показывать.

MA7_LOGIN задаётся один раз при установке и не редактируется из панели: у панели один общий пароль (UI_USER/UI_PASS) без отдельного клиентского входа, а MA7_JWT_SECRET умеет искать в MA7 любого абонента — редактируемый в браузере логин превратил бы личный баланс в инструмент подглядывания за чужими.

Warning

MA7_JWT_SECRET — мастер-ключ ко всему MA7: с ним можно читать данные любых пользователей MA7, не только этого сервера. Токены MA7 без срока действия, отзыва нет — «отобрать доступ» значит одновременно сменить MA7_JWT_SECRET во всех сервисах MA7 и здесь, в cli.env.

Лицензия

MIT © 2026 Ivan Vasilev

S
Description
No description provided
Readme MIT
2 MiB
v0.3.3
Latest
2026-09-27 13:23:02 +00:00
Languages
TypeScript 44.2%
Go 41.8%
Shell 6.9%
CSS 5.2%
JavaScript 1.8%