Proteus is a transparent gateway for a whole VLAN. Point a VLAN's default route at it and every device behind it leaves for the internet through a rotating set of Proton WireGuard exits. Each device gets pinned to its own healthy exit, a slow or flagged exit is swapped out before you notice, and if a tunnel drops, nothing leaks — traffic that can't reach its assigned exit is dropped, not sent in the clear.
No client software, no per-device config. The devices think they have a normal gateway.
The wizard runs the whole setup, and it has a demo mode that changes nothing on your machine:
git clone https://github.com/nuk3s/proteus.git && cd proteus
./install/proteus --demo # cinematic walkthrough: no root, changes nothingThat is the recording above. When you're ready to install for real on a fresh Debian 13 box:
sudo ./install/proteus # config → preflight → apply → go-live, guidedThe plain scripted path is in install/README.md: install.sh --check, then install.sh, then install.sh --confirm.
Each exit lives in its own network namespace with a single WireGuard interface. A namespace can only reach the internet through its tunnel, so a dead tunnel means no egress for that slot rather than a leak. A dispatcher on NFQUEUE 0 decides which slot a new flow takes: it pins a source to a slot, keeps that flow sticky through a conntrack mark, and skips any slot that warmup has marked unhealthy. DNS gets its own dedicated tunnel so name lookups don't ride the rotating pool and don't fall back to the clear.
A minted exit has to earn its place. Rotation stages the new tunnel in a parallel namespace, waits for the handshake, checks egress, runs a reputation probe (is this IP blocked by the sites people actually use?), and measures throughput against a streaming floor. Only an exit that clears all of that gets promoted; the incumbent keeps serving until its replacement has passed every gate, so a failed candidate never thins the pool. The swap itself is brief: flows caught on that slot reconnect through the fresh exit.
A passphrase-gated web UI on :8443 (TLS, self-signed by the installer) shows what every slot
is doing and exposes the tuning knobs without editing files on the box.
Each card is one exit: which Proton server it landed on, health score, latency, jitter and measured throughput, how long until it rotates, and a button to rotate it now. Below that, the dedicated DNS tunnel, a log of recent swaps and which client is pinned where.
Settings are plain-English rather than environment variables — rotation cadence, quality gates, exit country, ad/tracker blocking, client isolation, and the health checks a candidate exit has to pass before it is allowed to serve traffic.
Health checks are the interesting part. A candidate exit is probed in a throwaway tunnel before
promotion, and a check can assert on page content rather than just an HTTP status — which is the
only way to catch a streaming service that answers 200 from an exit it will not actually serve
video to. Mandatory checks reject the exit; advisory ones are recorded and don't gate.
Screenshots are rendered from synthetic data: exit addresses are RFC 5737 documentation ranges,
client addresses are the project's default RFC 1918 client VLAN (172.16.1.0/24).
The install is the dangerous part. It rewrites the firewall and routing on a box you may only reach over SSH. Proteus assumes that and builds in the recovery.
- Preflight doctor: before anything changes, it checks that you have two NICs, that IP forwarding is available, that no conflicting namespaces exist, and that the SSH session you're on right now sits inside the management subnet the new rules will keep open. If applying the ruleset would lock you out, it refuses and tells you why.
- Auto-reverting apply: the kill-switch and routing go in behind a self-cancelling timer. You open a second SSH session to confirm you still have access; if you can't, you do nothing and the box rolls back to its previous ruleset on its own. Only after you confirm does the install commit.
- The kill-switch itself: the main namespace can talk to RFC1918, its WireGuard peers, the Proton control API, NTP, and apt, and nothing else. Every real flow is forced through a tunnel namespace or dropped.
These guardrails came from getting bitten in testing.
Everything installs under /etc/proteus/ and runs as proteus-* systemd units. The pieces that do the work:
| Component | Job |
|---|---|
dispatcher.py |
NFQUEUE consumer. Per-source pinning, conntrack-backed stickiness, health-aware slot selection. |
rotate-slot.sh |
Mint → stage → handshake → egress → reputation → streaming gate → promote, up to 5 attempts. Old slot stays live until the new one passes. |
proton-mint |
Registers a WireGuard key against a cached Proton session and picks a streaming-friendly US exit. |
slot-warmup.sh |
Keeps each exit's Proton-side flow state warm and scores slots on latency, jitter, and throughput. Triggers an unscheduled rotation for a slot that keeps failing. |
rotate-dns.sh / dns-latency-check.sh |
Run and health-check the dedicated DNS tunnel; re-mint it when the DNS path degrades. |
| nftables kill-switch | Default-drop egress with a narrow allow-list, plus the @vpn_dispatch / @wg_peers / @proton_api sets the dispatcher and rotation maintain. |
Slot N uses fwmark N, routing table 100+N, and transit /30 172.31.N.0/30; the DNS tunnel takes index 99. Dispatch entries reference fwmarks, not endpoints, so routing follows a promotion instantly; established connections on the swapped slot re-emerge from the new exit and reconnect.
- Debian 13 (trixie) or another apt + systemd distro. Debian 13 ships the Proton library (
python3-proton-vpn-api-core) inmain; on other distros the installer adds Proton's official repo. - Two network interfaces: one for management, one facing the client VLAN.
- A Proton VPN account. The one-time login prompts for 2FA; after that, minting is unattended.
- Root on the target. The wizard's
--demoneeds neither root nor an account.
Proteus is an independent project and isn't affiliated with or endorsed by Proton AG. It uses Proton VPN through the same client library Proton's own Linux app uses.





