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.
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": "<имя>" }
Имя: a–z A–Z 0–9 _ -, 1–32 символа.
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