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 designbackend/Go API, migrations, seeds, and domain servicesadmin-web/React + Vite admin UIdesktop-client/Tauri desktop clientdeploy/Docker Compose, reverse proxy, and gateway assets
Architecture Overview
NexaVPN Architecture
┌──────────────────────────────┐
│ Internet / WAN │
└──────────────┬───────────────┘
│
│ HTTPS + WireGuard
│
┌───────────────────────┴────────────────────────┐
│ │
│ Public entry on NexaVPN host │
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ reverse-proxy (nginx / public ingress) │ │
│ │ - admin-vpn.nesterovic.cc │ │
│ │ - vpn.nesterovic.cc │ │
│ └───────────────┬──────────────────────────┘ │
│ │ │
│ HTTP/HTTPS│ │
│ │ │
│ ┌───────────────▼──────────────┐ │
│ │ public-web │ │
│ │ static frontend + /api │ │
│ └───────────────┬──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ backend (Go control plane) │ │
│ │ - auth / users / devices / policies │ │
│ │ - gateway sync bundle │ │
│ │ - service catalog + dns override API │ │
│ └───────────────┬──────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ postgres │ │
│ │ - users / groups / policies / devices │ │
│ │ - wireguard peers / ip allocations │ │
│ │ - service definitions / runtime stats │ │
│ └──────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ gateway │ │
│ │ - wg0 │ │
│ │ - syncs peer state from backend │ │
│ │ - renders nftables policy │ │
│ │ - enforces split tunnel / service ACLs │ │
│ └───────────────┬──────────────────────────┘ │
│ │ │
│ │ VPN client traffic │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ vpn-dns │ │
│ │ - upstream: internal DNS servers │ │
│ │ - overrides service domains │ │
│ │ to NexaVPN access-proxy IP │ │
│ └───────────────┬──────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ access-proxy │ │
│ │ - checks source VPN IP │ │
│ │ - checks Host / TLS SNI │ │
│ │ - forwards only allowed services │ │
│ └───────────────┬──────────────────────────┘ │
└──────────────────┼─────────────────────────────┘
│
▼
┌──────────────────────────────┐
│ Internal LAN / service tier │
│ - Zoraxy / reverse proxies │
│ - Jellyfin / PVE / apps │
│ - DNS servers │
└──────────────────────────────┘
Desktop flow
NexaVPN desktop client
│
├─ login / sync profile ─────────────► backend
│
├─ gets WireGuard profile + DNS ─────► backend
│
├─ connects WireGuard tunnel ────────► gateway:51900/udp
│
├─ normal split-tunnel CIDR traffic ─► internal LAN targets
│
└─ service-domain traffic
nesflix.cc
│
├─ DNS query ─────────────────► vpn-dns
├─ override answer ───────────► access-proxy IP
├─ HTTPS with Host/SNI ───────► access-proxy
└─ forwarded if policy allows ► Zoraxy / upstream service
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
- Copy
deploy/.env.exampletodeploy/.env. - Review
docs/architecture.mdanddocs/deployment.md. - Start the stack with Docker Compose from
deploy/. - Open
http://localhost. - On the admin login screen, choose the bootstrap flow if this is a fresh install.
- 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 for the current platform strategy.
Helper build commands:
cd desktop-client
npm run helper:windows-x64
npm run helper:macos-arm64
Ubuntu-to-Windows Setup.exe build:
cd desktop-client
sudo apt update
sudo apt install -y clang lld llvm nsis
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:
./deploy/scripts/generate-gateway-keypair.sh
./deploy/scripts/get-admin-token.sh http://localhost admin your-password
Local Test Flow
cd deploy
cp .env.example .env
docker compose up --build
Then:
- Visit
http://localhost - Bootstrap the first admin account
- Create a standard user in the
Userspage - Create a user policy in the
Policiespage - Enroll a device from the NexaVPN desktop app against
http://localhost - Inspect the generated device profile in the
Devicespage
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
Description
Languages
Go
39.7%
TypeScript
25.5%
Rust
19.7%
CSS
7.6%
Shell
4.3%
Other
3.2%