High-performance, censorship-resistant VPN built with Rust
β οΈ Mavi VPN is early beta software and has not been independently audited. Do not rely on it for high-risk security use cases yet.
Mavi VPN tunnels all network traffic over QUIC via the quinn fork and the h3 fork, both tracked on main, to deliver secure, reliable, low-latency connectivity β even on unstable mobile networks. It supports Windows, Linux, and Android with native clients and an optional cross-platform Tauri GUI.
| Category | Feature | Details |
|---|---|---|
| Censorship Resistance | Layer 7 Obfuscation | VPN traffic masquerades as HTTP/3 via ALPN h3 |
| Probe Resistance | Unauthorized connections receive a fake nginx welcome page (H3 200 OK) | |
| MASQUE / RFC 9484 | Optional connect-ip capsule framing for DPI-proof wire format |
|
| Encrypted Client Hello | ECH GREASE + SNI spoofing via X25519/HPKE (RFC 9180) | |
| Certificate Pinning | SHA-256 cert fingerprint verification on all clients | |
| Performance | Zero-Copy Path | bytes/BytesMut across the entire packet pipeline |
| BBR Congestion Control | Optimized for high-bandwidth, high-latency mobile networks | |
| GSO/GRO | Generic Segmentation Offload to reduce syscall overhead | |
| 4 MB UDP Buffers | Auto-tuned OS-level socket buffers for burst resilience | |
| mimalloc | High-performance memory allocator on the server | |
| Mobile-First | Seamless Roaming | QUIC connection migration β no handshake restart on IP change |
| MTU Pinning (1280/1360) | Avoids PMTUD black holes; ICMP PTB signal generation (RFC 4443) | |
| Split Tunneling | Per-app VPN bypass on Android | |
| Auth | Static Token | Simple pre-shared key authentication |
| Keycloak OIDC | Enterprise SSO with JWT validation, PKCE, and JWKS rotation | |
| Network | Dual-Stack | Full IPv4 + IPv6 support (NAT66 via ip6tables) |
| DNS Isolation | NRPT rules on Windows; per-tunnel DNS on Linux/Android |
graph TD
subgraph "Client β Windows / Linux / Android"
GUI["Tauri GUI / CLI / Android App"]
SVC["Background Service / Daemon / JNI Core"]
TUN_C["Virtual TUN Adapter"]
GUI <-->|"IPC (TCP 14433)"| SVC
SVC <-->|"Packet I/O"| TUN_C
end
subgraph "Transport β UDP/QUIC"
QUIC["QUIC Datagrams\n(or MASQUE connect-ip capsules)"]
end
subgraph "Server β Linux Docker Container"
AUTH["Auth Handshake\n(Token / Keycloak JWT)"]
HUB["Packet Routing Hub\n(DashMap peer table)"]
TUN_S["Virtual TUN Adapter"]
AUTH <--> QUIC
HUB <--> QUIC
HUB <-->|"Packet I/O"| TUN_S
end
SVC <-->|"QUIC payload β€1360 bytes"| QUIC
QUIC <-->|"QUIC payload β€1360 bytes"| HUB
mavi-vpn/
βββ backend/ # Linux VPN server (Rust) β QUIC endpoint, IP pool, routing, Keycloak
β βββ src/
β β βββ main.rs # Entry point, connection accept loop
β β βββ config.rs # CLI/env config (clap)
β β βββ state.rs # AppState: IP pool (v4+v6), peer DashMap
β β βββ routing.rs # TUN reader/writer tasks with local peer cache
β β βββ cert.rs # TLS cert generation & SHA-256 PIN export
β β βββ ech.rs # ECH key generation & ECHConfigList persistence
β β βββ keycloak.rs # OIDC JWT validator with JWKS refresh
β β βββ handlers/ # Per-connection QUIC session handler
β β βββ network/ # TUN device creation, h3-quinn adapter
β β βββ server/ # QUIC endpoint builder (BBR, timeouts, buffers)
β βββ docker-compose.yml # Full stack: VPN + optional Traefik + Keycloak
β βββ entrypoint.sh # iptables NAT, IPv6 forwarding, MSS clamping
β βββ .env.example # All configuration variables documented
β
βββ windows/ # Windows client (Rust) β WinTUN, Service/Client IPC
β βββ src/
β βββ main.rs # CLI client (start/stop/status)
β βββ bin/service.rs # Windows Service (WinTUN, routing, NRPT DNS)
β βββ vpn_core.rs # QUIC tunnel logic, ECH, MASQUE framing
β βββ oauth.rs # PKCE OAuth2 flow for Keycloak
β
βββ linux/ # Linux client (Rust) β TUN via /dev/net/tun, systemd
β βββ src/
β βββ main.rs # CLI + daemon mode + IPC client
β βββ vpn_core.rs # QUIC tunnel logic with network change detection
β βββ daemon.rs # IPC server (TCP 14433) for GUI integration
β βββ network.rs # Route setup, DNS config, cleanup
β βββ tun.rs # Raw TUN device via ioctl
β
βββ android/ # Android app (Kotlin + Rust JNI)
β βββ app/src/main/
β βββ kotlin/ # Jetpack Compose UI, VpnService, NetworkCallback
β βββ rust/src/lib.rs # JNI core: QUIC, cert pinning, connection migration
β
βββ gui/ # Cross-platform Tauri v2 GUI (HTML/CSS/JS + Rust)
β βββ src/ # Frontend (vanilla HTML/CSS/JS)
β βββ src-tauri/ # Tauri backend (IPC bridge, system tray, WiX installer)
β
βββ shared/ # Shared library (Rust)
β βββ src/
β βββ lib.rs # ControlMessage protocol (Auth β Config β Datagrams)
β βββ icmp.rs # ICMP "Packet Too Big" generation (RFC 792/4443)
β βββ ipc.rs # IPC protocol (SecureIpcRequest, Config, Response)
β βββ masque.rs # MASQUE connect-ip: capsules, varints, datagram framing
β βββ hex.rs # Hex encode/decode utilities
β
βββ quic-tester/ # DPI probe simulator β verifies censorship resistance
βββ docs/ # INSTALLATION.md, NGINX_PROXY.md, whitepaper.tex
βββ Dockerfile # Multi-stage build (rust:1.94 β debian:trixie-slim)
βββ .github/workflows/ # CI: build (Linux CLI, Android APK, Linux/Windows GUI), tests
cd backend
cp .env.example .env
nano .env # Set VPN_AUTH_TOKEN, VPN_PORT, etc.
docker-compose up -d --buildRetrieve the certificate PIN for clients:
cat data/cert_pin.txtPort: The server listens on UDP (default
10443). Ensure your firewall allows this.
Automated (recommended):
# Run PowerShell as Administrator
python install_cli_windows.py # Installs CLI + Windows Service
python install_gui_windows.py # Installs Tauri GUI (optional)Usage:
mavi-vpn-client start # Connect (prompts for config on first run)
mavi-vpn-client stop # Disconnect
mavi-vpn-client status # Check connection statusAutomated (recommended):
python3 install_cli_linux.py # Installs CLI + optional systemd service
python3 install_gui_linux.py # Installs Tauri GUI (deb/rpm/AppImage)The CLI installer creates the mavivpn group and adds your desktop user so the GUI/CLI can control the root daemon after you log out and back in.
Usage:
sudo mavi-vpn # Interactive connect (direct mode)
sudo mavi-vpn daemon & # Start IPC daemon (for GUI)
mavi-vpn start # Connect via daemon
mavi-vpn stop # Disconnect
mavi-vpn status # Check VPN status- Install Rust targets +
cargo-ndk:cargo install cargo-ndk rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android
- Open the
android/folder in Android Studio - Build β Build APK β the Rust core compiles automatically via Gradle
cd gui
npm install
npm run tauri -- dev # Development
npm run tauri -- build # Production (generates MSI/DEB/RPM)Mavi VPN offers three escalating levels of traffic obfuscation:
| Level | Mode | Wire Format | Activate |
|---|---|---|---|
| 0 | Standard | Raw QUIC datagrams | Default |
| 1 | CR Mode | QUIC + ALPN h3 + probe resistance |
censorship_resistant: true |
| 2 | HTTP/3 Framing | Full MASQUE connect-ip (RFC 9484) capsules | http3_framing: true |
| + | ECH | SNI spoofing + HPKE GREASE (RFC 9180) | Provide ech_config hex |
When CR Mode is enabled, the server responds to unauthorized connections with a fabricated HTTP/3 nginx welcome page. This makes the server indistinguishable from a regular web server to active probes and DPI systems.
ECH is supported on clients via EchMode::Grease β the real SNI is hidden behind a cover domain (e.g. cloudflare-ech.com). The server generates and persists the ECH keypair in data/ech_config_hex.txt.
Set VPN_AUTH_TOKEN on the server. Clients send this token during the QUIC handshake.
Full enterprise SSO with Keycloak:
- Enable in server
.env:VPN_KEYCLOAK_ENABLED=true VPN_KEYCLOAK_URL=https://auth.example.com VPN_KEYCLOAK_REALM=mavi-vpn VPN_KEYCLOAK_CLIENT_ID=mavi-client
- Deploy Keycloak via the included
docker-compose:COMPOSE_FILE=docker-compose.yml:keycloak/docker-compose.yml COMPOSE_PROFILES=traefik,keycloak
- Clients authenticate via browser-based PKCE OAuth2 β the CLI/GUI opens a local HTTP server on port
18923, redirects to Keycloak, and captures the JWT automatically.
The server validates JWTs using Keycloak's JWKS endpoint with automatic key rotation and constant-time
azpcomparison.
| Setting | Value | Why |
|---|---|---|
| Inner TUN MTU | 1280 | IPv6 minimum β universally supported, avoids fragmentation |
| QUIC Payload | 1360 | Fits within 1460-MTU networks (e.g. Vodafone) without fragmentation |
| Congestion Control | BBR | Bandwidth-based, not loss-based β optimal for mobile/high-latency |
| UDP Socket Buffers | 4 MB | Prevents kernel drops during GSO bursts |
| Allocator | mimalloc | Reduces memory allocation latency on the server |
| Release Profile | lto=true, codegen-units=1, strip=true |
Maximally optimized binary |
All server settings can be configured via environment variables or CLI flags:
| Variable | Default | Description |
|---|---|---|
VPN_BIND_ADDR |
0.0.0.0:4433 |
QUIC listen address |
VPN_AUTH_TOKEN |
(required) | Pre-shared authentication token |
VPN_NETWORK |
10.8.0.0/24 |
IPv4 client subnet (supports /8 to /30) |
VPN_NETWORK_V6 |
fd00::/64 |
IPv6 client subnet (ULA) |
VPN_DNS |
1.1.1.1 |
DNS server pushed to clients |
VPN_MTU |
1280 |
TUN interface MTU |
VPN_CENSORSHIP_RESISTANT |
false |
Enable Layer 7 obfuscation |
VPN_MSS_CLAMPING |
false |
TCP MSS rewriting via iptables mangle |
VPN_ECH_PUBLIC_NAME |
cloudflare-ech.com |
ECH cover SNI domain |
VPN_KEYCLOAK_ENABLED |
false |
Enable Keycloak JWT auth |
VPN_KEYCLOAK_URL |
β | Keycloak server URL |
VPN_KEYCLOAK_REALM |
mavi-vpn |
Keycloak realm name |
VPN_KEYCLOAK_CLIENT_ID |
mavi-client |
Keycloak OIDC client ID |
# Run unit tests (shared crate + backend)
cargo test -p shared --verbose
cargo test -p mavi-vpn --verboseThe quic-tester/ tool simulates a DPI scanner to verify censorship resistance:
cargo run -p quic-tester -- <server:port>
# Expects HTTP/3 nginx response β confirms probe resistance is active| Document | Description |
|---|---|
docs/INSTALLATION.md |
Comprehensive installation guide for all platforms |
docs/NGINX_PROXY.md |
Deploying behind an existing Nginx with wildcard SSL |
CODEWIKI.md |
Deep technical encyclopedia of the entire codebase |
docs/whitepaper.tex |
Academic whitepaper (LaTeX) |
- Socket Sharding β
SO_REUSEPORTfor multi-core UDP scaling - eBPF Data Plane β Kernel-level packet routing for zero-copy efficiency
- iOS Support β Rust core via C-FFI +
NEPacketTunnelProvider - Server-side ECH β Full ECH decryption when rustls adds support
