Canonical repository: git.iris.to (
htree://npub1xdhnr9mrv47kkrn95k6cwecearydeh8e895990n3acntwvmgk2dsdeeycm/nostr-vpn). GitHub is a mirror.
nostr-vpn is a Tailscale-style private mesh VPN built around a FIPS-backed data plane. It includes the nvpn CLI/daemon, a shared native app core, and native shells for desktop and mobile platforms.
- Latest releases on git.iris.to
- GitHub mirror releases
- CLI from crates.io:
cargo install nvpn - iOS TestFlight beta exists, but public access is not live yet
Release artifacts currently cover native Apple Silicon macOS, Linux x64, Windows x64, Android arm64, and headless CLI archives for Apple Silicon macOS, Windows x64, Linux x86_64, and Linux arm64. Intel macOS is source-only for now.
cargo install nvpn --force
nvpn init
MY_NPUB='<paste nostr_pubkey from nvpn init>'
nvpn set --participant "$MY_NPUB"
nvpn create-invite
nvpn start --daemon --connectUse the printed invite on another device; do not paste the example placeholder:
INVITE='<paste invite copied from nvpn create-invite>'
nvpn init
nvpn import-invite "$INVITE"
nvpn start --daemon --connectFor the background daemon flow used by desktop apps:
nvpn start --daemon --connect
nvpn status
nvpn stopFor persistent startup:
sudo nvpn service install
nvpn service statusOn Windows, run nvpn service install from an elevated shell instead of using sudo.
The native apps share the Rust app-core state/action contract and use platform shells for macOS, Linux, Windows, Android, and iOS.
just build
just runUse just run-macos or just run-linux when you want a specific desktop target.
- Generates Nostr identity keys automatically
- Shares networks through invites and roster/admin sync
- Stores multiple named networks with one active network at a time
- Brings up FIPS private mesh tunnels for private network traffic
- Routes private traffic directly when possible and through FIPS neighbors when direct UDP is blocked
- Supports MagicDNS, route advertisement, exit-node selection, and WireGuard upstream egress
- Exposes native desktop apps, JSON status, network diagnostics, doctor bundles, desktop updates, and Linux-focused Docker e2e coverage
| Platform | Status |
|---|---|
| Apple Silicon macOS | Native SwiftUI/AppKit app, CLI tarball, signed/notarized release artifacts when credentials are configured |
| Linux x64 | Native GTK/libadwaita app, .deb, CLI tarballs, Docker e2e coverage |
| Windows x64 | Native WPF app, installer, CLI zip, WinTun tunnel path |
| Android arm64 | Native app-core UI, signed APK/AAB artifacts when signing is configured, VPN runtime still being hardened |
| iOS | Native SwiftUI app and NetworkExtension target build from source and simulator; public TestFlight access is pending |
| Umbrel / StartOS | Web control panels and service packages |
| Intel macOS | Source-only |
- Protocol: invites, admin roster sync, and the FIPS mesh data plane
- Experiments: chronological benchmark and reliability log
- Native UI parity matrix: native app rewrite status
- Contributing: maintainer commands and package notes
- Changelog: release history
This section is intentionally compact and command-oriented. Keep user-facing product detail above; keep agent/operator reference material here.
nvpn init creates the config and keys automatically. By default, config lives in the OS app config directory:
- Linux:
~/.config/nvpn/config.toml - macOS:
~/Library/Application Support/nvpn/config.toml - Fallback when no config dir is available:
./nvpn.toml
The config contains global app settings, Nostr relay/identity settings, NAT settings, node settings, and a [[networks]] list. Each network has its own stable network_id; only the active network participates in the live runtime.
Normal Rust gate:
cargo fmt --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspaceRelease gate before version bumps and tags:
just release-gateUseful focused checks:
pnpm --dir web/control-panel check
( cd linux && cargo check )
dotnet build windows\NostrVpn.Windows\NostrVpn.Windows.csproj -p:EnableWindowsTargeting=trueRun the Windows build on the configured Windows dev VM when local dotnet is unavailable.
docker compose -f umbrel/docker-compose.local.yml up --build
just e2e-umbrel-webFocused security regression kit:
just security-regressionsDocker e2e and desktop updater scripts live under scripts. The most common entrypoints are scripts/e2e-docker.sh, scripts/e2e-fips-routed-udp-docker.sh, scripts/e2e-fips-nat-safe-mtu-docker.sh, scripts/e2e-wireguard-exit-docker.sh, and scripts/e2e-update-desktop.sh.
- Move
CHANGELOG.mdfrom## Unreleasedto## X.Y.Z - YYYY-MM-DD. - Bump the root
[workspace.package].versioninCargo.toml. - Run
node scripts/sync-versions.mjsand verify withnode scripts/sync-versions.mjs --check. - Run
just release-gate. - Commit, create
git tag vX.Y.Z, push the tag togithub, and pushmasterto bothgithuband htreeorigin. - Watch
.github/workflows/release.yml.
For local artifact staging, use:
cp .env.release.example .env.release.local
$EDITOR .env.release.local
just release-publishcrates/nostr-vpn-cli:nvpnCLI and daemon implementationcrates/nostr-vpn-core: config, FIPS control state, diagnostics, MagicDNS, and NAT helperscrates/nostr-vpn-app-core: native app state/action contract and UniFFI bridgemacos,linux,windows,android,ios: native platform shellsumbrel,startos: packaged service/web-control-panel targetsscripts: build, release, Docker e2e, and desktop updater entrypoints