bf9cbba535
Backend (server-core): - Extend firewall NetManager with AddForwardRule, AddInputRule via nft CLI - Sync FORWARD rules on peer create, update, delete, suspend/unsuspend - Sync INPUT rules on server create, update (port change), delete - Fix duplicate import and missing firewall cleanup calls Frontend (dashboard-ui): - Add Edit Node modal for MTU, DNS, ListenPort configuration - Add Advanced Peer Settings accordion (AllowedIPs, DNS, MTU, Keepalive, Notes) - Add Suspend/Unsuspend toggle with SUSPENDED badge - Update API client for new endpoints and fields
8.0 KiB
8.0 KiB
Plan: WGDashboard Config Parity (Phase 5.5)
1. Goal
Achieve feature parity with WGDashboard for WireGuard configuration editing and peer settings, adapting WGDashboard's local-file management approach to NexusGuard's multi-node database-driven SD-WAN architecture.
2. Current Status (May 22, 2026)
✅ COMPLETED
Phase 1: Database Model Updates (Backend)
- Update
WgServerModel: Added MTU (default 1420), DNS (default "1.1.1.1"). - Update
DeviceModel: Added EndpointAllowedIPs, DNS, MTU, PersistentKeepalive (default 25), Notes, IsSuspended, RxBytes, TxBytes. - Database Migration: Auto-migrate via GORM AutoMigrate.
Phase 2: API Updates (Backend)
- Server API (
servers.go):PUT /api/v1/servers/:id— pointer fields for partial updates, firewall sync on port change. - Device API (
devices.go):PUT /api/v1/devices/:id— pointer fields for EndpointAllowedIPs, DNS, MTU, PersistentKeepalive, Notes. - Config Generation (
peers.go):getDeviceConfig— DNS override (device > server > "1.1.1.1"), MTU override, PersistentKeepalive, EndpointAllowedIPs. - Peer Suspension API:
POST /api/v1/devices/:id/suspendand/unsuspendwithIsSuspendedtoggle + firewall rule add/remove.
Phase 3: Firewall Enforcement Sync (nftables) — MOSTLY DONE
- Firewall Manager Interface: Extended with
AddForwardRule,RemoveForwardRule,AddInputRule,RemoveInputRule. - Linux Implementation:
nftables_linux.govianftCLI (AddForwardRule, RemoveForwardRule, AddInputRule, RemoveInputRule). - Stub Implementation:
nftables_stub.gofor non-Linux builds. - Server Create:
AddInputRule(server.Name, server.ListenPort)inservers.go. - Server Update: Firewall re-sync when ListenPort changes in
servers.go. - Server Delete:
RemoveInputRule(server.Name)inservers.go. - Peer Suspend:
RemoveForwardRule/AddForwardRuleindevices.gotoggleSuspension. - Device Delete (partial):
RemoveRangeRulecalled but missingRemoveForwardRule.
❌ REMAINING (to be completed now)
Phase 3: Backend Firewall Fixes
- Fix duplicate
"net"import indevices.go(lines 4-5, two imports of same package). - Add
AddForwardRuleinpeers.goCreatePeer — after device creation, add FORWARD rule for device AllowedIPs. - Add firewall sync in
devices.goUpdate — when EndpointAllowedIPs or AllowInternet changes, re-sync FORWARD rule. - Add
RemoveForwardRuleindevices.goDelete — clean up FORWARD rule when device is deleted.
Phase 4: Dashboard UI (Frontend)
- Node Edit Modal in
Servers.vue— Edit Node button + modal to configure MTU, DNS, ListenPort viaPUT /api/v1/servers/:id. - Advanced Peer Settings in
DeviceDetail.vue— Accordion section with fields for AllowedIPs, DNS, MTU, Keepalive, Notes, Suspend toggle, using new API fields. - Update API client (
servers.ts,devices.ts) — AddupdateServer(),suspendDevice(),unsuspendDevice()and extendupdateDevice()with new fields.
3. Implementation Tasks
Task A: Backend Fixes (4 edits across 2 files)
A.1 devices.go — Duplicate import
- Remove second
"net"import on line 5. - File:
apps/server-core/api/devices.go - Verify:
go build ./...passes.
A.2 peers.go — Add ForwardRule on CreatePeer
- After line ~131 (configText generation), add:
// Sync firewall FORWARD rule for this peer h.fw.AddForwardRule(device.Name, ip, allowedIPs) - Also handle case where EndpointAllowedIPs is empty — derive from AllowInternet.
- File:
apps/server-core/api/peers.go
A.3 devices.go — Firewall sync on Update
- In
Update()handler, after device is updated, re-sync FORWARD rule if:EndpointAllowedIPschanged (req.EndpointAllowedIPs != nil)AllowInternetchanged (req.AllowInternet != nil)
- Calculate destCIDR from device's EndpointAllowedIPs > AllowInternet > InternalIP
- Call
h.fw.RemoveForwardRule(device.Name)thenh.fw.AddForwardRule(...)with new CIDR.
A.4 devices.go — ForwardRule cleanup on Delete
- In
Delete()handler, addh.fw.RemoveForwardRule(device.Name)before or after the existingh.db.Delete(&device). - File:
apps/server-core/api/devices.go
Task B: Frontend API Client Updates
B.1 servers.ts — Add updateServer()
export const updateServer = async (id: string, data: {
name?: string;
public_endpoint?: string;
listen_address?: string;
listen_port?: number;
mtu?: number;
dns?: string;
}) => {
await api.put(`/servers/${id}`, data)
}
B.2 devices.ts — Extend updateDevice() + add suspend/unsuspend
export const updateDevice = async (id: string, data: {
name?: string;
allow_internet?: boolean;
endpoint_allowed_ips?: string;
dns?: string;
mtu?: number;
persistent_keepalive?: number;
notes?: string;
}) => {
await api.put(`/devices/${id}`, data)
}
export const suspendDevice = async (id: string) => {
const { data } = await api.post(`/devices/${id}/suspend`)
return data
}
export const unsuspendDevice = async (id: string) => {
const { data } = await api.post(`/devices/${id}/unsuspend`)
return data
}
B.3 Device interface — Add new fields
export interface Device {
// ... existing fields ...
EndpointAllowedIPs?: string
DNS?: string
MTU?: number
PersistentKeepalive?: number
Notes?: string
IsSuspended?: boolean
}
Task C: Frontend UI Components
C.1 Servers.vue — Edit Node Modal
Add to the template:
- An "Edit" button next to "Delete" in each server row
- A modal dialog (glassmorphism style matching current design) with fields:
- ListenPort (number input)
- MTU (number input)
- DNS (text input)
- Form submits to
updateServer(id, payload)API - Modal uses
v-model="showEditModal"to open/close - Refresh list after update
Implementation approach:
- Add
editingServerref to track which server is being edited - Add modal template with glassmorphism card (bg-gray-900/90 rounded-2xl border border-white/10 shadow-lg backdrop-blur-xl)
- Pre-populate form with current server values
- On submit: call API, close modal, reload list
C.2 DeviceDetail.vue — Advanced Peer Settings
Add after the AllowInternet toggle section:
- A collapsible "Advanced Settings" accordion
- Inside: form fields for:
- AllowedIPs (text input - comma-separated CIDRs)
- DNS (text input)
- MTU (number input)
- PersistentKeepalive (number input)
- Notes (textarea)
- Suspend (toggle switch with API call)
- "Save" button calls
updateDevice()with all fields - Suspend toggle calls
suspendDevice()/unsuspendDevice()separately - Show "Suspended" badge when device is suspended
4. Execution Strategy
Wave 1 (parallel — backend fixes + frontend API):
├── Task A: Backend fixes (devices.go, peers.go)
├── Task B: Frontend API client updates (servers.ts, devices.ts, peers.ts)
Wave 2 (parallel — frontend UI):
├── Task C.1: Servers.vue Edit Node modal
├── Task C.2: DeviceDetail.vue Advanced Peer Settings accordion
Wave 3 (final — verification):
├── Verify go build ./... passes
├── Verify npm build passes (or at least no TS errors)
├── Update plan file with final status
├── Commit all changes
5. Verification Strategy
Backend Verification
cd apps/server-core
go build ./... # Expected: PASS (no errors)
go vet ./... # Expected: PASS (no warnings)
Frontend Verification
cd apps/dashboard-ui
npx vue-tsc --noEmit # Expected: PASS (no type errors)
npm run build # Expected: PASS (build succeeds)
Manual QA (after deploy to wglab)
- Add Node → Edit Node (change MTU, DNS, ListenPort) → Verify
- Create Peer → Edit Advanced Settings (AllowedIPs, DNS, MTU, Keepalive, Notes) → Verify
- Toggle Suspend → Verify peer status changes → Verify firewall rules update
- Verify nftables rules:
nft list chain ip nexusguard forward,nft list chain ip nexusguard input