easywireguard 0.5.1

mesh, minus the mess - interfaces, keys and full-mesh configs in one CLI + TUI
easywireguard-0.5.1 is not a library.

easywireguard (ewg)

Canonical: gitlab.com/safteinzz/easywireguard · Mirror: github.com/safteinzz/easywireguard

mesh, minus the mess - interfaces, keys and full-mesh configs in one CLI + TUI

Install

cargo install easywireguard   # the command you type is the shorter `ewg`
ewg self update               # reinstall the latest release later on

A tour of ewg: inspecting a running interface, toggling one up and down, browsing the mesh, creating a node with a generated keypair, exporting it as an Ansible entry, deleting it, and generating every node's config

Manage every interface

Bare ewg opens on the interface manager: every .conf across the dirs you registered, with what it is doing right now. ● up is running, ○ down is stopped, ⏻ boot starts with the machine.

The interface manager listing five WireGuard configs, two of them up and two flagged to start at boot, with the action keys along the bottom

Tell whether it is actually working

i shows the config, and for a running interface a live wg show under it: the peer, the last handshake, the bytes moved.

The inspector over the interface list, showing a config followed by a live wg show readout with a handshake a minute old and transfer counters

See the whole mesh

Describe each node once and ewg lays them out hub-and-spoke, spokes nested under the hub they dial. A hub has an endpoint and meshes with every other hub; a spoke has none and lists only its hub, so phones never get useless peer blocks for each other.

The Mesh tab showing two hubs with their spokes nested underneath, each row with its mesh IP and endpoint

By default a node advertises just its own /32. Set allowed-ips to 0.0.0.0/0 to make a hub a full-tunnel exit, or to a LAN subnet for site-to-site.

Create a node without touching a key

c opens a wizard: pick Spoke or Hub, fill a couple of fields, and the keypair is generated for you. store keeps the private key in the manifest so you can re-export a working config later; redact leaves it only in the QR and file handed out at create, nothing secret at rest.

The node wizard with a Spoke/Hub toggle and fields for name, address, DNS, the hub to dial, and where the private key goes

Onboard a phone by scanning

on a node renders its config as a black-on-white QR that scans on any terminal theme. Open the WireGuard app, scan, done - no file transfer. E exports the same config as out/<name>.conf, an install to /etc/wireguard, a PNG, or an Ansible peer entry.

A scannable QR code of a node's generated config, over the mesh list, titled scan phone

Keys

key Interfaces Mesh
j/k ↑↓ move move
h/l ←→ tab switch tab switch tab
toggle up / down show the QR
c new config in $EDITOR create a node
e edit it in $EDITOR edit the node
d delete (keeps a .bak) remove from the manifest
i inspect, with live wg show view the generated config
b toggle start-on-boot
R rotate the keypair
E export (file, install, QR, Ansible)
g generate every node's config
r refresh reload the manifest
q esc quit quit

A config pasted into $EDITOR is validated before it lands, so a truncated paste is caught there rather than at wg-quick up.

CLI

The TUI wraps these; call them directly to automate.

# interfaces
ewg list | status | up <name> | down <name>
ewg dir add <path>                 # register where .conf files live (not just /etc/wireguard)
ewg check /etc/wireguard/*.conf    # validate configs, non-zero exit if any is broken

# keys
ewg key | psk | pubkey <PRIVATE>

# mesh: design, then generate each node's config
ewg mesh add flint --address 10.10.1.1/24 --pubkey <PUB> \
    --endpoint vpn.example.com:51820 --allowed-ips 0.0.0.0/0     # a hub / exit
ewg mesh add phone --address 10.10.1.3/24 --pubkey <PUB> \
    --hub flint --dns 192.168.10.250 --keepalive 25 [--private <PRIV>]
ewg mesh                           # list (-v verbose, --json; never prints private keys)
ewg mesh rm <name>
ewg mesh gen -o out/               # write every node's .conf

# QR (onboard a phone)
ewg qr <node> -m mesh.toml         # QR of that node's generated config
ewg qr out/phone.conf -o phone.png # a .conf file, also written as a PNG

# the tool itself
ewg self check | self update

--hub (repeatable) makes a node a spoke of those hubs; omit it and a spoke reaches all hubs. --private is optional: omit it for a public-only manifest and inject keys later.

Notes

  • Reading /etc/wireguard needs root; ewg auto-elevates with sudo (disable with EWG_NO_SUDO=1). Point elsewhere with --dir or $EWG_DIR.
  • mesh.toml may hold private keys for store-mode nodes, so treat it as a secret and gitignore it; a redacted or public-only manifest is safe to commit. mesh list --json never prints private keys.
  • The Mesh tab reads mesh.toml from the directory you run ewg in, and g writes to ./out beside it.
  • Start-on-boot uses systemd (wg-quick@<name>); toggling interfaces shells out to your wg-quick. Keys and config generation are pure Rust, never a wrapper around wg.

License

AGPL-3.0-only.