Add environment variables to override admin panel interface settings

Co-authored-by: kaaax0815 <32197462+kaaax0815@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-11-14 13:01:39 +00:00
parent 5d6c35b183
commit e444936c04
5 changed files with 87 additions and 15 deletions
@@ -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. 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.
///
+2 -1
View File
@@ -1,8 +1,9 @@
export default definePermissionEventHandler('admin', 'any', async () => { export default definePermissionEventHandler('admin', 'any', async () => {
const wgInterface = await Database.interfaces.get(); const wgInterface = await Database.interfaces.get();
const wgInterfaceWithOverrides = applyInterfaceOverrides(wgInterface);
return { return {
...wgInterface, ...wgInterfaceWithOverrides,
privateKey: undefined, privateKey: undefined,
}; };
}); });
+14 -1
View File
@@ -8,7 +8,20 @@ export default definePermissionEventHandler(
event, event,
validateZod(InterfaceUpdateSchema, 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(); await WireGuard.saveConfig();
return { success: true }; return { success: true };
} }
+22 -13
View File
@@ -14,8 +14,9 @@ class WireGuard {
*/ */
async saveConfig() { async saveConfig() {
const wgInterface = await Database.interfaces.get(); const wgInterface = await Database.interfaces.get();
await this.#saveWireguardConfig(wgInterface); const wgInterfaceWithOverrides = applyInterfaceOverrides(wgInterface);
await this.#syncWireguardConfig(wgInterface); await this.#saveWireguardConfig(wgInterfaceWithOverrides);
await this.#syncWireguardConfig(wgInterfaceWithOverrides);
} }
/** /**
@@ -151,6 +152,7 @@ class WireGuard {
async getClientConfiguration({ clientId }: { clientId: ID }) { async getClientConfiguration({ clientId }: { clientId: ID }) {
const wgInterface = await Database.interfaces.get(); const wgInterface = await Database.interfaces.get();
const wgInterfaceWithOverrides = applyInterfaceOverrides(wgInterface);
const userConfig = await Database.userConfigs.get(); const userConfig = await Database.userConfigs.get();
const client = await Database.clients.get(clientId); const client = await Database.clients.get(clientId);
@@ -159,9 +161,14 @@ class WireGuard {
throw new Error('Client not found'); throw new Error('Client not found');
} }
return wg.generateClientConfig(wgInterface, userConfig, client, { return wg.generateClientConfig(
enableIpv6: !WG_ENV.DISABLE_IPV6, wgInterfaceWithOverrides,
}); userConfig,
client,
{
enableIpv6: !WG_ENV.DISABLE_IPV6,
}
);
} }
async getClientQRCodeSVG({ clientId }: { clientId: ID }) { async getClientQRCodeSVG({ clientId }: { clientId: ID }) {
@@ -217,25 +224,27 @@ class WireGuard {
Database.interfaces.update(wgInterface); Database.interfaces.update(wgInterface);
} }
WG_DEBUG(`Starting Wireguard Interface ${wgInterface.name}...`); const wgInterfaceWithOverrides = applyInterfaceOverrides(wgInterface);
await this.#saveWireguardConfig(wgInterface);
await wg.down(wgInterface.name).catch(() => {}); WG_DEBUG(`Starting Wireguard Interface ${wgInterfaceWithOverrides.name}...`);
await wg.up(wgInterface.name).catch((err) => { await this.#saveWireguardConfig(wgInterfaceWithOverrides);
await wg.down(wgInterfaceWithOverrides.name).catch(() => {});
await wg.up(wgInterfaceWithOverrides.name).catch((err) => {
if ( if (
err && err &&
err.message && err.message &&
err.message.includes(`Cannot find device "${wgInterface.name}"`) err.message.includes(`Cannot find device "${wgInterfaceWithOverrides.name}"`)
) { ) {
throw new Error( 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 } { cause: err.message }
); );
} }
throw err; throw err;
}); });
await this.#syncWireguardConfig(wgInterface); await this.#syncWireguardConfig(wgInterfaceWithOverrides);
WG_DEBUG(`Wireguard Interface ${wgInterface.name} started successfully.`); WG_DEBUG(`Wireguard Interface ${wgInterfaceWithOverrides.name} started successfully.`);
WG_DEBUG('Starting Cron Job...'); WG_DEBUG('Starting Cron Job...');
await this.startCronJob(); await this.startCronJob();
+27
View File
@@ -54,6 +54,19 @@ export const WG_INITIAL_ENV = {
: undefined, : 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<T extends string>(env: T) { function assertEnv<T extends string>(env: T) {
const val = process.env[env]; const val = process.env[env];
@@ -63,3 +76,17 @@ function assertEnv<T extends string>(env: T) {
return val; 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,
};
}