From e444936c04643c7a76c7c35d430ca3db5fabb194 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 14 Nov 2025 13:01:39 +0000 Subject: [PATCH] Add environment variables to override admin panel interface settings Co-authored-by: kaaax0815 <32197462+kaaax0815@users.noreply.github.com> --- .../advanced/config/optional-config.md | 22 ++++++++++++ src/server/api/admin/interface/index.get.ts | 3 +- src/server/api/admin/interface/index.post.ts | 15 +++++++- src/server/utils/WireGuard.ts | 35 ++++++++++++------- src/server/utils/config.ts | 27 ++++++++++++++ 5 files changed, 87 insertions(+), 15 deletions(-) diff --git a/docs/content/advanced/config/optional-config.md b/docs/content/advanced/config/optional-config.md index c58f5636..e2a20da8 100644 --- a/docs/content/advanced/config/optional-config.md +++ b/docs/content/advanced/config/optional-config.md @@ -20,3 +20,25 @@ You will however still see a IPv6 address in the Web UI, but it won't be used. This option can be removed in the future, as more devices support IPv6. /// + +## Configuration Overrides + +These environment variables allow you to override settings that would normally be configured through the Admin Panel. When set, these values take precedence over database settings and cannot be changed through the Web UI. + +| Env | Example | Description | +| ---------------------------- | ------- | ----------------------------------------------------- | +| `OVERRIDE_INTERFACE_PORT` | `51820` | Override the WireGuard interface listening port | +| `OVERRIDE_INTERFACE_DEVICE` | `eth1` | Override the network device/interface | +| `OVERRIDE_INTERFACE_MTU` | `1420` | Override the MTU (Maximum Transmission Unit) setting | + +/// warning | Override Behavior + +When these override environment variables are set: +- The specified values will be used instead of database settings +- Changes made through the Web UI to these fields will not take effect +- The Web UI will still display the overridden values +- Updates to these fields via the API will be ignored + +These overrides are useful for containerized environments where configuration should be controlled externally. + +/// diff --git a/src/server/api/admin/interface/index.get.ts b/src/server/api/admin/interface/index.get.ts index 7161aecc..d0ddceff 100644 --- a/src/server/api/admin/interface/index.get.ts +++ b/src/server/api/admin/interface/index.get.ts @@ -1,8 +1,9 @@ export default definePermissionEventHandler('admin', 'any', async () => { const wgInterface = await Database.interfaces.get(); + const wgInterfaceWithOverrides = applyInterfaceOverrides(wgInterface); return { - ...wgInterface, + ...wgInterfaceWithOverrides, privateKey: undefined, }; }); diff --git a/src/server/api/admin/interface/index.post.ts b/src/server/api/admin/interface/index.post.ts index d6beedbe..ba5bda29 100644 --- a/src/server/api/admin/interface/index.post.ts +++ b/src/server/api/admin/interface/index.post.ts @@ -8,7 +8,20 @@ export default definePermissionEventHandler( event, validateZod(InterfaceUpdateSchema, event) ); - await Database.interfaces.update(data); + + // Remove overridden fields from the update data + const updateData = { ...data }; + if (WG_OVERRIDE_ENV.INTERFACE_PORT !== undefined) { + delete updateData.port; + } + if (WG_OVERRIDE_ENV.INTERFACE_DEVICE !== undefined) { + delete updateData.device; + } + if (WG_OVERRIDE_ENV.INTERFACE_MTU !== undefined) { + delete updateData.mtu; + } + + await Database.interfaces.update(updateData); await WireGuard.saveConfig(); return { success: true }; } diff --git a/src/server/utils/WireGuard.ts b/src/server/utils/WireGuard.ts index 2da26fce..61101249 100644 --- a/src/server/utils/WireGuard.ts +++ b/src/server/utils/WireGuard.ts @@ -14,8 +14,9 @@ class WireGuard { */ async saveConfig() { const wgInterface = await Database.interfaces.get(); - await this.#saveWireguardConfig(wgInterface); - await this.#syncWireguardConfig(wgInterface); + const wgInterfaceWithOverrides = applyInterfaceOverrides(wgInterface); + await this.#saveWireguardConfig(wgInterfaceWithOverrides); + await this.#syncWireguardConfig(wgInterfaceWithOverrides); } /** @@ -151,6 +152,7 @@ class WireGuard { async getClientConfiguration({ clientId }: { clientId: ID }) { const wgInterface = await Database.interfaces.get(); + const wgInterfaceWithOverrides = applyInterfaceOverrides(wgInterface); const userConfig = await Database.userConfigs.get(); const client = await Database.clients.get(clientId); @@ -159,9 +161,14 @@ class WireGuard { throw new Error('Client not found'); } - return wg.generateClientConfig(wgInterface, userConfig, client, { - enableIpv6: !WG_ENV.DISABLE_IPV6, - }); + return wg.generateClientConfig( + wgInterfaceWithOverrides, + userConfig, + client, + { + enableIpv6: !WG_ENV.DISABLE_IPV6, + } + ); } async getClientQRCodeSVG({ clientId }: { clientId: ID }) { @@ -217,25 +224,27 @@ class WireGuard { Database.interfaces.update(wgInterface); } - WG_DEBUG(`Starting Wireguard Interface ${wgInterface.name}...`); - await this.#saveWireguardConfig(wgInterface); - await wg.down(wgInterface.name).catch(() => {}); - await wg.up(wgInterface.name).catch((err) => { + const wgInterfaceWithOverrides = applyInterfaceOverrides(wgInterface); + + WG_DEBUG(`Starting Wireguard Interface ${wgInterfaceWithOverrides.name}...`); + await this.#saveWireguardConfig(wgInterfaceWithOverrides); + await wg.down(wgInterfaceWithOverrides.name).catch(() => {}); + await wg.up(wgInterfaceWithOverrides.name).catch((err) => { if ( err && err.message && - err.message.includes(`Cannot find device "${wgInterface.name}"`) + err.message.includes(`Cannot find device "${wgInterfaceWithOverrides.name}"`) ) { throw new Error( - `WireGuard exited with the error: Cannot find device "${wgInterface.name}"\nThis usually means that your host's kernel does not support WireGuard!`, + `WireGuard exited with the error: Cannot find device "${wgInterfaceWithOverrides.name}"\nThis usually means that your host's kernel does not support WireGuard!`, { cause: err.message } ); } throw err; }); - await this.#syncWireguardConfig(wgInterface); - WG_DEBUG(`Wireguard Interface ${wgInterface.name} started successfully.`); + await this.#syncWireguardConfig(wgInterfaceWithOverrides); + WG_DEBUG(`Wireguard Interface ${wgInterfaceWithOverrides.name} started successfully.`); WG_DEBUG('Starting Cron Job...'); await this.startCronJob(); diff --git a/src/server/utils/config.ts b/src/server/utils/config.ts index 322b7ae6..e6d63079 100644 --- a/src/server/utils/config.ts +++ b/src/server/utils/config.ts @@ -54,6 +54,19 @@ export const WG_INITIAL_ENV = { : undefined, }; +export const WG_OVERRIDE_ENV = { + /** Override the WireGuard interface port */ + INTERFACE_PORT: process.env.OVERRIDE_INTERFACE_PORT + ? Number.parseInt(process.env.OVERRIDE_INTERFACE_PORT, 10) + : undefined, + /** Override the network device/interface */ + INTERFACE_DEVICE: process.env.OVERRIDE_INTERFACE_DEVICE, + /** Override the MTU setting */ + INTERFACE_MTU: process.env.OVERRIDE_INTERFACE_MTU + ? Number.parseInt(process.env.OVERRIDE_INTERFACE_MTU, 10) + : undefined, +}; + function assertEnv(env: T) { const val = process.env[env]; @@ -63,3 +76,17 @@ function assertEnv(env: T) { return val; } + +/** + * Apply environment variable overrides to an interface object + */ +export function applyInterfaceOverrides< + T extends { port: number; device: string; mtu: number }, +>(wgInterface: T): T { + return { + ...wgInterface, + port: WG_OVERRIDE_ENV.INTERFACE_PORT ?? wgInterface.port, + device: WG_OVERRIDE_ENV.INTERFACE_DEVICE ?? wgInterface.device, + mtu: WG_OVERRIDE_ENV.INTERFACE_MTU ?? wgInterface.mtu, + }; +}