Interface Control
Control WireGuard interfaces with up and down functions for starting and stopping VPN connections.
Overview
The interface control functions allow you to programmatically start and stop WireGuard interfaces. These functions are essential for managing VPN connections and are typically used after configuration changes.
Functions
up(iface: string)
Starts a WireGuard interface using wg-quick up.
iface(string): Interface name (e.g., "wg0", "wg1")
Returns: Promise<void>
down(iface: string)
Stops a WireGuard interface using wg-quick down.
iface(string): Interface name (e.g., "wg0", "wg1")
Returns: Promise<void>
Basic Usage
Starting an Interface
import { up } from "@kriper0nind/wg-utils"
// Start the wg0 interface
await up("wg0")
console.log("WireGuard interface started")Stopping an Interface
import { down } from "@kriper0nind/wg-utils"
// Stop the wg0 interface
await down("wg0")
console.log("WireGuard interface stopped")Complete Interface Management
import { up, down } from "@kriper0nind/wg-utils"
async function manageInterface(iface: string, action: "start" | "stop") {
try {
if (action === "start") {
await up(iface)
console.log(`${iface} started successfully`)
} else {
await down(iface)
console.log(`${iface} stopped successfully`)
}
} catch (error) {
console.error(`Failed to ${action} ${iface}:`, error.message)
throw error
}
}
// Usage
await manageInterface("wg0", "start")
await manageInterface("wg0", "stop")Advanced Usage
Interface Status Checking
import { exec } from "child_process"
import { promisify } from "util"
const execAsync = promisify(exec)
async function isInterfaceUp(iface: string): Promise<boolean> {
try {
const { stdout } = await execAsync(`wg show ${iface}`)
return stdout.trim().length > 0
} catch {
return false
}
}
async function safeUp(iface: string) {
const isUp = await isInterfaceUp(iface)
if (isUp) {
console.log(`${iface} is already running`)
return
}
await up(iface)
console.log(`${iface} started`)
}Multiple Interface Management
class InterfaceManager {
private interfaces: string[] = []
async startInterface(iface: string) {
try {
await up(iface)
this.interfaces.push(iface)
console.log(`${iface} started`)
} catch (error) {
console.error(`Failed to start ${iface}:`, error.message)
throw error
}
}
async stopInterface(iface: string) {
try {
await down(iface)
this.interfaces = this.interfaces.filter(i => i !== iface)
console.log(`${iface} stopped`)
} catch (error) {
console.error(`Failed to stop ${iface}:`, error.message)
throw error
}
}
async stopAll() {
for (const iface of [...this.interfaces]) {
await this.stopInterface(iface)
}
}
getActiveInterfaces() {
return [...this.interfaces]
}
}
// Usage
const manager = new InterfaceManager()
await manager.startInterface("wg0")
await manager.startInterface("wg1")
console.log("Active interfaces:", manager.getActiveInterfaces())
// Stop all interfaces
await manager.stopAll()Interface Restart
async function restartInterface(iface: string) {
try {
// Stop the interface
await down(iface)
console.log(`${iface} stopped`)
// Wait a moment
await new Promise(resolve => setTimeout(resolve, 1000))
// Start the interface
await up(iface)
console.log(`${iface} restarted`)
} catch (error) {
console.error(`Failed to restart ${iface}:`, error.message)
throw error
}
}Error Handling
Common Error Scenarios
import { up, down } from "@kriper0nind/wg-utils"
async function safeInterfaceControl(iface: string, action: "up" | "down") {
try {
if (action === "up") {
await up(iface)
} else {
await down(iface)
}
} catch (error) {
if (error.message.includes('Permission denied')) {
console.error("Permission denied - run with sudo")
} else if (error.message.includes('No such device')) {
console.error(`Interface ${iface} does not exist`)
} else if (error.message.includes('already exists')) {
console.error(`Interface ${iface} is already running`)
} else if (error.message.includes('not found')) {
console.error(`Configuration file for ${iface} not found`)
} else {
console.error(`Interface control failed:`, error.message)
}
throw error
}
}Retry Logic
async function upWithRetry(iface: string, maxRetries: number = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
await up(iface)
console.log(`${iface} started successfully`)
return
} catch (error) {
console.warn(`Attempt ${attempt} failed:`, error.message)
if (attempt === maxRetries) {
throw new Error(`Failed to start ${iface} after ${maxRetries} attempts`)
}
// Wait before retry
await new Promise(resolve => setTimeout(resolve, 1000 * attempt))
}
}
}Complete VPN Management
import {
up,
down,
initConf,
addPeer,
generateKeys
} from "@kriper0nind/wg-utils"
class VPNManager {
constructor(private iface: string = "wg0") {}
async setup() {
// Generate server keys
const serverKeys = await generateKeys()
// Create server configuration
await initConf(`/etc/wireguard/${this.iface}.conf`, {
privateKey: serverKeys.privateKey,
port: 51820,
ip: "10.0.0.1"
})
console.log("VPN server configured")
return serverKeys
}
async start() {
await up(this.iface)
console.log(`VPN server ${this.iface} started`)
}
async stop() {
await down(this.iface)
console.log(`VPN server ${this.iface} stopped`)
}
async restart() {
await this.stop()
await new Promise(resolve => setTimeout(resolve, 1000))
await this.start()
}
async addClient() {
const clientKeys = await generateKeys()
const result = await addPeer(`/etc/wireguard/${this.iface}.conf`, {
publicKey: clientKeys.publicKey
})
// Restart to apply changes
await this.restart()
return {
privateKey: clientKeys.privateKey,
publicKey: clientKeys.publicKey,
ip: result.ip
}
}
}
// Usage
const vpn = new VPNManager("wg0")
// Setup and start VPN
await vpn.setup()
await vpn.start()
// Add a client
const client = await vpn.addClient()
console.log("Client added:", client.ip)
// Stop VPN
await vpn.stop()System Integration
Service Management
import { exec } from "child_process"
import { promisify } from "util"
const execAsync = promisify(exec)
async function enableSystemdService(iface: string) {
try {
await execAsync(`systemctl enable wg-quick@${iface}`)
console.log(`Systemd service enabled for ${iface}`)
} catch (error) {
console.error("Failed to enable systemd service:", error.message)
}
}
async function startSystemdService(iface: string) {
try {
await execAsync(`systemctl start wg-quick@${iface}`)
console.log(`Systemd service started for ${iface}`)
} catch (error) {
console.error("Failed to start systemd service:", error.message)
}
}Health Monitoring
async function monitorInterface(iface: string, intervalMs: number = 30000) {
const checkStatus = async () => {
try {
const { stdout } = await execAsync(`wg show ${iface}`)
const isUp = stdout.trim().length > 0
if (isUp) {
console.log(`${iface} is healthy`)
} else {
console.warn(`${iface} appears to be down`)
// Optionally restart
// await up(iface)
}
} catch (error) {
console.error(`Health check failed for ${iface}:`, error.message)
}
}
// Initial check
await checkStatus()
// Set up interval
const interval = setInterval(checkStatus, intervalMs)
// Return cleanup function
return () => clearInterval(interval)
}
// Usage
const cleanup = await monitorInterface("wg0", 30000)
// Stop monitoring after 5 minutes
setTimeout(cleanup, 5 * 60 * 1000)Examples
Development Workflow
async function devWorkflow() {
const iface = "wg-dev"
try {
// Start development VPN
await up(iface)
console.log("Development VPN started")
// Do development work...
console.log("Working with VPN...")
} finally {
// Always clean up
try {
await down(iface)
console.log("Development VPN stopped")
} catch (error) {
console.warn("Failed to stop development VPN:", error.message)
}
}
}Production Deployment
async function deployVPN() {
const iface = "wg0"
try {
// Stop existing interface
await down(iface)
console.log("Stopped existing interface")
} catch (error) {
console.log("No existing interface to stop")
}
// Apply new configuration
// ... configuration updates ...
// Start with new configuration
await up(iface)
console.log("VPN deployed successfully")
}Dependencies
wg-quick: WireGuard's interface management tool- System privileges: Root/sudo access required
- Configuration files: Must exist in
/etc/wireguard/
Notes
- Interface names should match configuration file names (e.g., "wg0" for "/etc/wireguard/wg0.conf")
- The
upfunction applies all PostUp commands from the configuration - The
downfunction applies all PostDown commands for cleanup - Interfaces must be stopped before making configuration changes
- Always handle errors gracefully in production environments