bartei/wiregui

Firezone Inspired Wireguard VPN Server and nftables Firewall

76

stars

54

commits

Python

primary language

Aug 19, 2026

updated

bartei.github.io/wiregui
nftables
nicegui
vpn
wireguard

README

WireGUI

A self-hosted WireGuard VPN management platform built with Python, NiceGUI, and PostgreSQL.

WireGUI gives you a clean web interface for managing WireGuard peers, firewall rules, and user authentication -- without depending on any third-party cloud service. It's designed for teams and individuals who want full control over their VPN infrastructure.

Against enshittification

This project exists because we believe infrastructure software should serve its users, not its investors. Too many open-source VPN tools have been enshittified -- features locked behind paid tiers, telemetry quietly added, self-hosting made deliberately painful to push you toward a managed offering.

WireGUI is AGPL-licensed specifically to prevent this. If you run it, you own it. If you modify it and offer it as a service, you share the source. No bait-and-switch, no open-core grift, no "community edition" that mysteriously lacks the features you actually need.

Software that manages your network traffic should be fully transparent and fully yours.

Screenshots

DevicesAccount Settings
DevicesAccount Settings
User ManagementFirewall Rules
User ManagementFirewall Rules
Settings & SSO
Settings

See the wiki for full documentation with more screenshots.

Features

  • WireGuard management -- create/delete peers, automatic IP allocation (IPv4 + IPv6), QR codes and .conf downloads
  • Firewall rules -- per-user nftables chains with CIDR, protocol, and port range support
  • Multi-factor auth -- TOTP authenticator apps and WebAuthn security keys
  • SSO -- OpenID Connect and SAML identity providers with auto-provisioning
  • Magic links -- passwordless email login
  • API tokens -- programmatic access via REST API (/api/v0)
  • Dark/light theme -- user preference stored in profile, auto mode follows system
  • VPN session management -- configurable session duration with automatic peer expiry
  • Real-time stats -- live RX/TX counters and handshake tracking
  • Diagnostics -- WAN connectivity checks, peer status, system notifications

Tech stack

LayerTechnology
UINiceGUI (reactive server-side, WebSocket)
APIFastAPI (built into NiceGUI)
ORMSQLModel (SQLAlchemy + Pydantic)
DatabasePostgreSQL (asyncpg)
CacheValkey (Redis-compatible)
MigrationsAlembic
Authauthlib, python-jose, pyotp, webauthn, bcrypt
VPNWireGuard (wg + ip CLI)
Firewallnftables (nft CLI)
Python3.13+

Quick start

# Clone and install
git clone https://github.com/bartei/wiregui.git
cd wiregui
uv sync

# Start PostgreSQL and Valkey
docker compose up -d

# Run migrations and start
alembic upgrade head
uv run python -m wiregui.main

Open http://localhost:13000 -- an admin account is created automatically on first run (check the logs for the generated password).

Production deployment

# Docker Compose (recommended)
docker compose -f compose.prod.yml up -d

The container runs migrations on startup, manages the WireGuard interface, and requires NET_ADMIN + SYS_MODULE capabilities. See compose.prod.yml for the full configuration including environment variables.

Host networking caveat: when running with --network=host, exclude the WireGuard interface from any host network manager (dhcpcd, systemd-networkd, NetworkManager) — otherwise it may claim the interface and strip its addresses. On NixOS: networking.dhcpcd.denyInterfaces = [ "wg0" ];. WireGUI re-asserts its addresses periodically and logs a warning when it has to restore one, but the host should not be fighting it in the first place.

Environment variables

All settings use the WG_ prefix:

VariableDefaultDescription
WG_DATABASE_URLpostgresql+asyncpg://wiregui:wiregui@localhost/wireguiPostgreSQL connection
WG_REDIS_URLredis://localhost:6379/0Valkey/Redis connection
WG_SECRET_KEYchange-me-in-productionJWT signing + Fernet encryption key
WG_WG_ENABLEDfalseEnable WireGuard interface management
WG_WG_ENDPOINT_HOSTlocalhostPublic endpoint for client configs
WG_WG_ENDPOINT_PORT51820WireGuard listen port
WG_WG_IPV4_NETWORK10.3.2.0/24IPv4 tunnel network
WG_WG_IPV6_NETWORKfd00::3:2:0/120IPv6 tunnel network
WG_ADMIN_EMAILadmin@localhostInitial admin email
WG_ADMIN_PASSWORD(auto-generated)Initial admin password
WG_EXTERNAL_URLhttp://localhost:13000Public-facing URL
WG_IDP_CONFIG_FILE(none)Path to YAML file with OIDC/SAML IdP definitions

Testing

# Unit + integration tests
uv run pytest

# E2E tests (Playwright — requires running PostgreSQL, Valkey, and mock-oidc)
docker compose up -d
uv run pytest tests/e2e/ -v

# E2E in headed mode (watch tests in a browser)
uv run pytest tests/e2e/ --headed --slowmo 300

E2E tests automatically start a WireGUI instance on port 13001 and use Playwright's async API to drive a real Chromium browser. The --headed flag opens a visible browser window and --slowmo adds a delay (in ms) between actions for debugging. The OIDC login flow tests use the mock-oidc service from compose.yml.

IdP provisioning from YAML

Identity providers can be seeded at startup from a YAML file, enabling GitOps and infrastructure-as-code workflows:

WG_IDP_CONFIG_FILE=/etc/wiregui/idps.yaml uv run python -m wiregui.main

See tests/e2e/test_idp_seed.py for the YAML format and seeding behavior.

License

Copyright 2026 Stefano Bertelli / Provvedo

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This means: if you run a modified version of WireGUI as a network service, you must make the source code available to users of that service. No exceptions, no loopholes.

See LICENSE for the full text.

Contributors

bartei81

35 commits

bartei

16 commits

fherbert

3 commits

bartei/wiregui

Firezone Inspired Wireguard VPN Server and nftables Firewall

76

stars

54

commits

Python

primary language

Aug 19, 2026

updated

bartei.github.io/wiregui
nftables
nicegui
vpn
wireguard

README

WireGUI

A self-hosted WireGuard VPN management platform built with Python, NiceGUI, and PostgreSQL.

WireGUI gives you a clean web interface for managing WireGuard peers, firewall rules, and user authentication -- without depending on any third-party cloud service. It's designed for teams and individuals who want full control over their VPN infrastructure.

Against enshittification

This project exists because we believe infrastructure software should serve its users, not its investors. Too many open-source VPN tools have been enshittified -- features locked behind paid tiers, telemetry quietly added, self-hosting made deliberately painful to push you toward a managed offering.

WireGUI is AGPL-licensed specifically to prevent this. If you run it, you own it. If you modify it and offer it as a service, you share the source. No bait-and-switch, no open-core grift, no "community edition" that mysteriously lacks the features you actually need.

Software that manages your network traffic should be fully transparent and fully yours.

Screenshots

DevicesAccount Settings
DevicesAccount Settings
User ManagementFirewall Rules
User ManagementFirewall Rules
Settings & SSO
Settings

See the wiki for full documentation with more screenshots.

Features

  • WireGuard management -- create/delete peers, automatic IP allocation (IPv4 + IPv6), QR codes and .conf downloads
  • Firewall rules -- per-user nftables chains with CIDR, protocol, and port range support
  • Multi-factor auth -- TOTP authenticator apps and WebAuthn security keys
  • SSO -- OpenID Connect and SAML identity providers with auto-provisioning
  • Magic links -- passwordless email login
  • API tokens -- programmatic access via REST API (/api/v0)
  • Dark/light theme -- user preference stored in profile, auto mode follows system
  • VPN session management -- configurable session duration with automatic peer expiry
  • Real-time stats -- live RX/TX counters and handshake tracking
  • Diagnostics -- WAN connectivity checks, peer status, system notifications

Tech stack

LayerTechnology
UINiceGUI (reactive server-side, WebSocket)
APIFastAPI (built into NiceGUI)
ORMSQLModel (SQLAlchemy + Pydantic)
DatabasePostgreSQL (asyncpg)
CacheValkey (Redis-compatible)
MigrationsAlembic
Authauthlib, python-jose, pyotp, webauthn, bcrypt
VPNWireGuard (wg + ip CLI)
Firewallnftables (nft CLI)
Python3.13+

Quick start

# Clone and install
git clone https://github.com/bartei/wiregui.git
cd wiregui
uv sync

# Start PostgreSQL and Valkey
docker compose up -d

# Run migrations and start
alembic upgrade head
uv run python -m wiregui.main

Open http://localhost:13000 -- an admin account is created automatically on first run (check the logs for the generated password).

Production deployment

# Docker Compose (recommended)
docker compose -f compose.prod.yml up -d

The container runs migrations on startup, manages the WireGuard interface, and requires NET_ADMIN + SYS_MODULE capabilities. See compose.prod.yml for the full configuration including environment variables.

Host networking caveat: when running with --network=host, exclude the WireGuard interface from any host network manager (dhcpcd, systemd-networkd, NetworkManager) — otherwise it may claim the interface and strip its addresses. On NixOS: networking.dhcpcd.denyInterfaces = [ "wg0" ];. WireGUI re-asserts its addresses periodically and logs a warning when it has to restore one, but the host should not be fighting it in the first place.

Environment variables

All settings use the WG_ prefix:

VariableDefaultDescription
WG_DATABASE_URLpostgresql+asyncpg://wiregui:wiregui@localhost/wireguiPostgreSQL connection
WG_REDIS_URLredis://localhost:6379/0Valkey/Redis connection
WG_SECRET_KEYchange-me-in-productionJWT signing + Fernet encryption key
WG_WG_ENABLEDfalseEnable WireGuard interface management
WG_WG_ENDPOINT_HOSTlocalhostPublic endpoint for client configs
WG_WG_ENDPOINT_PORT51820WireGuard listen port
WG_WG_IPV4_NETWORK10.3.2.0/24IPv4 tunnel network
WG_WG_IPV6_NETWORKfd00::3:2:0/120IPv6 tunnel network
WG_ADMIN_EMAILadmin@localhostInitial admin email
WG_ADMIN_PASSWORD(auto-generated)Initial admin password
WG_EXTERNAL_URLhttp://localhost:13000Public-facing URL
WG_IDP_CONFIG_FILE(none)Path to YAML file with OIDC/SAML IdP definitions

Testing

# Unit + integration tests
uv run pytest

# E2E tests (Playwright — requires running PostgreSQL, Valkey, and mock-oidc)
docker compose up -d
uv run pytest tests/e2e/ -v

# E2E in headed mode (watch tests in a browser)
uv run pytest tests/e2e/ --headed --slowmo 300

E2E tests automatically start a WireGUI instance on port 13001 and use Playwright's async API to drive a real Chromium browser. The --headed flag opens a visible browser window and --slowmo adds a delay (in ms) between actions for debugging. The OIDC login flow tests use the mock-oidc service from compose.yml.

IdP provisioning from YAML

Identity providers can be seeded at startup from a YAML file, enabling GitOps and infrastructure-as-code workflows:

WG_IDP_CONFIG_FILE=/etc/wiregui/idps.yaml uv run python -m wiregui.main

See tests/e2e/test_idp_seed.py for the YAML format and seeding behavior.

License

Copyright 2026 Stefano Bertelli / Provvedo

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This means: if you run a modified version of WireGUI as a network service, you must make the source code available to users of that service. No exceptions, no loopholes.

See LICENSE for the full text.

Contributors

bartei81

35 commits

bartei

16 commits

fherbert

3 commits

Languages

Python

88.6%

Astro

9.8%