Exit
Exit is the server end of a path: vpnw exit, on a machine with fixed addresses. Each client leaves from an address of its own, and every request is decided again at the exit with that client’s own policy, by the same code that decided it on the client’s machine.
Partners and internal systems often let traffic in by address, so agents and CI jobs need fixed addresses to leave from. A plain proxy with a fixed address trusts whatever reaches it with the right password, so a hijacked client, or anyone holding its token, can push anything through it. An exit checks every request again, with that client’s own policy.

How It Works
Clients reach the exit over TLS, with vpnw’s proxy paths, each with a token of its own. The exit keeps only each token’s hash.
# a private CA and the exit's certificate
vpnw exit cert --host 198.51.100.2 --name exit-de
# a client's token
vpnw exit token --out agent-1.token
vpnw exit serve --config exit-de.toml
On the client’s machine, with the CA’s certificate and the token copied over:
vpnw guard --proxy https://198.51.100.2:8443 --ca ca.pem --token-file agent-1.token \
--policy agent-1.toml -- ./my-agent
For every request, the exit:
- knows the client by its token. A wrong token is refused, and answered after a second, so guessing is slow.
- decides again with that client’s own policy file, by the same code vpnw uses on the client’s side. Names are looked up at the exit, so
deny_privatesees where a name really points. - never connects to its own machine or a cloud’s metadata service, whatever the client’s policy allows, unless the exit’s file lets that client reach the machine.
- connects from the client’s fixed address, or from one address of a pool it shares with other clients, and checks the connection really left from there.
Give --proxy twice for a list of exits: when the one in use stops answering, connections move to the next.
The Record at Both Ends
The exit keeps a record in the same event format as a run, with the client’s run and connection IDs on each connection. So the client’s record and the exit’s line up, connection by connection. Plugins run at the exit as they do in a run: Trace prints its record, Ledger can seal it, and a Guard plugin gets a say after the client’s policy, told which client asked.
What the Tests Showed
The tests run the real vpnw exit serve, with the real vpnw as its client, on one Linux machine, and 21 of 21 checks passed. The full results
| Test | What happened |
|---|---|
| A client sends forbidden requests straight to the exit, skipping its own policy, with its valid token | 11 of 11 refused at the exit by the client’s own policy; none reached a server |
| One policy file at both ends | the client refused 3 of 5 destinations, and those never reached the exit; the exit allowed the other 2 by the same rules, and the two records lined up on run and connection IDs |
| The exit in use is killed after 3 of 10 fetches | the other 7 went through the second exit, from its own address; none failed |
| A client whose policy allows everything asks for the exit’s own machine and for cloud metadata | 5 of 5 refused at the exit, none reached; with allow_exit_host for that client, its machine was reached and cloud metadata stayed refused |
| A run’s broker and an exit, given the same policy and the same DNS answers | 513 of 513 requests decided the same way |
On that machine, opening a connection through an exit took 2.0 ms, TLS and token included, and data went through it at 511 MB/s.
What It Doesn’t Do Yet
It reads its file when it starts; to change its clients, restart it. A client’s policy file at the exit is the exit’s own copy, so when it changes on the client’s side, copy it over. Over SOCKS5 a refusal carries no reason. And a client can’t ask for a particular address of its pool.
Where It Came From
Exit first ran as a separate engine, vpnw-exit, in VPN Works 0.2.0. In its recorded case, a stolen agent token sent straight to the exit reached nothing its policy refused. The case study

In 0.7.0 it’s part of vpnw itself, with the same broker deciding at both ends. Roadmap · Reference