# Architecture Overview NexusGuard is a three-component SD-WAN system: a central API server, a web dashboard, and cross-platform device agents. All communication is encrypted. Tunnels are fileless. Access is zero-trust. ## High-Level Architecture ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Dashboard (Vue 3) │ │ Glassmorphism Web Interface │ │ Manages: Nodes, Devices, Rules │ └───────────────────────────────────┬─────────────────────────────────┘ │ HTTP (port 80) ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ Nginx Reverse Proxy │ │ Routes: /api/ → :8080, / → SPA │ └───────────────────────────────────┬─────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ Server Core (Go/Gin) │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ │ │ HTTP API │ │ gRPC │ │ IPAM │ │ nftables │ │ │ │ (20+ │ │ Signaling│ │ Manager │ │ Firewall │ │ │ │ handlers)│ │ (cmux) │ │ │ │ │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────────┬─────────┘ │ │ │ │ │ │ │ │ ▼ ▼ ▼ ▼ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ PostgreSQL Database │ │ │ │ (wg_servers, devices, rules, users) │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────┐ ┌──────────────────────┐ │ │ │ Redis │ │ WireGuard │ │ │ │ (Heartbeat TTL) │ │ (wg0 interface) │ │ │ └──────────────────────┘ └──────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ │ ┌───────────────┴───────────────┐ │ │ ▼ ▼ ┌───────────────────────────┐ ┌───────────────────────────┐ │ Device Agent (Linux) │ │ Device Agent (Win/Mac) │ │ Systemd Daemon │ │ System Tray │ │ Memory-injected WG │ │ Memory-injected WG │ └───────────────────────────┘ └───────────────────────────┘ ``` ## Component Breakdown ### Server Core The central API and VPN hub. Written in Go with Gin framework. | Responsibility | Implementation | |----------------|----------------| | API endpoints | 20+ Gin handlers (`api/` directory) | | gRPC signaling | Bidirectional streaming via cmux (port 8080) | | IPAM | IP pool allocation from CIDR per node | | Firewall | nftables rule management (add/remove per peer) | | WireGuard | Interface control, peer sync, config push | | Auth | JWT middleware, admin-only enforcement | | Heartbeat | Config sync, handshake monitoring | ### Dashboard UI Admin web interface. Built with Vue 3 and glassmorphism design system. | Responsibility | Implementation | |----------------|----------------| | Node management | Register/edit WireGuard servers | | Device management | CRUD, provisioning tokens, QR codes | | Firewall rules | Per-peer nftables rule editor | | Live telemetry | 10s polling for device health | | Traffic history | Time-range filtering, export | ### Device Agent Stealth VPN daemon. Cross-platform Go binary. | Responsibility | Implementation | |----------------|----------------| | Provisioning | HTTP POST with AES-256-GCM encrypted response | | Tunnel | Memory-injected WireGuard (no disk files) | | Heartbeat | HTTP/gRPC, config sync, handshake monitoring | | gRPC | Bidirectional stream for real-time commands | | Self-healing | Exponential backoff reconnection | ## Data Flow ### Provisioning Flow ``` 1. Admin creates device via Dashboard → API generates registration token 2. Agent sends token + HWID to POST /api/v1/provision 3. Server validates token, allocates IP from pool 4. Server responds with WireGuard config (AES-256-GCM encrypted) 5. Agent decrypts config, injects into WireGuard via IpcSet 6. Tunnel established — no files written to disk ``` ### Heartbeat Flow ``` Every 30 seconds: 1. Agent reads last_handshake_time from WireGuard IPC 2. Agent computes config_hash = endpoint + internalIP + serverPub 3. Agent POSTs {config_hash, last_handshake, tunnel_up} to server 4. Server compares with stored config 5. If config changed → server responds with new config 6. Agent detects change → rebuilds tunnel ``` ### Suspend/Resume Flow ``` Suspend: 1. Admin clicks "Suspend" in Dashboard 2. Dashboard POSTs /api/v1/devices/:id/suspend 3. Server updates DB (is_suspended = true) 4. Server sends gRPC SuspendCommand to agent 5. Server removes WireGuard peer from kernel 6. Agent receives command → stops tunnel Resume: 1. Admin clicks "Resume" in Dashboard 2. Server updates DB (is_suspended = false) 3. Server re-adds WireGuard peer to kernel 4. Server sends gRPC ResumeCommand with full ConfigUpdate 5. Agent receives command → rebuilds tunnel ``` ## Security Model ### Zero-Trust Principles | Principle | Implementation | |-----------|----------------| | No public registration | `/auth/register` locked; admin via CLI only | | Encrypted provisioning | AES-256-GCM for WireGuard config transfer | | Fileless tunnels | WireGuard config in process memory only | | Hardware binding | HWID (DMI/CPU serial) bound to registration token | | Per-peer isolation | nftables rules per device, default deny | | JWT authentication | All API endpoints require valid token | ### Trust Boundaries ``` ┌─────────────────────────────────────────────────────────┐ │ Trusted Zone │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────────────────┐ │ │ │ Server │ │ Database │ │ WireGuard Interface │ │ │ │ Core │ │ (PG) │ │ (wg0) │ │ │ └──────────┘ └──────────┘ └──────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────┘ │ Encrypted Channel (AES-256-GCM / WG) │ ┌─────────────────────────────────────────────────────────┐ │ Untrusted Zone │ │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ Device Agent │ │ │ │ (Memory-only WireGuard config) │ │ │ └──────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────┘ ``` ## Port Multiplexing Server Core uses cmux to serve both HTTP and gRPC on port 8080: ```go m := cmux.New(lis) grpcLis := m.MatchWithWriters(cmux.HTTP2MatchHeaderFieldSendSettings( "content-type", "application/grpc", )) httpLis := m.Match(cmux.Any()) ``` - gRPC matched by `content-type: application/grpc` header - HTTP matched by `Any()` (catch-all) - Single port, single listener, zero extra config