If you run infrastructure or self-host anything, you know the scenario: a branch office, a colo box, the NAS at home, a roaming laptop, a few ARM boxes stuck behind NAT — and you want them to reach each other as if they were on the same LAN. WireGuard is great, but you wire up peers and routes by hand; n2n is flexible, but you drag along a supernode, TAP, and dynamic discovery. Subnetra takes a more deliberately restrained path, and I'd like to introduce it.
What it is
In one line: a pure-Zig, zero-dependency Layer-3 UDP encrypted tunnel. The build artifact is a single static binary, under 512KB on Linux — no kernel module, no third-party libraries. The entire data plane is the standard library plus raw syscalls.
The topology is the classic hub-and-spoke: one reachable Hub relays traffic between Spokes. Any node can reach any other node at a fixed virtual IP — even when most nodes sit behind NAT. Every packet is encrypted end-to-end inside a plain UDP tunnel, and the whole thing is one file: drop it in, add a config.json, run it.
Architecture coverage is broad: amd64 / arm64 / armv7 / armv5, plus the just-shipped mips / mipsel (OpenWrt routers), and a native macOS Spoke. It fits on cloud VMs, containers, BusyBox, Raspberry Pis, and MikroTik RouterOS (via its container feature).
A few deliberate choices
What's interesting about Subnetra isn't what it does — it's what it deliberately refuses to do:
-
No handshake. It's stateless, with no session negotiation — no Noise handshake, no rekey timer, no roaming handshake. Every packet is authenticated and encrypted with ChaCha20-Poly1305, a unique key per link, with replay protection via a 64-bit monotonic nonce + sliding window. A per-restart "session epoch" is mixed into key derivation, so old captures can't be replayed across restarts. "No handshake" means no negotiation round-trip — not that packets are unauthenticated.
-
Invisible on the wire. There are no magic bytes; a packet that fails authentication is silently dropped, with no error reply. To a port scanner, the port looks like nothing is listening. (It's honest about scope: this is best-effort obfuscation, and it does not claim to beat a serious DPI adversary.)
-
Hub-and-spoke only, no P2P hole punching. This is the opposite of n2n — every Spoke-to-Spoke packet is relayed through the Hub, in exchange for a single, predictable path. There's no failover and no multipath either: those are external decisions (VRRP / health checks / orchestration). The daemon's job is to stay small and predictable.
-
It never touches your host networking. This is one of its iron laws: the daemon only prints the network plan (
--print-network-planemits the exactip/routecommands) and never mutates your routing table or firewall on its own. Whether and how to apply it is a deliberate, auditable decision left to you or your config-management tool. It only manages its own TUN device.
What it's like to use
NAT traversal is built in: Spokes keep their own NAT mapping alive with a built-in keepalive, and the Hub automatically re-learns a Spoke's endpoint when it roams to a new address — no external ping scripts, no manual reconnects. Routing is hot-editable: inject/update forwarding rules at runtime with zero disruption. Config is declarative: mark a node hub or spoke and the forwarding table is derived for you; you can also name peers so status shows bj-office-gw instead of id=2.
It's clearly built with operators in mind: subnetra status gives both human-readable and JSON output, turning packets that are "silently dropped by design" into per-reason drop counters — telling you why traffic isn't flowing — alongside a per-peer online flag and a Prometheus exporter.
Fastest start (the Hub is usually a public cloud VM):
cp config.example.json config.json # one Hub + one or more Spokes
# a unique key per link: openssl rand -hex 32
docker run -d --name subnetra --cap-add=NET_ADMIN --device=/dev/net/tun \
-v "$PWD/config.json":/etc/subnetra/config.json:ro \
ghcr.io/jamiesun/subnetra:latest
docker exec subnetra subnetra status
Prefer a bare binary? Grab your arch from releases, drop a config.json next to it, and run ./subnetrad.
Who it's for
If you want WireGuard's plug-and-play general-purpose client, or n2n's L2 LAN + P2P direct connections, this isn't it. Subnetra targets fixed, operator-managed deployments — where you value a tiny, auditable, topology-deterministic binary and are happy to trade static config for predictability. Site-to-site full-subnet routing, a stable private IP for a roaming laptop, exposing an entire LAN from behind NAT, running on edge boxes too small for a heavy VPN — that's its home turf.
Open source (MIT). Docs: https://jamiesun.github.io/subnetra/ · Repo: GitHub - jamiesun/subnetra: A pure-Zig, zero-dependency Layer-3 UDP tunnel that ships as a single static binary under 200KB. · GitHub . Feedback welcome.