Skip to main content

WGPL (WireGuard Peer Lite) — disconnected CLI for declarative hub-and-spoke IPv4 VPN intent (SQLite SSOT, BYOI).

Project description

WGPL (WireGuard Peer Lite)

CI License: MIT Python 3.12+ Status: Stable

WGPL is a disconnected Python CLI for hub-and-spoke WireGuard (IPv4). You declare routing intent in SQLite (the SSOT); WGPL derives AllowedIPs, allocates addresses, and tracks peer lifecycle and audit.

Hot-reload the hub with zero downtime (wg syncconf) — bring your own OS interface (BYOI). Mutations stay in the database until you apply or remote syncconf.

Compatibility (1.0.x): Follows Semantic Versioning. Patch and minor releases will not break existing CLI commands, flags, or public --json field names. Breaking changes require a new major version (2.0.0).

See it in action

Add a peer. Get a QR. Done.

WGPL quickstart — Ana_Laptop config and QR

More: split tunnel · branch offices · all scenarios · demo/README.md

Start here: Quick Start · Why WGPL · Documentation map

What WGPL is / is not

WGPL is WGPL is not
Declarative hub-and-spoke IPv4 topology manager A network daemon or control plane
Routing intent engine + WireGuard config generator Full-mesh overlay (use Tailscale / Netmaker)
Disconnected CLI; SQLite SSOT A kernel routing or iptables manager
Peer lifecycle, IPAM, append-only audit IPv6 support (IPv4 pools and peers only)
BYOI: you create the OS wg0 (or equivalent) Direct site-to-site P2P without a hub

Architecture and module layers: DESIGN.md.

Quick Start

1. Install

Recommended: Python / uv (Python 3.12+)

uv tool install wgpl
# or: pip install wgpl

Experimental: standalone binaries (Linux / macOS)

Unsigned release artifacts for air-gapped routers or testing. Prefer uv/pip when possible. Verify the checksum from the GitHub Release (<binary_name>.sha256) before running.

Linux (amd64)

curl -sL https://github.com/aleaz/wgpl/releases/latest/download/wgpl-linux-amd64 \
  -o /usr/local/bin/wgpl
# Verify SHA-256 against wgpl-linux-amd64.sha256 from the same release, then:
chmod +x /usr/local/bin/wgpl

macOS (Apple Silicon / arm64)

Download the .tar.gz, verify the checksum, extract, and clear Gatekeeper quarantine:

curl -sL https://github.com/aleaz/wgpl/releases/latest/download/wgpl-macos-arm64.tar.gz \
  -o wgpl-macos-arm64.tar.gz
# Verify SHA-256 against wgpl-macos-arm64.tar.gz.sha256 from the same release, then:
tar -xzf wgpl-macos-arm64.tar.gz
xattr -r -d com.apple.quarantine wgpl-macos-arm64  # Required to bypass macOS Gatekeeper

# You can now run the executable inside the folder:
./wgpl-macos-arm64/wgpl-macos-arm64 --version

# Optional: Link it to your PATH for global access
sudo ln -s $(pwd)/wgpl-macos-arm64/wgpl-macos-arm64 /usr/local/bin/wgpl

[!TIP] The standalone binaries are provided for environments without Python. However, the recommended and fastest way to install WGPL on macOS is via PyPI using uv tool install wgpl or pipx install wgpl.

2. Bring your own hub interface (BYOI)

WGPL does not create the OS WireGuard netdev. Create wg0 (or equivalent) first, then copy its public key for interface add.

# Minimal hub: [Interface] with PrivateKey, Address (e.g. 10.0.0.1/24), ListenPort
sudo systemctl enable --now wg-quick@wg0
sudo wg show wg0 public-key   # <WG0_PUBKEY> below

If wgpl apply later fails because the OS interface does not exist, finish this step first — see docs/runbook.md — Troubleshooting.

3. Pin the database and register a hub

Pin a database path so sudo apply and non-root mutations share the same SSOT:

export WGPL_DB_PATH="$HOME/.wgpl.db"
# or pass --db "$HOME/.wgpl.db" on every command

A WGPL hub is the database record for one VPN domain (you may name it wg0 to match your OS interface).

# Register the hub: name, server endpoint host, hub public key, address pool
# Add --port N if the hub does not listen on the default 51820
wgpl interface add wg0 vpn.example.com <WG0_PUBKEY> 10.0.0.0/24

# Attach a Node (default policy: vpn_only). Positional name find-or-creates it.
wgpl peer add "Alice_Laptop" -i wg0
wgpl peer list
Term Meaning
Server endpoint Host (and port) where clients connect — e.g. vpn.example.com in interface add
peer.role = endpoint An end-user device (laptop/phone), not the server endpoint hostname

Client AllowedIPs default to vpn_only. Policies and overrides: docs/routing.md.

4. Validate, apply, inspect, and distribute

Canonical flow: validate → apply → explain → distribute.

wgpl validate wg0
sudo --preserve-env=WGPL_DB_PATH wgpl apply wg0
# equivalent: sudo wgpl --db "$HOME/.wgpl.db" apply wg0

wgpl peer list                  # copy the peer ID (or unique hex prefix) from the ID column
wgpl peer explain <PEER_ID>
wgpl peer qr <PEER_ID>
wgpl peer config <PEER_ID> > alice.conf
chmod 600 alice.conf

<PEER_ID> is a peer UUID or hex prefix from peer list (not the node name). Multi-hub DBs need -i on secret-bearing commands — docs/cli.md.

Install on the end-user device: docs/runbook.md — Client provisioning.

Demos

Offline VHS recordings (admin laptop — no local apply). Regenerate with cd demo && make all. Details: demo/README.md.

Demo What it shows
01 Quickstart Peer + client config + QR
02 Split tunnel Cloud VPC via split_tunnel + peer explain
03 Branch offices NY ↔ London subnet_router AllowedIPs matrix
04 Mixed topology Laptops + three branches + validate --strict
05 Remote sync interface export | ssh … wg syncconf

Why WGPL

Replaces hand-edited AllowedIPs and hub restarts with declared routing intent and zero-downtime wg syncconf.

vs wg-quick (manual config files)

Feature wg-quick (manual) wgpl
Peer storage / IPAM Text files; manual IPs SQLite + automatic CIDR IPAM
Routing / AllowedIPs Manual per peer in .conf Declared routing intent; derived at emit
Applying changes Restarts interface (drops connections) Zero-downtime hot-reload (wg syncconf)
Audit / TTL / verify None / manual Append-only audit, --expires, validate + routing matrix

Fit / not a fit

You keep keys, backups, and hub relay; you run apply and OS forwarding yourself — not a mesh control plane.

  • Full-mesh or managed overlay — Tailscale, Netmaker, or similar (WGPL targets one hub per VPN domain, not P2P mesh).
  • Direct site-to-site without a hubOut of scope. Configure WireGuard manually, or use peer config --allowed-ips for a one-off export override.
  • Site-to-site via a central hubIn scope. Two subnet_router peers; LAN↔LAN through the concentrator. See docs/routing.md — Site-to-site.

Concepts

WGPL models hub-and-spoke routing intent in SQLite — not WireGuard text files. WireGuard ([Interface], [Peer], AllowedIPs) is an emit format produced at apply / export time.

  Node          Peer              Interface
 (who)   →   (attachment)   →   (hub / VPN domain)
Concept Meaning
Node Who — global device identity (wgpl node); rename with node update (peer update has no --name)
Peer How — attachment to one hub (keys, IP, routing intent, lifecycle)
Interface Where — WGPL hub for one VPN domain (pool, server endpoint, optional hub routes)

Full domain table and identity rules: DESIGN.md — Domain model.

Mutations never touch the kernel until you validate and emit:

SQLite intent  →  validate  →  emit
                              ├─ apply / interface export   (hub)
                              └─ peer config / QR           (client)
  • Mutate writes the database only; it does not touch WireGuard.
  • Emit (apply, export, config, QR) derives routes, validates, then writes WireGuard text or JSON.
  • wgpl apply fails closed if the database fails consistency checks.

Module-level emit gate and layering: DESIGN.md.

Routing

Declare role, routed_networks, and allowed_ips_policy on hubs and peers. WGPL derives AllowedIPs at emit time; hub packet relay (ip_forward, firewall) stays with the operator — docs/runbook.md — Hub routing relay.

Policy Client AllowedIPs (summary)
vpn_only (default) VPN address pool only
split_tunnel Pool + interface.routed_networks
all_remote_networks Split set + other sites' LANs
full_tunnel 0.0.0.0/0
custom peer.custom_allowed_ips

Eight hub-and-spoke patterns, glossary, LAN↔LAN, and invariants: docs/routing.md. Executable topology spec: docs/routing_matrix.md. Inspect with wgpl peer explain <PEER_ID> (UUID or hex prefix from peer list).

Day-2 ops (validate/apply, TTL, prune, backup, deploy, client OS): docs/runbook.md.

Highlights

  • Composite identity: Hub names may repeat across servers; hubs are keyed by name + server endpoint + port. Use the numeric interface ID from wgpl interface list when names collide.
  • Global IPAM within each hub CIDR; idempotent wgpl apply (deltas only).
  • Node identity via wgpl node; the same Node can attach to several hubs.
  • TTL and cleanup: --expires, soft delete, and prune — runbook.
  • Fail-closed emit/apply/restore; chmod 600 on DB and sensitive outputs; append-only audit (no secrets in metadata) — SECURITY.md.
  • --json for automation — stdout contract: docs/cli.md.
  • Wire-safe MTU (minimum 1280 or unset); server endpoints RFC 1123 (IPv4/hostname; IPv6 endpoints rejected).
  • BYOI deploy: systemd, remote syncconf, Docker, MikroTik — runbook — Deployment.

Integrations

Copy-paste starting points in examples/:

Configuration

Pin the DB when using sudo apply so root and your user share the same SSOT.

Variable Description Default
WGPL_DB_PATH Path to the SQLite database (also settable with global --db) ~/.wgpl.db
WGPL_WG_BIN Path to wg for apply / syncconf (ignored when UID 0; defaults to /usr/bin/wg) wg (PATH)
WGPL_EXEC_CMD Optional audit metadata: the CLI command that triggered the mutation (sanitized, bounded) (unset)

wireguard-tools (wg) is required only for wgpl apply on the same machine. Full CLI: wgpl --help or docs/cli.md. Docker image ghcr.io/aleaz/wgpl and DB permissions: runbook — Docker, Environment and permissions.

Documentation map

Document Contents
DESIGN.md Domain model, layered architecture, security boundaries
docs/routing.md Routing model, patterns, scope, invariants
docs/routing_matrix.md Executable topology spec (valid / invalid)
docs/runbook.md Production procedures (validate, apply, hub relay, deploy, client OS, backup, compliance)
docs/cli.md Full CLI reference
SECURITY.md Threat model and security policies
CONTRIBUTING.md Development workflow and commit conventions
MAINTAINERS.md Maintainer ownership
CHANGELOG.md Release history
CODE_OF_CONDUCT.md Community conduct

Contributing

git clone https://github.com/aleaz/wgpl.git
cd wgpl
uv sync --dev
uv tool run pre-commit install
uv run pytest

Please read CONTRIBUTING.md before opening a pull request.

Author

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wgpl-1.0.2.tar.gz (3.3 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

wgpl-1.0.2-py3-none-any.whl (69.7 kB view details)

Uploaded Python 3

File details

Details for the file wgpl-1.0.2.tar.gz.

File metadata

  • Download URL: wgpl-1.0.2.tar.gz
  • Upload date:
  • Size: 3.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for wgpl-1.0.2.tar.gz
Algorithm Hash digest
SHA256 c76fca13076f724a11213e8cb017fb0d16af4800ff89cb743853086a85f59960
MD5 e06d9bef7e579c50b044cc32e8299f30
BLAKE2b-256 8742b86352b3eed262ae1c1e1ed68a514e69654bd620b2543395de658e60936f

See more details on using hashes here.

Provenance

The following attestation bundles were made for wgpl-1.0.2.tar.gz:

Publisher: release.yml on aleaz/wgpl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file wgpl-1.0.2-py3-none-any.whl.

File metadata

  • Download URL: wgpl-1.0.2-py3-none-any.whl
  • Upload date:
  • Size: 69.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for wgpl-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 4a1fbf2de1beefc97665f4a0d23b55c9cd8df27ea53e1d45f46467fa50126a82
MD5 5b9ba92539df8ba6c0fc6b7a1b902023
BLAKE2b-256 a21cbd62120f68040ae890c575d841898eebef55fd0911b7a2f26a89da7998bd

See more details on using hashes here.

Provenance

The following attestation bundles were made for wgpl-1.0.2-py3-none-any.whl:

Publisher: release.yml on aleaz/wgpl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page