fix(awg): infer wg0 iface from wg0.conf; chmod600 before syncconf

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Андрей Бобырев
2026-05-15 01:09:09 +03:00
parent 6faf696650
commit 65e10ae625
2 changed files with 22 additions and 3 deletions

View File

@@ -96,6 +96,10 @@ curl -fsSL https://raw.githubusercontent.com/andrey271192/amnezia_web/main/scrip
Если на хосте уже что-то слушает **TCP 80**, установщик сообщит об этом и, при дефолтном **`LANDING_PORT=80`**, сам попробует другой свободный порт (обычно начиная с **8081**). Либо явно: **`LANDING_PORT=8083`**, либо **`SKIP_LANDING=1`**. Если на хосте уже что-то слушает **TCP 80**, установщик сообщит об этом и, при дефолтном **`LANDING_PORT=80`**, сам попробует другой свободный порт (обычно начиная с **8081**). Либо явно: **`LANDING_PORT=8083`**, либо **`SKIP_LANDING=1`**.
### AmneziaWG Legacy: удаление клиента не срабатывает (`wg0.conf is world accessible` / `No such device`)
Панель синхронизирует живой интерфейс через **`wg-quick strip` + `syncconf`**. У Legacy конфиг часто **`/opt/amnezia/awg/wg0.conf`**, интерфейс — **`wg0`**, не **`awg0`**. В актуальном коде интерфейс выводится из **имени файла** (**`wg0.conf``wg0`**). Если путь другой — задайте в профиле **`AWG_IFACE`** / в **`AWG_PROFILES`** поле **`iface`**. Предупреждение про world-accessible: перед применением конфига файл на стороне контейнера выставляется в **`chmod 600`**.
--- ---
## Лицензия ## Лицензия

View File

@@ -707,11 +707,23 @@ function peerUsesWarp(peer, selectedSet) {
return false; return false;
} }
/** Имя интерфейса для `awg|wg syncconf` и `… show`: при Legacy часто `/…/wg0.conf`, а в env остаётся дефолт `awg0`. */
function resolveTunnelIface(profile) {
const cp = String(profile.confPath || "");
const m = cp.match(/\/([^/.]+)\.conf$/);
if (m) {
const stem = m[1];
const low = stem.toLowerCase();
if (low === "wg0" || low === "awg0") return stem;
}
return profile.iface;
}
function createRuntime(profile) { function createRuntime(profile) {
const container = profile.container; const container = profile.container;
const confPath = profile.confPath; const confPath = profile.confPath;
const clientsPath = profile.clientsPath; const clientsPath = profile.clientsPath;
const iface = profile.iface; const iface = resolveTunnelIface(profile);
const wgBinary = profile.wgBinary; const wgBinary = profile.wgBinary;
const pskPath = profile.pskPath; const pskPath = profile.pskPath;
@@ -749,7 +761,9 @@ function createRuntime(profile) {
async function applySyncconf() { async function applySyncconf() {
await dockerExec( await dockerExec(
`wg-quick strip '${confPath}' > /tmp/wg-admin-strip.conf && ${wgBinary} syncconf ${iface} /tmp/wg-admin-strip.conf` `chmod 600 '${confPath}' 2>/dev/null || true` +
`; wg-quick strip '${confPath}' > /tmp/wg-admin-strip.conf` +
` && ${wgBinary} syncconf ${iface} /tmp/wg-admin-strip.conf`
); );
} }
@@ -776,6 +790,7 @@ function createRuntime(profile) {
return { return {
profile, profile,
tunnelIface: iface,
dockerExec, dockerExec,
dockerReadFile, dockerReadFile,
dockerWriteFile, dockerWriteFile,
@@ -1741,7 +1756,7 @@ app.get("/api/clients", requireAuth, async (req, res) => {
try { try {
let wgShow = ""; let wgShow = "";
try { try {
wgShow = await rt.dockerExec(`${rt.profile.wgBinary} show ${rt.profile.iface}`); wgShow = await rt.dockerExec(`${rt.profile.wgBinary} show ${rt.tunnelIface}`);
} catch { } catch {
wgShow = ""; wgShow = "";
} }