# 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
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:

```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
