Documentation

Shireguard builds private WireGuard mesh networks. Each device gets a stable private IP, peers connect directly when they can, and fall back to an encrypted relay when they can't.

Installation

Shireguard runs on macOS and Linux. The daemon manages the WireGuard interface; the menu bar app (macOS) gives you one-click connect/disconnect.

macOS (Homebrew)

brew install doppiscantsleep/shireguard/shireguard

Linux (curl installer)

curl -sSL https://shireguard.com/install.sh | bash

After installation the shireguard binary is on your PATH. No kernel modules, no root required at runtime — WireGuard runs entirely in userspace.

Sign In

Sign in with Apple, Google, or GitHub. The CLI opens a browser window for OAuth and polls for the token — no local callback server needed.

shireguard login

This saves a session token in ~/.shireguard/config.json. You can also sign in via the web dashboard at shireguard.com.

Create a Network

A shirenet is a private network with its own CIDR block. Every device that joins gets a stable IP in that range.

shireguard networks create --name "homelab"

The default CIDR is 100.65.0.0/16, giving up to 65 533 device addresses. You can specify a custom CIDR with --cidr. You can also create networks from the dashboard.

Connect a Device

1
Register the device — generates a WireGuard key pair, registers the public key with the control plane, and receives an assigned IP.
shireguard up --network homelab
2
The daemon starts and brings up a WireGuard interface (e.g. utun8 on macOS). It syncs peers from the control plane every 30 s.
3
Peers appear automatically. Any other device connected to the same network will show up as a WireGuard peer. Connectivity is attempted directly first, with relay as fallback.
4
Disconnect with shireguard down. The interface is torn down and the daemon exits.
On macOS, the menu bar app handles connect/disconnect with a single click and shows your assigned IP inline.

Networks

A network (shirenet) is the top-level grouping. It has:

  • A name — human-readable label
  • A CIDR — the IP range for all devices in this network (default 100.65.0.0/16)
  • An owner — the user who created it
  • Optional members — other users invited to join

Devices in the same network can reach each other using their assigned private IPs. Traffic never leaves the WireGuard tunnel — the control plane only stores public keys and endpoint hints; it never sees packet contents.

You can have multiple networks — for example, homelab, team-dev, and offsite-backup can all coexist independently.

Devices

A device is any machine running the Shireguard daemon. Each device has:

  • A WireGuard key pair — generated locally, private key never leaves the device
  • An assigned IP — stable address within the network CIDR, allocated by the control plane
  • A platformmacos, linux, or raspberrypi
  • An endpoint — the last-known public IP:port, updated by heartbeat every 30 s
  • A relay slot — optional relay host and port used as fallback when direct connection fails

Multiple devices can be registered to the same network by the same user, or by different users who are members of that network. Each member's devices join the mesh as peers to everyone else in the network.

Devices are identified by their public key, which is globally unique. If you run shireguard up on a machine that already has a registered key, it reconnects to the existing device record.

Members & Roles

Networks support three roles:

RoleWhoCapabilities
Owner The user who created the network Full control: invite, remove anyone, change roles, delete network
Admin Elevated member, promoted by owner Generate invite links (member-only), remove members, view member list
Member Standard joined user Register devices to the network, see peers, connect

Role permissions matrix

ActionOwnerAdminMember
Register devices
View peers
View member list
Generate invite links
Invite as admin
Remove members✓ (non-admins)
Change roles
Delete network

Invite Links

Owners and admins can generate shareable invite links from the dashboard. Each invite has:

  • Role — the role the invited user will receive (member or admin, owner-only)
  • Max uses — how many people can claim the invite (1, 5, 10, or unlimited)
  • Expiry — 24 h, 7 days, or 30 days

An invite link looks like: https://shireguard.com/?invite=<token>

When someone clicks the link they land on the Shireguard home page. The token is saved to sessionStorage so it survives the OAuth redirect. After they sign in, the invite is automatically accepted and they join the network with the specified role. If they were already a member, the accept is a no-op.

Invites can be revoked at any time from the dashboard. Expired or fully-used invites are automatically ignored.

WireGuard

WireGuard is the VPN protocol underlying Shireguard. It uses modern cryptography — Curve25519 for key exchange, ChaCha20-Poly1305 for symmetric encryption, and BLAKE2s for hashing — with a deliberately minimal codebase (~4 000 lines vs. OpenVPN's ~100 000+).

Key properties relevant to Shireguard:

  • Identity = public key. Each peer is identified by its 32-byte public key. The control plane stores these and distributes them to every device in the network.
  • Roaming. WireGuard peers track each other's endpoints and update automatically when an IP or port changes — useful when devices move between networks.
  • Userspace. Shireguard uses wireguard-go, a pure-Go implementation that runs without kernel modules. This means it works on any macOS or Linux without elevated privileges at runtime (only initial setup requires brief sudo for the utun interface).
  • Silence. WireGuard only sends traffic when there is data to send. Peers that aren't communicating generate no keepalive load — Shireguard adds its own lightweight keepalive just to maintain NAT mappings.

STUN & NAT

Most devices sit behind a NAT (Network Address Translator) — a router that maps many private IPs to one public IP. The problem: two NATted devices can't connect directly because neither knows the other's real public endpoint.

What STUN does

STUN (Session Traversal Utilities for NAT) is a protocol that lets a device discover its own public IP and port as seen by the outside world. Shireguard queries a STUN server (Google's stun.l.google.com:19302 with Cloudflare as fallback) during startup to learn its external endpoint, then registers that endpoint with the control plane.

Your device
→ STUN query →
STUN server
← your public IP:port ←
Your device
→ register →
Control plane

NAT types

Not all NATs behave the same:

  • Full-cone / port-restricted NAT — most home routers. Two devices can hole-punch: both send a UDP packet to each other's public endpoint simultaneously, which opens a path through each router. WireGuard then flows directly peer-to-peer.
  • Symmetric NAT — common on corporate networks and some mobile carriers. The NAT assigns a different external port for every destination, so hole-punching fails. The relay takes over in this case.
Shireguard attempts direct connection first. If no handshake completes within ~15 seconds, it falls back to the relay automatically — no manual configuration needed.

Relay Fallback

When two devices can't punch through their NATs, Shireguard uses a UDP relay running on a public server (AWS Lightsail). The relay is dumb on purpose — it doesn't terminate TLS or decrypt anything. It just forwards UDP packets between two registered slots.

How the relay works

1
Registration. Each device's daemon registers with the relay over HTTP (:8080), claiming a slot and providing its desired WireGuard port.
2
Local proxy. The daemon starts a local UDP proxy on a random port. WireGuard's outbound traffic is routed through this proxy, which maintains a single persistent UDP socket to the relay.
3
Keepalives. The proxy sends a lightweight keepalive UDP packet to the relay every few seconds. This keeps the NAT mapping alive — the relay learns the device's current public IP:port from the source address of these packets.
4
Forwarding. When device A sends WireGuard traffic, the relay looks up device B's registered endpoint and forwards the packet. B's relay proxy receives it and injects it into B's local WireGuard interface. B's reply takes the same path back.
WireGuard's encryption is end-to-end. The relay server sees only ciphertext — it has no keys and cannot read or modify packet contents.

Reconnection & backoff

If the relay proxy dies (network change, server restart), the daemon detects it and attempts reconnection with exponential backoff: 5 s → 10 s → 20 s. After three failures it clears the relay fallback and logs a warning. If direct connectivity has since become possible, WireGuard will use it instead.

Full Connection Flow

Here's what happens end-to-end when you run shireguard up:

1
Key generation. A WireGuard key pair is generated locally if one doesn't exist. Private key stays on device.
2
STUN probe. The daemon queries a STUN server to discover its public endpoint.
3
Registration. Public key + STUN endpoint sent to the control plane. An assigned IP in the network CIDR is returned.
4
Relay setup. Daemon registers a relay slot. Starts the local UDP proxy and begins sending keepalives.
5
Interface up. WireGuard utun interface created with the assigned IP. Peer list populated from the control plane.
6
Peer sync. Every 30 s the daemon polls /v1/networks/:id/peers and updates WireGuard's peer list. New devices appear automatically; departed devices are removed.
7
Heartbeat. Every 30 s the daemon posts its current endpoint to the control plane so peers can find it. Interval doubles on failure, capped at 5 min, resets on success.
8
Connection attempt. WireGuard tries a handshake with each peer using the direct endpoint first. If that fails, the peer's relay host:port is set as the endpoint and WireGuard retries through the relay.
Device A
↔ direct (preferred)
Device B
Device A
→ proxy →
Relay
Device B
(fallback, still E2E encrypted)