v0.3.2 March 27, 2026 GPL-3.0-or-later macOS and Linux
A WireGuard tunnel, built again in Rust.
IronGuard is a from-scratch WireGuard implementation. Homebrew installs the tunnel and a manager. You describe the interface in wg.json, then bring it up.
Cross-section of the tunnel. The ruler is the 16-byte v2 frame header. The block on the wire is one frame.
- type 1
- flags 1
- reserved 2
- receiver 4
- counter 8
brew tap dickwu/tap
brew install ironguard
Same formula, one command.
brew install dickwu/tap/ironguard
- ironguardThe tunnel. Keys, validate, up, down, status, import, export.
- ironguard-tuiThe manager. A dashboard, or setup and client commands.
- macOS and Linuxutun on macOS. TUN on Linux. Four prebuilt archives.
- GPL-3.0-or-laterFormula version 0.3.2, released March 27, 2026.
Bring a tunnel up
Do these in order. The commands are the ones in the repository README and the Homebrew tap.
-
Install both binaries
Tap
dickwu/tap, then installironguard. The formula putsironguardandironguard-tuion your PATH.brew tap dickwu/tapbrew install ironguard -
Make a key pair
genkeyprints a private key.pubkeyreads a private key on stdin and prints the public key.genpskprints a pre-shared key.ironguard genkey > private.keyironguard pubkey < private.key -
Write wg.json
Point
private_key_fileat the key, set an address, and add peers. The file has to be JSON. Comments are not allowed. A full example is below. Validate it before you open a device.ironguard validate wg.json -
Bring the interface up
This is the command from the tap README.
utun9is the interface name in that example, and it has to be a key in yourwg.json. On Linux the key is whatever you named the interface, such aswg0in the TUI setup example. Creating the TUN device needs root. If you are not root,ironguard upre-runs itself with sudo.ironguard down utun9stops that interface.ironguard statuslists what the file configures.sudo ironguard up utun9 --config wg.json --foreground
Or let the manager build the server
Run ironguard-tui with no arguments for the dashboard. The README's non-interactive example is the three commands below. setup detects Linux or macOS, writes /etc/ironguard/wg.json, generates keys under /etc/ironguard/keys/, and registers systemd or launchd. client create makes a key pair, picks the next address from 10.0.0.2, and adds the peer. Run restart after you add or remove a client.
sudo ironguard-tui setup
sudo ironguard-tui client create laptop --endpoint=vpn.example.com:51820
sudo ironguard-tui start
On the wire
Taken from the v0.3.2 sources, the repository README, and the Homebrew formula. The schema tables live in the README.
- Frame
- 16-byte v2 header: type, flags, reserved, receiver id, counter. In the source the type byte starts at 0x04 for data, then 0x05 keepalive, 0x06 control, and 0x07 batch, so the header can share the wire with older handshake messages.
- AEAD
- AES-256-GCM through ring. The project README reports 2.5 to 3.6 times the speed of ChaCha20-Poly1305 on AES-NI hardware.
- Keys
- X25519 for key exchange. HKDF-SHA256 derives epoch keys. Private key material is zeroed on drop.
- Routing
- Crypto-key routing with longest-prefix match tables for IPv4 and IPv6. Anti-replay is an RFC 6479 window of 2048 bits. Each peer has five timers.
- QUIC
- A Cargo feature, compiled into the release binaries. The README says tunnel packets can ride inside QUIC on networks that block UDP: unreliable datagrams first, length-prefixed streams if datagrams are unavailable.
quic.modeishandshake_only(the schema default) orfull_transport. The handshake port isquic.port, or the listen port plus one.ironguard gen-quic-certwrites an mTLS certificate. - Pipeline
- Tokio workers batch TUN and UDP I/O. A batch flushes on count, size, or timeout. The buffer pool has two tiers: 8192 buffers of 2 KB and 128 of 64 KB. Each peer has a reorder buffer.
- Systems
- macOS uses utun,
sendmsg_x/recvmsg_x, and kernel buffer tuning. Linux uses a TUN device,sendmmsg/recvmmsg, and GSO/GRO. The formula publishes archives for macOS Apple Silicon, macOS Intel, Linux x86_64, and Linux ARM64. - NAT
- The README’s connectivity crate does STUN binding requests, coordinated UDP hole punching, a birthday-paradox spray for symmetric NAT, UPnP port mapping, mDNS on the LAN, and a QUIC relay.
- Config
wg.jsonholds interfaces, addresses, peers, DNS names in endpoints, masquerade, andpost_up/post_downhooks. A peer can carry allowed IPs, a keepalive, a pre-shared key file, and an ACL of destination CIDRs.ironguard importandironguard exportconvert standard WireGuard.conffiles.- Post-quantum
- The schema has
post_quantumset tofalse,true, orstrict, and a per-peerpq_public_keydocumented as an ML-KEM-768 public key. The Homebrew tap describes that cryptography as optional and feature-gated.
A wg.json file
The example from the repository README. The public key there is a placeholder. Secrets stay in private.key, not in the JSON.
wg.json
{
"$schema": "ironguard/v1",
"interfaces": {
"utun9": {
"private_key_file": "./private.key",
"listen_port": 51820,
"address": ["10.0.0.1/24"],
"mtu": 1420,
"quic": {
"port": 51821,
"sni": "vpn.example.com"
},
"peers": [
{
"public_key": "abc123...",
"endpoint": "vpn.example.com:51820",
"allowed_ips": ["10.0.0.2/32"],
"persistent_keepalive": 25
}
]
}
}
}
Keys load from a file or an environment variable, hex or base64. More fields, including DNS, fwmark, and per-peer ACLs, are in the README. Sample files are in configs/.
Without Homebrew
The formula installs the v0.3.2 archives. You can fetch those same files, or build the workspace.
Each archive contains ironguard and ironguard-tui. After it unpacks, move both binaries onto your PATH: sudo mv ironguard ironguard-tui /usr/local/bin/.
curl -sL https://github.com/dickwu/ironguard/releases/download/v0.3.2/ironguard-macos-aarch64.tar.gz | tar xz
curl -sL https://github.com/dickwu/ironguard/releases/download/v0.3.2/ironguard-macos-x86_64.tar.gz | tar xz
curl -sL https://github.com/dickwu/ironguard/releases/download/v0.3.2/ironguard-linux-x86_64.tar.gz | tar xz
curl -sL https://github.com/dickwu/ironguard/releases/download/v0.3.2/ironguard-linux-aarch64.tar.gz | tar xz
The workspace asks for Rust 1.85. cargo build --workspace --release builds the tunnel and the manager. The two cargo install lines put them in ~/.cargo/bin/.
git clone https://github.com/dickwu/ironguard.git
cargo build --workspace --release
cargo install --path crates/ironguard-cli
cargo install --path crates/ironguard-tui
Questions
Something missing belongs in the issue tracker.
What is IronGuard?
IronGuard is a from-scratch WireGuard implementation in Rust. The tunnel binary is ironguard. The manager is ironguard-tui. Configuration is a JSON file named wg.json. It runs on macOS and Linux.
How do I install it with Homebrew?
Run brew tap dickwu/tap, then brew install ironguard. The formula installs both ironguard and ironguard-tui. brew install dickwu/tap/ironguard is the same formula in one command.
Which systems have prebuilt binaries?
The Homebrew formula ships macOS Apple Silicon, macOS Intel, Linux x86_64, and Linux ARM64. The formula version is 0.3.2, released March 27, 2026. The license is GPL-3.0-or-later.
How do I bring a tunnel up?
Write a private key with ironguard genkey, derive the public key with ironguard pubkey, and put the path to the private key in wg.json. Then run sudo ironguard up utun9 --config wg.json --foreground. Creating the TUN device needs root. If you are not root, ironguard up re-runs itself with sudo.
Can it read a standard WireGuard conf file?
Yes. ironguard import reads a .conf file and writes wg.json. ironguard export writes one interface from wg.json back to .conf.
How does QUIC use ports?
QUIC is a Cargo feature, and the release builds include it. The handshake port is quic.port when that field is set, otherwise the listen port plus one. The client connects to the peer endpoint port plus one, and both ports have to be reachable. The README says QUIC prefers unreliable datagrams and falls back to streams.
What does ironguard-tui do?
With no arguments it opens a dashboard of status, peers, and logs. Subcommands cover setup, client create, start, stop, restart, status, logs, peers, and server-key. setup registers systemd on Linux or launchd on macOS, writes /etc/ironguard/wg.json, and generates keys under /etc/ironguard/keys/.
Where is the source?
The formula homepage and the source repository are https://github.com/dickwu/ironguard. This page is part of the LifeFarmer catalog at https://lifefarmer.ca.
Install IronGuard
Two commands. Both binaries. Then a JSON file and an interface name.
brew tap dickwu/tap
brew install ironguard