Open-source project
jamesmcm/vopono avatar
jamesmcm/vopono

vopono and the case for a VPN tunnel per application

Run applications through VPN tunnels with temporary network namespaces

1,399 stars85 forksRustGPL-3.0

At a glance

What is it?
vopono is a Rust tool that runs individual applications through VPN tunnels using temporary network namespaces, so a browser can go through one provider while everything else keeps its normal connection. It ships killswitches for WireGuard and OpenVPN, a daemon mode so the privileged part runs once, and a provider matrix that is honest about which protocol each service actually supports.
Who is it for?
Adopt vopono if you need one application on a different VPN exit than the rest of the machine, or you want traffic from a single process to leave through another provider, and if you are on Linux with WireGuard or OpenVPN available. Do not adopt it if you need every application on one tunnel, since a conventional VPN client is simpler for that, and do not adopt it on a platform where network namespaces are not available.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 21 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One process, one tunnel

vopono runs applications through VPN tunnels using temporary network namespaces. The description of what that buys is short and worth quoting in full, since it is the whole product: you can run only a handful of applications through different VPNs simultaneously, whilst keeping your main connection as normal.

That is a different shape from a conventional VPN client. A conventional client moves the default route of the whole machine into a tunnel, and everything you run inherits the new exit address, whether you wanted it or not. vopono instead creates a network namespace per connection, puts the process inside it, and gives that namespace its own tunnel, its own routing table and its own DNS resolution.

The audience is a Linux user with a specific need. You have a service that has to appear to come from another country, and you do not want your whole desktop to move with it. You have two providers and want one browser on each. You are running a scraper or a client that should egress from a specific exit node while your mail client stays on your home connection. In each case the alternative, running a full tunnel and constantly switching, is operationally clumsy.

The implementation is Rust, and the repository layout matches a tool with a library core. The Cargo manifest declares a workspace with the root package and a vopono_core member, and vopono_core is the internal library the binary depends on. There is also a vopono-gui directory, which is explicitly excluded from the workspace, and an install.sh, an RPM packaging directory, a Debian packaging directory and a vopono.service unit file.

The killswitch is the reason to use namespaces

vopono includes built-in killswitches for both WireGuard and OpenVPN, and that single feature explains most of the design.

The problem a killswitch solves is the moment a tunnel drops. Traffic that was supposed to go through the VPN suddenly goes out through the normal interface instead, and whatever you were doing online happens from your real address. On a machine where the VPN is running system wide, a killswitch has to sit at the firewall and block everything that is not the tunnel.

In a per-application model the same guarantee is much easier to express, because the process is already isolated in a namespace whose only way out is the tunnel. If the tunnel dies, the namespace has no route to the internet and the application simply stops working instead of leaking. The killswitch is a property of the architecture rather than a rule bolted on top of it.

The manifest shows what that involves at the system level. The nix crate is pulled in with the signal, process, socket, uio, mount and term features, which is the low level Linux surface a tool needs to create namespaces, mount things and manage the process inside them. The interprocess crate handles the communication with the privileged daemon when daemon mode is in use, and the firewall backend is configurable, with the config file example setting firewall to NfTables, so the rules are written with nftables.

The Debian packaging metadata reinforces the design, with the recommended packages listed as wireguard-tools, openvpn, openssh-client and redsocks. The first two are the tunnel clients, and redsocks is the usual companion for tunnelling DNS and TCP through a SOCKS proxy, which is how a name based tunnel can still resolve names correctly.

The provider table is the honest part

The supported providers table is unusual in how much it admits, and it is the first thing to read.

Mullvad, AzireVPN and MozillaVPN are WireGuard only, with no OpenVPN support marked. NordVPN is the mirror image, OpenVPN only, with no WireGuard. iVPN, PrivateInternetAccess, ProtonVPN and AirVPN support both. Cloudflare Warp supports neither, because it uses its own protocol, and the documentation says so explicitly: set both the provider and the protocol to warp.

Self hosted connections with the --custom argument support both protocols, and for custom connections the OpenConnect and OpenFortiVPN protocols are also supported, which the README points out is aimed at enterprise VPNs. That is a meaningfully broader list than the table of consumer providers suggests, and it is the part that matters if you are connecting to a corporate gateway rather than a commercial one.

The footnotes carry the operational detail. ProtonVPN's OpenVPN authentication needs a header of the form AUTH-xxx=yyy copied from the x-pm-uid value of a request made while logged in, and the user guide covers generating the configs with vopono sync. For WireGuard, ProtonVPN configs can be generated and used as a custom provider, and the port forwarding implementation to use has to be named explicitly with the custom port forwarding option, for example with a provider of custom, a custom config file, a protocol of wireguard and a custom port forwarding of protonvpn. natpmpc has to be installed for that to work.

For OpenVPN with ProtonVPN the username has to be generated with +pmp appended, and a server that supports the feature has to be chosen, with the Romania servers given as an example at the time of writing. The assigned port is printed to the terminal where vopono was launched, and has to be set in the applications that need it, or handed to a script through the port forwarding callback argument.

AirVPN is the case the documentation handles most carefully, since port forwarding is supported as a provider capability but forwarded ports must be configured in AirVPN's own client area, and vopono does not claim or toggle those ports automatically.

Daemon mode, so the privileged part happens once

The README is explicit that you should run vopono as your own user, not using sudo, and that it will handle privilege escalation where necessary. That is the right default for a tool that is invoked per command, since it avoids asking for root on every launch.

For a smoother experience the project also offers daemon mode, where the privileged root daemon runs and you keep using vopono as your normal user. The CLI automatically forwards exec requests to the daemon if it is running, which is the detail that makes the mode invisible in daily use.

The commands are short:

bash
sudo systemctl enable --now vopono
sudo vopono daemon start
vopono daemon status --json

The first line starts it at boot through systemd, the second is the explicit equivalent of running it manually as root with sudo vopono daemon, and the third inspects it with machine readable output, which is what you want if you are writing a health check or a script.

The unit file is shipped in the repository, and the Debian packaging metadata installs it to the systemd unit directory alongside the binary in /usr/bin, with the packaging scripts in the packaging/ directory. The user guide has a ready to copy systemd unit for anyone who wants to adjust it, and it also covers the case of running the tool as a service.

The vopono.service file in the repository root is the same artefact, and the manifest's asset list shows exactly what the package installs, which is a small binary and one unit file, with no configuration written into the system directories.

Namespaces are shared per provider and server prefix

vopono can handle up to 255 separate network namespaces, which is the number of different VPN server connections, limited by what the provider allows. Commands launched with the same server prefix and VPN provider share the same network namespace, and that rule has consequences for how you organise a session.

Sharing is the efficient behaviour, because a namespace carries a tunnel and a set of rules, and creating one per process would be wasteful. It also means that two applications pointed at the same provider and the same server group share a tunnel, so a connection limit at the provider is consumed once rather than twice, and the second application inherits whatever the first one did to the namespace.

The defaults live in a TOML file at ~/.config/vopono/config.toml, and the example in the README is short:

toml
firewall = "NfTables"
provider = "Mullvad"
protocol = "Wireguard"
server = "usa-us22"

The values are case-sensitive, and the README says so, which is a small warning with a large failure mode, since a lowercase protocol name silently means no configuration match rather than an error message. The firewall key selects the backend used to write the namespace rules, and the config crate in the dependency list is what reads the file.

The typical session is two commands. vopono sync sets up the provider configuration files, and vopono exec runs a program with a provider and a server, for example vopono exec --provider azirevpn --server norway firefox. The sync step is where the provider specific authentication happens, and for ProtonVPN it is where the OpenVPN config files with the right headers are generated.

One operational warning from the README is worth repeating because it will otherwise look like a bug. When creating and uploading new WireGuard keypairs there may be a delay of about 30 to 60 seconds before they are usable, on Mullvad for example, so a run that fails immediately after a sync may simply be too early.

A full tunnel client versus per process namespaces

The honest alternative to vopono is an ordinary VPN client, and the choice comes down to scope.

A full tunnel client moves the machine. It is simpler, it is what the provider's own application does, it handles its own killswitch, and it works on the platforms where namespaces are awkward. If your requirement is that everything on the machine exits through one provider, a full tunnel client is the better tool and vopono is the wrong one.

vopono earns its place in the cases where scope matters. Applications that should not be tunnelled keep working normally, several providers can be used at once, and the isolation is enforced by the kernel rather than by a firewall rule set that has to be maintained.

The cost is that vopono is Linux only and depends on tooling you have to install. The Raspberry Pi instructions make that concrete. The deb package is installed from the releases page, then OpenVPN has to be installed from the Raspbian repositories, and the usage is the same as elsewhere with the difference that the Chromium binary is called chromium-browser. The README also warns that WireGuard is not in the Raspbian repositories, so installing it is not trivial, since you need WireGuard and wireguard-tools for the wg binary as well as the linux headers.

The Arch route is the easiest of the documented installs, with paru -S vopono-git for the source package or the vopono-bin package if you do not want to compile, followed by vopono sync.

There is a third option worth naming for completeness, an application level proxy such as a SOCKS proxy, which needs no privileges and no namespaces but only affects applications configured to use it. That is more portable and far less automatic, and the redsocks recommendation in the Debian packaging shows how the namespace approach handles the DNS problem that a plain proxy leaves behind.

Rust, edition 2024, and a 1.0 line

The manifest describes the package as vopono, with the description launch applications via VPN tunnels using temporary network namespaces, edition 2024, and the licence GPL-3.0-or-later, which is what the repository's licence file matches.

The dependency list is short and tells you the design. clap with the derive feature is the command line interface, nix provides the low level Linux operations, shellexpand handles the tilde and environment expansion in paths, config reads the TOML file, serde and serde_json handle serialisation, thiserror and strum handle errors and enumerations, interprocess handles the daemon communication, wincode and tempfile handle encoding and temporary files, compound_duration and chrono handle time values, bs58 handles base58 encoding, and dialoguer and pretty_env_logger are the terminal interaction and logging.

The workspace arrangement is worth noting. The root package and vopono_core are the members, with the root as the default, and vopono-gui is excluded from the workspace entirely, so the GUI is a separate build that the core does not depend on. That keeps the library usable without the interface.

The release history is short because the project is young. Version 1.0.0 shipped on 2026-08-27, 1.0.1 on 2026-08-30 and 1.0.2 on 2026-09-20, so the 1.0 line is only a few weeks old. The repository is not archived, and the last push was on 2026-10-02.

What to take from all this is that the tool has a clear, narrow shape and a real system dependency, and the documentation is unusually forthcoming about the parts that are awkward, from ProtonVPN's authentication headers to AirVPN's client area to the 30 second keypair delay. The user guide is where the rest of it lives.

Editorial conclusion

Adopt vopono if you need one application on a different VPN exit than the rest of the machine, or you want traffic from a single process to leave through another provider, and if you are on Linux with WireGuard or OpenVPN available. Do not adopt it if you need every application on one tunnel, since a conventional VPN client is simpler for that, and do not adopt it on a platform where network namespaces are not available. Verify three things first: that the provider and protocol combination you need is marked as supported in the table, since several providers offer only one of the two protocols, that the killswitch behaviour matches what you need when the tunnel drops, and that the privileges the daemon or the sync step needs are acceptable in your environment. The last push was on 2026-10-02 and the newest release is 1.0.2 from 2026-09-20.

Frequently asked questions

What does vopono do?

It runs applications through VPN tunnels using temporary network namespaces, so you can route only a handful of applications through different VPNs at once while your main connection stays as normal. It includes built-in killswitches for both WireGuard and OpenVPN.

Which VPN providers does vopono support?

Mullvad, AzireVPN, iVPN, PrivateInternetAccess, ProtonVPN, MozillaVPN, NordVPN, AirVPN and Cloudflare Warp are supported directly, plus custom configuration files with the --custom argument, where OpenConnect and OpenFortiVPN are also available for enterprise VPNs. The table shows that several providers support only one of OpenVPN and WireGuard.

Do I need to run vopono with sudo?

No. The README says to run it as your own user, since it handles privilege escalation where necessary. There is also a daemon mode where a privileged root daemon runs and the CLI forwards exec requests to it, started with sudo systemctl enable --now vopono.

How many VPN connections can vopono hold at once?

Up to 255 separate network namespaces, limited by what the provider allows. Commands launched with the same server prefix and provider share the same namespace, so those applications share a tunnel.

Does vopono support port forwarding?

Yes, with the --port-forwarding option and --port-forwarding-callback to run a command when the port is refreshed. ProtonVPN needs natpmpc installed and a +pmp username for OpenVPN, and for AirVPN the forwarded ports must be configured in AirVPN's own client area.

Where does vopono keep its configuration?

Default options go in ~/.config/vopono/config.toml, with keys such as firewall, provider, protocol and server, and the values are case-sensitive. The project is licensed under GPL-3.0-or-later, the newest release is 1.0.2 from 2026-09-20, and the last push was on 2026-10-02.

Official sources

  1. Issues
  2. jamesmcm/vopono on GitHub
  3. License: GPL-3.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jamesmcm-vopono.svg)](https://hysenlabs.com/projects/jamesmcm-vopono)

Was this useful?