# NexaVPN NexaVPN is a production-oriented, self-hosted WireGuard control plane for remote access. It combines: - A Go backend and PostgreSQL control plane - A React admin console - A Tauri desktop client for Windows and macOS - WireGuard gateway and firewall policy enforcement - Docker Compose deployment assets ## Monorepo Layout - `docs/` architecture, schema, API, and deployment design - `backend/` Go API, migrations, seeds, and domain services - `admin-web/` React + Vite admin UI - `desktop-client/` Tauri desktop client - `deploy/` Docker Compose, reverse proxy, and gateway assets ## Phase Status This repository contains the initial production-minded MVP scaffold: - Phase 1: architecture, schema, API, enrollment, provisioning, gateway design - Phase 2: backend scaffold, migrations, auth, CRUD, audit, profile generation - Phase 3: admin UI scaffold and core pages - Phase 4: desktop client scaffold, enrollment flow, profile provisioning abstraction - Phase 5: deployment assets, bootstrap scripts, and hardening notes ## Quick Start 1. Copy `deploy/.env.example` to `deploy/.env`. 2. Review `docs/architecture.md` and `docs/deployment.md`. 3. Start the stack with Docker Compose from `deploy/`. 4. Open `http://localhost`. 5. On the admin login screen, choose the bootstrap flow if this is a fresh install. 6. Create the initial admin, then sign in. ## Important MVP Notes - WireGuard remains the tunnel transport. NexaVPN is the control plane around it. - Client private keys are generated on-device and are not stored server-side. - Gateway-side enforcement uses nftables generated from issued policy state. - The desktop client is structured so NexaVPN is the only user-facing VPN app. - The tunnel layer still uses WireGuard internally, but the intended delivery model is a NexaVPN-bundled tunnel backend, not a separately used WireGuard app. ## Desktop Requirements - Windows x64: package NexaVPN with the bundled Windows x64 tunnel helper - macOS ARM: package NexaVPN with the bundled macOS ARM tunnel helper See [client-platforms.md](/mnt/c/Users/neste/Documents/GIT/NexaVPN/docs/client-platforms.md) for the current platform strategy. Helper build commands: ```bash cd desktop-client npm run helper:windows-x64 npm run helper:macos-arm64 ``` Ubuntu-to-Windows `Setup.exe` build: ```bash cd desktop-client cargo install --locked cargo-xwin rustup target add x86_64-pc-windows-msvc npm install npm run helper:windows-x64 npm run tauri:build:windows-x64:linux ``` The resulting NSIS installer is written to: - `desktop-client/src-tauri/target/i686-pc-windows-msvc/release/bundle/nsis/` - `desktop-client/src-tauri/target/x86_64-pc-windows-msvc/release/bundle/nsis/` This Linux cross-build path is intended for NSIS `Setup.exe` output. Native MSI packaging and final Windows code signing should still be done on Windows. For `x86_64-pc-windows-msvc`, the build uses the Windows `x86_64` SDK/CRT set via `cargo-xwin`. Gateway utility scripts: ```bash ./deploy/scripts/generate-gateway-keypair.sh ./deploy/scripts/get-admin-token.sh http://localhost admin your-password ``` ## Local Test Flow ```bash cd deploy cp .env.example .env docker compose up --build ``` Then: 1. Visit `http://localhost` 2. Bootstrap the first admin account 3. Create a standard user in the `Users` page 4. Create a user policy in the `Policies` page 5. Enroll a device from the NexaVPN desktop app against `http://localhost` 6. Inspect the generated device profile in the `Devices` page ## Realistic MVP Usage The current repository can act as a real WireGuard control plane and issue per-device peer state, but these platform pieces are still at MVP level: - the desktop app now targets an embedded NexaVPN tunnel backend model, and the helper source is in-repo, but final platform builds and signing still need to happen per target OS - the gateway helper now applies WireGuard and nftables state in-container, but you still need to provide the gateway private key and correct uplink interface settings - admin debug profiles intentionally use a private-key placeholder because the client private key stays local