maeneko 6fdacd71c3 Fix 3.1 rollout on servers with an older loaded module and UFW
Three defects surfaced on a real upgrade from 2.0.

The module gate read modinfo, which reports the version on disk. apt
--only-upgrade rebuilds the DKMS module but does not replace the one already
loaded, so the installer wrote a 3.1 conf that the running 2.0 module rejected
with 'Unable to modify interface: Invalid argument'. It now compares
/sys/module/amneziawg/version, reloads the module when it lags behind the disk,
and decides the generation from the loaded version only.

Bringing the interface up is the only real proof the kernel accepted the 3.1
parameters, so a failure there no longer aborts the install: it enables dynamic
debug, retries, prints the amneziawg lines from dmesg, then strips the 3.x keys
and comes up on 2.0. The rejected conf is kept as awg1.conf.awg31.

PostUp appends 'iptables -A FORWARD', but UFW inserts its jumps at the head of
the chain, so client traffic was dropped with '[UFW BLOCK] IN=awg1 OUT=eth0' —
the tunnel connected and had no internet. When UFW is active the installer now
adds 'ufw route allow in on awg1 out on eth0' and opens the AWG and UI ports.

Version 0.1.4.1.
2026-08-17 18:48:38 +03:00
2026-07-10 00:19:05 +03:00
2026-07-10 00:19:05 +03:00
2026-07-10 01:42:06 +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 (/api/v1), прокси к 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://raw.githubusercontent.com/maeneko/forgetting/main/install.sh)

Управление

awg-ctrl 

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

systemctl start|stop|restart awg-control

1. Публичный API (/api/v1)

Авторизация по API-ключу. Ответы содержат только публичные поля — приватные ключи и PSK наружу не отдаются.

Авторизация

Каждый запрос обязан содержать заголовок:

X-Api-Key: awgk_<...>

Ключ создаётся в панели (вкладка «API-ключи») или через POST /ui/apikeys (раздел 3). Открытое значение ключа показывается один раз при создании — сохрани его сразу, дальше доступен только хэш.

Ответы при проблемах с ключом:

Код Когда
401 {"error":"API key required"} заголовок отсутствует или не начинается с awgk_
401 {"error":"Invalid API key"} ключ не найден (удалён/неверный)

Ключ привязан к серверу (server_id). Сейчас сервер один — поле всегда 0

POST /api/v1/users — создать пользователя

Создаёт VPN-пира и возвращает готовый vpn:// ключ.

Тело: { "name": "<имя>" } Имя: az AZ 09 _ -, 132 символа.

201 Created:

{
  "name": "alice",
  "ip": "10.9.0.2",
  "vpn_key": "vpn://AAAI..."
}
Код ошибки Причина
400 имя не прошло валидацию
409 пользователь с таким именем уже есть
curl -X POST http://HOST:PORT/api/v1/users \
  -H "X-Api-Key: awgk_xxx" \
  -H "Content-Type: application/json" \
  -d '{"name":"alice"}'

GET /api/v1/users — список пользователей

Пиры с трафиком и статусом онлайн. 200 OK:

{
  "users": [
    { "name": "alice", "ip": "10.9.0.2", "online": true,  "lastHandshake": 1718800000, "rx": 142400000, "tx": 9800000 },
    { "name": "bob",   "ip": "10.9.0.3", "online": false, "lastHandshake": 0,          "rx": 0,         "tx": 0 }
  ]
}
  • lastHandshake — unix-секунды последнего рукопожатия (0 — не было).
  • rx/tx — байты принято/отдано.
curl http://HOST:PORT/api/v1/users -H "X-Api-Key: awgk_xxx"

GET /api/v1/users/:name — получить ключ пользователя

200 OK:

{ "name": "alice", "ip": "10.9.0.2", "vpn_key": "vpn://AAAI..." }
Код ошибки Причина
404 пользователь не найден
curl http://HOST:PORT/api/v1/users/alice -H "X-Api-Key: awgk_xxx"

Имея vpn_key, конфиг .conf можно получить локально: убрать префикс vpn://, base64url-декодировать, отбросить первые 4 байта (длина), распаковать zlib inflate → JSON; текст конфига лежит в last_config.config.

DELETE /api/v1/users/:name — удалить пользователя

200 OK:

{ "success": true, "name": "alice" }
curl -X DELETE http://HOST:PORT/api/v1/users/alice -H "X-Api-Key: awgk_xxx"

Лицензия

MIT © 2026 Ivan Vasilev

S
Description
No description provided
Readme MIT
118 KiB
Languages
TypeScript 62.1%
Shell 24.7%
CSS 13%
HTML 0.2%