Terminal UI for WireGuard and OpenVPN with real-time telemetry and leak guarding.
New in v0.4.0 — multi-tunnel. Run multiple VPN tunnels at the same time; one owns the kernel default route (the primary), the rest are addressable on their declared
AllowedIPs. Per-profile retry and auto-reconnect. Scanner auto-adopts externally-started tunnels. JSON status envelope bumps toschema_version: 2withdata.connections[]+data.primary. Kill switch VPN-only mode now keeps the firewall engaged whether the VPN is up or down (canonical Linux killswitch shape — closes a gap-between-drop-and-reconnect leak path). See the CHANGELOG for the full list.v0.3.0 migration (Engine FSM, session journal, encrypted secret store):
- Release notes — what changed (60s read)
- Upgrade guide — for v0.2.x users
- FAQ — common upgrade questions

I wanted a single interface to: - See connection status, throughput, and latency at a glance - Detect IPv6/DNS leaks without running separate tools - Switch between VPN profiles without remembering CLI flags
Existing options (wg show, NetworkManager, Tunnelblick) either lack real-time telemetry or require a GUI.
| Feature | Vortix | GUI Clients | CLI-only |
|---|---|---|---|
| Memory usage | ~15MB | 200-500MB | ~5MB |
| Startup time | <100ms | 2-5s | Instant |
| Real-time telemetry | ✅ | ✅ | ❌ |
| Leak detection | ✅ | Some | ❌ |
| Kill switch | ✅ | ✅ | Manual |
| Keyboard-driven | ✅ | ❌ | ✅ |
| Works over SSH | ✅ | ❌ | ✅ |
.conf and .ovpn fileswg-quick up X from another terminal shows up in the TUI within ~1s)iptables or nftables on Linux). Three modes — Off (no firewall), Block on drop (engages only if the VPN drops unexpectedly), VPN-only (firewall stays engaged whether the VPN is up or down — closes the gap-between-drop-and-reconnect leak window). Multi-tunnel-aware: every active tunnel's interface is allow-listed${XDG_DATA_HOME}/vortix/sessions/, 30-day retention; useful for diagnostics and scriptingvortix audit answers "is this traffic actually routing through the tunnel?" with per-PID socket inventory; Linux + macOS supported--json envelope carries a schema_version field (currently 2) so consumers can detect breaking changes instead of finding them at runtimeVortix is actively developed and used primarily on macOS.
Linux support is a current focus and is improving quickly, with CI coverage for Ubuntu and Fedora. Linux environments still vary a lot across distributions, firewall backends, DNS tooling, and privilege models, so distro-specific issues may still exist.
If you use Vortix on Linux and hit a problem, please open an issue and include vortix report output when possible. Ubuntu, Fedora, and Arch users are especially helpful when testing release candidates and validating fixes before release. If you want to help test Linux support, join the Linux tester discussion.
| Dependency | macOS | Linux | Purpose |
|---|---|---|---|
openvpn |
brew install openvpn |
apt install openvpn |
OpenVPN sessions |
wireguard-tools |
brew install wireguard-tools |
apt install wireguard-tools |
WireGuard sessions |
resolvconf / systemd-resolved |
N/A (uses native DNS) | Auto-detected; see DNS note below | WireGuard DNS management (only on non-resolved hosts) |
iptables or nftables |
N/A (uses pfctl) |
Pre-installed | Kill switch |
Vortix checks for missing tools at startup and shows a warning toast with install instructions. Interface inspection, network stats, DNS detection, HTTP telemetry, ICMP latency, and clipboard handoff now run in-process — no
curl,ping,which,ifconfig,ip addr,ps,netstat,lsof,scutil,pbcopy, orxclipshell-out required.
DNS tools note: If your WireGuard profile includes a DNS = directive, Vortix manages per-link DNS itself:
- systemd-resolved hosts (Arch / Omarchy, NixOS with services.resolved.enable = true, default Fedora Workstation): no extra package required. Vortix calls resolvectl (shipped with systemd) to register the tunnel's DNS server on the kernel interface. The legacy systemd-resolvconf / openresolv shim is no longer needed on these distros.
- Non-resolved Linux (Debian/Ubuntu without resolved, etc.): Vortix falls back to wg-quick's built-in resolvconf path — install openresolv if your distro doesn't ship one (sudo apt install openresolv).
- Alpine/Void (OpenRC): /etc/resolv.conf editing as the universal fallback.
edition2024 transitive deps; distros shipping older Rust — e.g. Ubuntu 24.04's apt — will need rustup for source builds)Ubuntu/Debian:
sudo apt install wireguard-tools openvpn iptables systemd-resolved
Fedora/RHEL:
sudo dnf install wireguard-tools openvpn iptables systemd-resolved
Arch Linux (only needed for source builds — pacman -S vortix handles deps automatically):
sudo pacman -S wireguard-tools openvpn iptables
DNS management: When your WireGuard profile contains
DNS =, Vortix detects systemd-resolved and registers per-link DNS viaresolvectldirectly (nosystemd-resolvconf/openresolvshim required). On non-resolved Linux Vortix falls back towg-quick's built-inresolvconfpath; installopenresolvif your distro doesn't ship one. Non-systemd distros (Alpine, Void, Gentoo OpenRC) use/etc/resolv.confediting.
Homebrew (macOS/Linux):
brew install Harry-kp/tap/vortix
npm/npx:
npm install -g @harry-kp/vortix
# or run directly without installing:
npx @harry-kp/vortix
From crates.io:
cargo install vortix
Arch Linux (extra repo):
pacman -S vortix
Quick install (Binary):
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/Harry-kp/vortix/releases/latest/download/vortix-installer.sh | sh
Static binary (Linux):
Download the x86_64-unknown-linux-musl release from the releases page. This is a statically linked binary (no glibc needed), but you still need the runtime dependencies above (openvpn/wireguard-tools and the kill-switch tools).
Nix (flakes):
nix run github:Harry-kp/vortix # Run without installing
nix profile install github:Harry-kp/vortix # Install to profile
From source:
git clone https://github.com/Harry-kp/vortix.git
cd vortix
cargo install --path .
Vortix needs root to manage VPN connections and firewall rules. On Linux, sudo uses a restricted PATH (secure_path in /etc/sudoers) that does not include ~/.cargo/bin/ — so sudo vortix will fail with command not found.
Fix (one-time):
sudo ln -s ~/.cargo/bin/vortix /usr/local/bin/vortix
After this, sudo vortix works as expected.
Who is affected:
- cargo install vortix — yes
- Shell installer (curl | sh) — yes
- From source (cargo install --path .) — yes
- pacman -S vortix (Arch) — no, installs to /usr/bin/
- brew install (Homebrew) — no, installs to Homebrew prefix
- npm install -g (npm) — no, installs to npm global bin
- Nix (nix profile install) — no, installs to Nix profile bin
- macOS — no, sudo preserves user PATH
Most day-to-day development happens on macOS. Linux support is continuously tested in CI, but real-world distro coverage is still growing. If something behaves differently on your Linux setup, please treat that as useful signal and report it rather than assuming it is expected.
Vortix has two modes: an interactive TUI dashboard (default) and a headless CLI for scripting, automation, and AI agents.
sudo vortix # Launch TUI dashboard (default)
Every subcommand supports --json for machine-readable output and --quiet for silent operation (exit code only).
Connection (multi-tunnel aware):
sudo vortix up work-vpn # Connect to a profile
sudo vortix up vpn-b --yes # Bypass the conflict gate (default-route
# takeover / route overlap with another
# active tunnel; non-interactive)
sudo vortix down # Disconnect every active tunnel
sudo vortix down work-vpn # Disconnect only the named profile
sudo vortix down --force # Force-disconnect (SIGKILL)
sudo vortix reconnect # Cycle every currently-Connected tunnel
vortix status # Show connection state + telemetry
vortix status --json # v2 envelope: data.connections[] +
# data.primary (back-compat data.connection
# populated when exactly one tunnel is up)
vortix status --brief # One-line: "● Connected to work-vpn"
vortix status --watch # Live updates every 2s
vortix status --watch --json # NDJSON stream for monitoring
Multiple tunnels can be active simultaneously. The tunnel that owns the
kernel default route is the primary; secondaries are addressable
(reachable on their declared AllowedIPs only). vortix up B while
A is up triggers a conflict gate when both claim the default route or
when their AllowedIPs overlap — pass --yes to bypass for scripts.
Profile Management:
vortix list # List all imported profiles
vortix list --names-only # Profile names for scripting
vortix list --sort last-used # Most recently used first
vortix import ./work.conf # Import a WireGuard profile
vortix import ./configs/ # Bulk import from directory
vortix show work-vpn # Display profile configuration
vortix show work-vpn --raw # Raw config file contents
vortix delete old-vpn --yes # Delete without confirmation
vortix rename old-vpn new-vpn # Rename a profile
Security:
# Kill switch — one label per mode, used in the TUI, JSON envelope,
# CLI input, and CLI output alike.
# off All traffic flows. Real IP exposed if VPN drops.
# block-on-drop Block traffic only if the VPN drops unexpectedly.
# vpn-only Only VPN traffic permitted. No internet without a VPN.
sudo vortix killswitch off
sudo vortix killswitch block-on-drop
sudo vortix killswitch vpn-only
vortix killswitch # Show current mode + behaviour
sudo vortix release-killswitch # Emergency firewall release
System: ```bash vortix info # Config paths, versions, profile
$ claude mcp add vortix \
-- python -m otcore.mcp_server <graph>