Приложение AmneziaVPN при переподключении пересобирает clientsTable из awg0.conf
и оставляет только clientId с именами «Client N» — имена, даты создания и last_config
пропадают. Панель теперь держит снимок этих полей в DATA_DIR и восстанавливает их
при следующем чтении состояния, попутно чиня файл в контейнере.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The instances section listed only panel-managed instances, so an
AmneziaWG container set up by the Amnezia desktop app (e.g.
amnezia-awg2) did not appear as a card.
/api/instances now iterates ALL effective profiles (env-discovered +
managed): resolves each container, reads ListenPort and peer count,
and detects the variant from the interface config (S3/S4 -> awg2,
S1/S2 -> awg, wg0 -> legacy). Native (non-managed) instances are
flagged managed:false.
UI: native cards get an "приложение Amnezia" tag and hide the Удалить
button (the panel must not tear down app-managed containers); they
keep Подключения and Стоп/Старт. Stop/start now resolve the real
container name so they work for native instances too.
Verified live: native amnezia-awg2 shows as "AmneziaWG 2.0" port
37395 (managed:false) alongside a panel-created Legacy :5534.
Add a "Протоколы / инстансы" section that spins up AmneziaWG server
containers straight from the panel, with port + variant selection —
no need to run the Amnezia desktop app to set up the server.
Core (scripts/awg-instance.sh):
- create <awg2|awg|legacy> <port> [name]: pulls the public image
(amneziavpn/amneziawg-go:2.0.0 / :0.2.18 / amneziavpn/amnezia-wg),
generates server keys + psk, writes awg0.conf/wg0.conf with a free
10.8.<N>.0/24 subnet (scans running containers to avoid clashes),
random AmneziaWG obfuscation (Jc/Jmin/Jmax/S1..S4/H1..H4 as single
uint32 values — ranges break awg setconf), and a start.sh that
brings the iface up via userspace amneziawg-go + NAT MASQUERADE.
remove <name>, list.
Backend (server.js):
- Profiles are now dynamic: env AWG_PROFILES merged with managed
instances persisted in /data/instances.json (getProfiles()), so a
new instance is usable immediately without restarting the panel.
- /api/instances (list with running/peers), /api/instances/create,
/delete, /stop, /start. create runs the script then registers the
profile; delete tears down container + data + profile.
Infra:
- Dockerfile: add bash iproute2 coreutils, COPY scripts.
- install.sh: mkdir /opt/amnezia-instances and bind-mount it into the
panel so docker-in-docker bind paths line up.
UI (index.html/app.js/styles.css):
- Cards per instance (icon, NEW badge, description, РАБОТАЕТ/ОСТАНОВЛЕН,
port, connections) with Стоп/Старт, Подключения (switches the active
instance), Удалить; plus a create form (variant + port).
Verified end to end on a live VPS: create awg2/awg/legacy instances,
interfaces come up, a client created on a new instance gets the right
subnet (10.8.20.2) and Endpoint (host:51850).
Tester hit 'No such container: amnezia-awg' after a stock install
on a VPS where Amnezia created the WG container as amnezia-awg2.
Install-time detection was not enough.
The panel now resolves the real container at runtime: if the
configured AWG_CONTAINER lacks the conf file (or does not exist),
it scans running containers for one holding awg0.conf, preferring
amnezia-awg* names. All docker exec paths (clients list/create/
enable/disable/delete, WARP, host-setup) and the API container
field use the resolved name. Clear error lists running containers
if none match.
Result: install -> login -> change password -> create client works
with no manual AWG_CONTAINER/AWG_PROFILES on single-instance setups.
Two issues reported on direct/cascade client creation:
- DNS hardcoded to Google (8.8.8.8/8.8.4.4). Default now 1.1.1.1/
1.0.0.1 (Amnezia standard); still overridable via
CLIENT_EXPORT_DNS1/DNS2 env.
- Config emitted empty I2 =/I3 =/I4 =/I5 = lines when the server
only defines I1. Now only non-empty I-params are written, so the
client's AmneziaWG obfuscation matches the server head exactly
(mismatched/empty junk lines could break some clients).
Add "Новый клиент" (direct) flow alongside cascade:
- server.js: POST /api/clients/create — Endpoint = this server's
public IP:ListenPort (CLIENT_CONFIG_ENDPOINT or request host),
reuses the same key/peer/conf pipeline as create-cascade.
- public/index.html: "Новый клиент" panel with #direct-form
(name + optional tunnel IP).
- public/app.js: downloadDirectConf() handler + form binding.
install.sh hardening so fresh installs work out of the box:
- Auto-detect a single amnezia-awg* container (e.g. amnezia-awg2,
Amnezia AWG 2.0 default) -> AWG_CONTAINER, instead of the fixed
"amnezia-awg" default that mismatched and blocked client ops.
- Auto-default CLIENT_CONFIG_ENDPOINT to the host primary IP so
direct .conf exports get a correct Endpoint without manual env.
Fixes "cannot create users" on servers whose WG container is
named amnezia-awg2.
Add AMNEZIA_EDITION=community with API/UI locks for client mutations,
export, cascade, WARP and host time sync; banner + Boosty CTA.
Install passes edition from AMNEZIA_EDITION env or .amnezia-panel-edition.
Co-authored-by: Cursor <cursoragent@cursor.com>
Hide users/warp/cascade blocks via env; block warp/cascade APIs when hidden.
install.sh passes UI_HIDE_* and restores from previous container on upgrade.
Co-authored-by: Cursor <cursoragent@cursor.com>
- POST /api/clients/create-cascade: genkeys, add peer, save last_config, download .conf
- Optional tunnel IP in VPN subnet; obfuscation from server [Interface] when present
- /api/protocols: singleProfile hint for missing instance selector
- UI: cascade form, profile banner; README cascade section
Co-authored-by: Cursor <cursoragent@cursor.com>
- install.sh: snapshot /root/amnezia-admin.awg-profiles.json + restore from old container
- GET /api/clients/export-config (+ profileId); optional EXPORT_CONFIG_SECRET
- UI: direct link, copy URL, hint when last_config missing
Co-authored-by: Cursor <cursoragent@cursor.com>
Adds POST /api/clients/export-config, UI button when exportAvailable, CLIENT_* env for Endpoint/DNS in install.sh.
Co-authored-by: Cursor <cursoragent@cursor.com>