From ef463d3d8540554e2d0a147e84f64b116382480a Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Thu, 14 Aug 2025 14:10:18 +0700 Subject: [PATCH] feat: add amneziawg support (#2102) * feat: detect wireguard executable * feat: add amneziawg-tools to container * feat: enhance AWG detection and configuration handling * refactor: change env name * refactor: change env values --- Dockerfile | 13 +++++++++++++ src/nuxt.config.ts | 2 +- src/server/utils/config.ts | 10 ++++++++++ src/server/utils/wgHelper.ts | 34 +++++++++++++++++++++++++--------- 4 files changed, 49 insertions(+), 10 deletions(-) diff --git a/Dockerfile b/Dockerfile index 236cb4eb..d5bba623 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,6 +14,12 @@ RUN pnpm install COPY src ./ RUN pnpm build +# Build amneziawg-tools +RUN apk add linux-headers build-base git && \ + git clone https://github.com/amnezia-vpn/amneziawg-tools.git && \ + cd amneziawg-tools/src && \ + make + # Copy build result to a new image. # This saves a lot of disk space. FROM docker.io/library/node:lts-alpine @@ -32,6 +38,10 @@ RUN cd /app/server && \ # cli COPY --from=build /app/cli/cli.sh /usr/local/bin/cli RUN chmod +x /usr/local/bin/cli +# Copy amneziawg-tools +COPY --from=build /app/amneziawg-tools/src/wg /usr/bin/awg +COPY --from=build /app/amneziawg-tools/src/wg-quick/linux.bash /usr/bin/awg-quick +RUN chmod +x /usr/bin/awg /usr/bin/awg-quick # Install Linux packages RUN apk add --no-cache \ @@ -44,6 +54,9 @@ RUN apk add --no-cache \ iptables-legacy \ wireguard-tools +RUN mkdir -p /etc/amnezia +RUN ln -s /etc/wireguard /etc/amnezia/amneziawg + # Use iptables-legacy RUN update-alternatives --install /usr/sbin/iptables iptables /usr/sbin/iptables-legacy 10 --slave /usr/sbin/iptables-restore iptables-restore /usr/sbin/iptables-legacy-restore --slave /usr/sbin/iptables-save iptables-save /usr/sbin/iptables-legacy-save RUN update-alternatives --install /usr/sbin/ip6tables ip6tables /usr/sbin/ip6tables-legacy 10 --slave /usr/sbin/ip6tables-restore ip6tables-restore /usr/sbin/ip6tables-legacy-restore --slave /usr/sbin/ip6tables-save ip6tables-save /usr/sbin/ip6tables-legacy-save diff --git a/src/nuxt.config.ts b/src/nuxt.config.ts index f106eb53..b63e1c18 100644 --- a/src/nuxt.config.ts +++ b/src/nuxt.config.ts @@ -95,7 +95,7 @@ export default defineNuxtConfig({ esbuild: { options: { // to support big int - target: 'es2020', + target: 'node20', }, }, alias: { diff --git a/src/server/utils/config.ts b/src/server/utils/config.ts index 886c0a28..9bfbca9e 100644 --- a/src/server/utils/config.ts +++ b/src/server/utils/config.ts @@ -12,6 +12,8 @@ export const OLD_ENV = { PASSWORD_HASH: process.env.PASSWORD_HASH, }; +const OVERRIDE_AUTO_AWG = process.env.OVERRIDE_AUTO_AWG?.toLowerCase(); + export const WG_ENV = { /** UI is hosted on HTTP instead of HTTPS */ INSECURE: process.env.INSECURE === 'true', @@ -19,6 +21,14 @@ export const WG_ENV = { PORT: assertEnv('PORT'), /** If IPv6 should be disabled */ DISABLE_IPV6: process.env.DISABLE_IPV6 === 'true', + /** Override automatic detection */ + OVERRIDE_AUTO_AWG: + OVERRIDE_AUTO_AWG === ('wg' as const) || + OVERRIDE_AUTO_AWG === ('awg' as const) + ? OVERRIDE_AUTO_AWG + : undefined, + /** TODO: delete on next major version */ + EXPERIMENTAL_AWG: process.env.EXPERIMENTAL_AWG === 'true', }; export const WG_INITIAL_ENV = { diff --git a/src/server/utils/wgHelper.ts b/src/server/utils/wgHelper.ts index 51fa0ce2..e424fcc0 100644 --- a/src/server/utils/wgHelper.ts +++ b/src/server/utils/wgHelper.ts @@ -9,6 +9,18 @@ type Options = { enableIpv6?: boolean; }; +let wgExecutable: 'awg' | 'wg' = 'wg'; + +if (WG_ENV.EXPERIMENTAL_AWG) { + if (WG_ENV.OVERRIDE_AUTO_AWG !== undefined) { + wgExecutable = WG_ENV.OVERRIDE_AUTO_AWG; + } else { + wgExecutable = await exec('modinfo amneziawg') + .then(() => 'awg' as const) + .catch(() => 'wg' as const); + } +} + export const wg = { generateServerPeer: ( client: Omit, @@ -107,37 +119,41 @@ Endpoint = ${userConfig.host}:${userConfig.port}`; }, generatePrivateKey: () => { - return exec('wg genkey'); + return exec(`${wgExecutable} genkey`); }, getPublicKey: (privateKey: string) => { - return exec(`echo ${privateKey} | wg pubkey`, { - log: 'echo ***hidden*** | wg pubkey', + return exec(`echo ${privateKey} | ${wgExecutable} pubkey`, { + log: `echo ***hidden*** | ${wgExecutable} pubkey`, }); }, generatePreSharedKey: () => { - return exec('wg genpsk'); + return exec(`${wgExecutable} genpsk`); }, up: (infName: string) => { - return exec(`wg-quick up ${infName}`); + return exec(`${wgExecutable}-quick up ${infName}`); }, down: (infName: string) => { - return exec(`wg-quick down ${infName}`); + return exec(`${wgExecutable}-quick down ${infName}`); }, restart: (infName: string) => { - return exec(`wg-quick down ${infName}; wg-quick up ${infName}`); + return exec( + `${wgExecutable}-quick down ${infName}; ${wgExecutable}-quick up ${infName}` + ); }, sync: (infName: string) => { - return exec(`wg syncconf ${infName} <(wg-quick strip ${infName})`); + return exec( + `${wgExecutable} syncconf ${infName} <(${wgExecutable}-quick strip ${infName})` + ); }, dump: async (infName: string) => { - const rawDump = await exec(`wg show ${infName} dump`, { + const rawDump = await exec(`${wgExecutable} show ${infName} dump`, { log: false, });