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 VPN topologies. You declare routing intent in SQLite (the single source of truth); WGPL derives WireGuard AllowedIPs, allocates IPv4 addresses, tracks peer lifecycle and audit, and applies hub changes with zero downtime (wg syncconf). Bring your own OS interface (BYOI) — no more hand-picking free IPs or restarting the hub to add a peer. The kernel stays unchanged until you apply or remote syncconf.

Compatibility (1.0.x): Once 1.0.0 is released, the 1.0.x line follows Semantic Versioning. Patch and minor releases in 1.0.x will not break existing CLI commands, flags, or public --json field names. Breaking CLI or JSON changes require a new major version (2.0.0).

Start here: Quick Start · docs/routing.md · 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 Linux binary

Unsigned release artifact for air-gapped routers. Prefer uv/pip when possible. Verify the checksum from the GitHub Release (SHA256SUMS) before running.

curl -sL https://github.com/aleaz/wgpl/releases/latest/download/wgpl-linux-amd64 \
  -o /usr/local/bin/wgpl
# Verify SHA-256 against SHA256SUMS from the same release, then:
chmod +x /usr/local/bin/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
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 hub hostname

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

# 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 device (default policy: vpn_only). Positional name find-or-creates the Node.
wgpl peer add "Alice_Laptop" -i wg0
wgpl peer list

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 unique hex prefix from peer list (not the node name — use wgpl node for device identity / rename). With more than one WGPL interface, pass -i on secret-bearing commands — docs/cli.md.

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

Why WGPL

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 intent; derived at export
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 a declarative hub-and-spoke VPN topology, not WireGuard text files. WireGuard ([Interface], [Peer], AllowedIPs) is an export format produced at apply/export time.

Node (identity)  →  Peer (attachment)  →  Interface (hub / VPN domain)
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 — hub record for one VPN domain (pool, endpoint, optional hub routes)

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

Mutations never touch the kernel until you apply or export:

Intent (SQLite)  →  validate  →  apply / export / peer config / QR
  • Mutations write the database only; they do not touch WireGuard.
  • Apply / export derives routes, validates, then emits text for wg syncconf, client .conf, QR, 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 interfaces and peers. WGPL derives AllowedIPs at export; 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: Interface 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).
  • Device identity via wgpl node; the same device 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.
  • Strict --json for automation (including derived hub_allowed_ips / client_allowed_ips): resource payloads use {"status":"success","data":…} on stdout; domain errors use {"status":"error","message":…} on stdout with human hints on stderr. Use jq '.data' / .data[] for resources.
  • 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

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 ruff check src/ tests/
uv run mypy src/ tests/
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.1.tar.gz (216.7 kB 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.1-py3-none-any.whl (69.2 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for wgpl-1.0.1.tar.gz
Algorithm Hash digest
SHA256 21196c593471cfdb6167870b76a911be7455d306d129e0e647f986e1713e6cdc
MD5 df0eedf0b6847304ce5b32c7553f65b5
BLAKE2b-256 026223c94be6839b263a2c37b24b8c79b209316db2cf27594dd492cbe719992c

See more details on using hashes here.

Provenance

The following attestation bundles were made for wgpl-1.0.1.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.1-py3-none-any.whl.

File metadata

  • Download URL: wgpl-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 69.2 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 3b996e4516163d3f190cbc71d82f8a1a1a5a3c9c7b9dd08521507fe1f34343bd
MD5 862a82b1aab4e42b10efe331c1fffd45
BLAKE2b-256 4e7451c7ccba2dbcaf20b0494eae2ba3cea026a333bb289ea61b4518652cda55

See more details on using hashes here.

Provenance

The following attestation bundles were made for wgpl-1.0.1-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