<# .SYNOPSIS Install WireGuard and bring up the FlatRender mesh tunnel as a persistent service. .DESCRIPTION - Verifies WireGuard is installed (downloads the MSI if missing and -Download is set). - Installs the given .conf as a permanent WireGuard tunnel service (survives reboot). - The tunnel auto-connects on boot, BEFORE the node-agent service starts, so the agent can always reach the gateway over 10.66.0.0/24. Run ELEVATED (Administrator). .PARAMETER ConfigPath Path to the filled-in WireGuard config (from wireguard-node.conf.template). Default: wg-flatrender.conf beside this script. .PARAMETER Download If set and WireGuard is not installed, download + silently install the MSI. .EXAMPLE .\setup-wireguard.ps1 -ConfigPath .\wg-flatrender.conf #> param( [string]$ConfigPath = (Join-Path $PSScriptRoot "wg-flatrender.conf"), [switch]$Download ) $ErrorActionPreference = "Stop" $principal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Write-Error "This script must be run as Administrator." exit 1 } # ── Ensure WireGuard is installed ───────────────────────────────────────────── $wg = "C:\Program Files\WireGuard\wireguard.exe" if (-not (Test-Path $wg)) { if ($Download) { Write-Host "WireGuard not found — downloading installer..." $msi = Join-Path $env:TEMP "wireguard.msi" Invoke-WebRequest -Uri "https://download.wireguard.com/windows-client/wireguard-installer.exe" -OutFile $msi Write-Host "Installing WireGuard silently..." Start-Process -FilePath $msi -ArgumentList "/S" -Wait } else { Write-Error "WireGuard is not installed. Install it from https://www.wireguard.com/install/ or re-run with -Download." exit 1 } } # ── Validate config ─────────────────────────────────────────────────────────── if (-not (Test-Path $ConfigPath)) { Write-Error "Config not found: $ConfigPath`nCopy wireguard-node.conf.template, fill the placeholders, save as wg-flatrender.conf." exit 1 } $ConfigPath = (Resolve-Path $ConfigPath).Path if ((Get-Content $ConfigPath -Raw) -match '<[A-Z_]+>') { Write-Error "Config still contains . Fill in all four values before installing." exit 1 } $tunnelName = [System.IO.Path]::GetFileNameWithoutExtension($ConfigPath) # ── Remove existing tunnel of the same name ─────────────────────────────────── $svcName = "WireGuardTunnel`$$tunnelName" if (Get-Service -Name $svcName -ErrorAction SilentlyContinue) { Write-Host "Removing existing tunnel '$tunnelName'..." & $wg /uninstalltunnelservice $tunnelName | Out-Null Start-Sleep -Seconds 2 } # ── Install the tunnel as a service ─────────────────────────────────────────── Write-Host "Installing WireGuard tunnel '$tunnelName' as a boot service..." & $wg /installtunnelservice $ConfigPath Start-Sleep -Seconds 3 $svc = Get-Service -Name $svcName -ErrorAction SilentlyContinue if ($svc -and $svc.Status -eq 'Running') { Write-Host "" Write-Host "✓ WireGuard tunnel '$tunnelName' is up." -ForegroundColor Green Write-Host " Verify : & '$wg' show" Write-Host " Ping CP: ping 10.66.0.1" Write-Host "" Write-Host " Next : install the node agent service (install-service.ps1) and point" Write-Host " ORCHESTRATOR_URL in agent.env at the control plane's mesh IP." } else { Write-Warning "Tunnel service did not reach Running state. Check: & '$wg' show" }