VPN Works 0.8.0 Adds Tunnel Plugins and Rotates Through a Folder of WireGuard Configs
VPN Works 0.8.0 opens a new kind of plugin, the Tunnel. A Tunnel plugin hands the kernel WireGuard configs and says how long to keep each, and vpnw runs every tunnel itself. The built-in rotate takes the configs in a folder and moves to the next one every so often, or when a tunnel stops answering.
A scraper or a crawler often has to change where it leaves from, every few minutes or as soon as a server goes quiet. VPN providers hand out one WireGuard config per server, and switching between them by hand means stopping the program, or running a VPN for the whole machine.
With rotate the program keeps running and vpnw does the switching. The next tunnel is up before anything moves to it, and connections already open finish on the tunnel they started on.

How It Works
mkdir -p ~/.config/vpnw/rotate && cp se-*.conf ~/.config/vpnw/rotate/
vpnw guard --tunnel rotate --set rotate.every=10m --policy scraper.toml -- ./scraper
vpnw asks the plugin for a config when the run starts, when the one in use has been kept as long as the plugin asked, and when its tunnel stops answering: data went out and nothing WireGuard accepts came back for 20 seconds. Each config is checked as a --wireguard file is. One that’s refused, such as a config with a shell hook or an OpenVPN file, or whose tunnel doesn’t come up, is skipped, and the record says why. If no config comes up at the start, the program never starts. If none comes up later, the tunnel in use stays: vpnw never falls back to connecting directly.
A WireGuard peer talks to one tunnel of a key at a time. So when the rotation comes back to a config whose tunnel still carries connections, vpnw moves back to that tunnel instead of starting a second one, which would take the peer from it. A long download, or a connection left open between requests, carries on.
Rotate reads its folder through a new permission, folder.read, which any plugin can ask for: the files in one folder that vpnw opens for it, and nothing outside it. A Tunnel plugin decides where the program’s traffic goes, so choose one as you would a VPN provider.
What the Tests Showed
The tests run the real vpnw with rotate against real WireGuard peers inside the tests, and 9 of 9 checks passed. Rotating every 5 seconds through three peers while the program asked for a page every 200 ms, 102 requests went through and none failed, and the peers came in turn A, B, C, A. A connection that asked now and then and a 16 MB download that paused both carried on through a.conf’s tunnel while the path went to b.conf and back. When the peer in use went silent, vpnw moved to the next config on its own, and no request reached the silent peer after. A plugin that panicked in the middle of a run left the tunnel in use carrying on, with 49 requests and none failed.
Lab, the fault kit every tunnel must pass, now runs each of its 18 cases twice: with --wireguard, and with the same config handed over by rotate. All 36 were handled.
What the Review Found
An independent review went through the release in two passes and found real problems before it shipped:
- Two tunnels with one key. Coming back to a config whose old tunnel was still winding down started a second tunnel with the same key. The peer followed the new one, and the connections on the old one stalled. Now vpnw moves back to the old tunnel, or closes it with its connections when it can’t be used.
- A private key in the record. A mistyped line such as
PrivateKey: <key>gave an error that quoted the line, key included, and errors about a plugin’s configs go to the record. Errors now show a key’s name or an address and nothing else from the line. - Packets made to look like a peer’s. Anyone who could send packets shaped like WireGuard’s to the tunnel’s port could keep a dead peer looking alive. Now only what WireGuard accepted counts.
- A crash as a tunnel closed. The network stack vpnw runs inside its process, from wireguard-go, could panic when a tunnel closed while packets were still being sent, and take vpnw down with it. Rotation closes tunnels while traffic flows, so vpnw now carries a copy of that code with the fix.
- Lookups as a side channel. Error text told the plugin what its endpoint names resolved to on your machine. Now it learns only whether a name could be looked up.
Each is a case in the tests now.
Measured
| What | 0.8.0 |
|---|---|
| Tunnel plugin checks, with the real binary and real peers | 9 of 9 passed |
Faults thrown by Lab, through --wireguard and through rotate |
36, all handled |
| Moving to the next config: its tunnel up and the handshake done | 31.5 ms |
| Rotate asked for the next config, from a folder of 20 | 1.7 ms |
| Test functions | 236 of 236 passed |
| Ways out of the sealed sandbox | 17 of 17 blocked, IPv6 included |
| Statements covered | 85.4% |
| Fuzz targets | 17, all clean |
How it was measured: test/results
What It Doesn’t Do Yet
--tunnel is given on the command line. A file’s [paths] doesn’t take a Tunnel plugin yet, and neither does an exit. Configs that rotate can’t share a fixed ListenPort, since two tunnels are up while one replaces the other.
This release ends the program that started with 0.4.1. What comes next is chosen after a look at it. Plugins · Roadmap · Download