easywireguard 0.3.0

make wireguard easy - interfaces, keys and full-mesh configs in one CLI + TUI
# easywireguard (`ewg`)

> **Canonical:** [gitlab.com/safteinzz/easywireguard]https://gitlab.com/safteinzz/easywireguard · **Mirror:** [github.com/safteinzz/easywireguard]https://github.com/safteinzz/easywireguard

WireGuard without the hand-editing. A tabbed TUI for humans and a flag-driven CLI
for scripts/agents: manage live interfaces, generate **hub-and-spoke** or full-mesh
configs from one manifest, and onboard devices by QR. Pure Rust — no `wg` binary
needed for keys or generation.

```bash
cargo install easywireguard   # the command you type is the shorter `ewg`
```

## The TUI (just run `ewg`)

Bare `ewg` opens a two-tab toolbox — `h/l ←→` switch tabs, `j/k ↑↓` move:

- **Interfaces** — every `.conf` across your registered dirs; `` brings one up/down,
  `c` creates one in your `$EDITOR` (paste a provider config), `e` edits, `d` deletes it
  (a `.bak` is kept), `b` toggles start-on-boot, `i` inspects it (with live `wg show`
  when up).
- **Mesh** — the nodes in a manifest, shown **hub-and-spoke** (spokes nested under
  their hub). Per node: `c` create, `e` edit, `R` rotate keys, `d` delete, `E` export,
  `` show its QR, `i` view its generated `.conf`.

The **create wizard** (`c`) is two toggles + a few fields (`←/→` flip a toggle,
`ctrl-hjkl`/Tab move between fields):

- **Type: Spoke │ Hub** — a *spoke* is a road-warrior that dials the hub(s) you pick;
  a *hub* is reachable (has an endpoint) and meshes with every other hub.
- **Key: Generate │ Paste***generate* a fresh keypair, or *paste* an existing public
  key (e.g. a router's, whose private lives elsewhere).
  - On **generate** you also choose **store** (keep the private key in the manifest so you
    can re-export a working config later) or **redact** (private only in the QR/file at
    create — the phone case, nothing secret at rest).

**Export** (`E`) offers: write `out/<name>.conf`, install to `/etc/wireguard`, show the
QR, or print the peer entry for an Ansible `wg_peers` list. The QR renders as real
black-on-white cells (scans on any terminal theme) and shrinks to fit. In any text box,
`y` copies to the clipboard (wl-copy/xclip/pbcopy, or an OSC 52 escape over SSH).

## The mesh model

Describe every node once; each node's config is generated as the peers it should reach:

- a **hub** (has an `endpoint`) meshes with every other hub, plus the spokes that point at it;
- a **spoke** (no endpoint) lists only its hub(s) — so phones don't get useless peer
  blocks for each other.

By default a node advertises just its own `/32`. Override with `allowed-ips`: `0.0.0.0/0`
makes a hub a **full-tunnel exit**, a LAN subnet makes it **site-to-site**.

## CLI (scripting / agents)

The TUI wraps these; use them directly to automate.

```bash
# interfaces (this box)
ewg list | status | up <name> | down <name>
ewg dir add <path>            # register where .conf files live (not just /etc/wireguard)

# keys
ewg key | psk | pubkey <PRIVATE>

# mesh: design, then generate "each node's config"
ewg mesh add phone --address 10.10.1.2/24 --pubkey <PUB> --hub flint \
    --dns 192.168.10.250 --keepalive 25 [--private <PRIV>]
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            # list (-v verbose, --json machine-readable; never prints private keys)
ewg mesh rm <name>
ewg mesh gen -o out/                                            # write every node's .conf

# QR (onboard a phone)
ewg qr <name> -m mesh.toml        # QR of that node's generated config
ewg qr out/phone.conf -o phone.png
```

`--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`.
- The manifest (`mesh.toml`) may hold private keys for `store`-mode nodes — treat it as a
  secret (gitignore it); a redacted or public-only manifest is safe to commit.