MIT · Linux · Python 3.11+

Web UI for an existing WireGuard host

Reads every *.conf in /etc/wireguard. Peers, Address, and PostUp stay in that file. Writes, then wg syncconf if the interface is up.

  • Does not install WireGuard
  • Does not replace wg-quick
  • Does not generate PostUp / NAT

Scope

Existing configs stay in place

Install on a host that already runs WireGuard. [Interface] keys, PostUp / PostDown, and existing peers stay in the file. You can edit those lines; wg-admin does not invent iptables. Peer apply is wg syncconf when the interface is up.

Behaviour wg-admin
Installs WireGuard No
Replaces wg-quick No
Generates PostUp / NAT No — existing lines are editable in the UI
Reads existing *.conf Yes — every file in /etc/wireguard
Apply while up wg syncconf (no bounce)
Backup before write /var/lib/wg-admin/backups/, restorable from the UI
Disable a peer Commented out with # wg-admin:disabled; block stays in the file

Features

What it does

Reads /etc/wireguard

Every *.conf is listed and edited in place. A comment above a peer (# Alice) is used as the display name.

wg syncconf

Peer changes write the file, then sync if the interface is up. Address and PostUp/PostDown apply on the next wg-quick up, or Restart from the UI.

Server [Interface]

Edit Address, ListenPort, MTU, PostUp, and PostDown in place. PrivateKey stays hidden. No generated iptables.

Peers

Add, rename, edit, disable, rotate keys, remove. New peers get the next free IPv4. Disable comments the block out; it is not deleted.

Existing public keys

Paste a public key the client already has. No client private key is generated or stored.

Client .conf / QR

Available after create or rotate, when the private key is stored here. DNS, AllowedIPs, and endpoint can be overridden per peer.

wg status

Last handshake, transfer, and endpoint. Filter and sort.

Backups

A copy is stored under /var/lib/wg-admin/backups/ before each write. Restore from the UI; the current file is backed up first.

Binds to 127.0.0.1

Put Caddy or nginx with TLS in front if remote access is needed.

Screenshots

Dashboard, peers, QR, first run

Interfaces

Every *.conf in /etc/wireguard is listed. Status comes from wg when the interface is up. Admin password is in the header.

Add a peer

Generate a keypair, or paste an existing public key. Next free IPv4 in the subnet is suggested. QR and .conf are shown after create if the private key is stored here.

Client QR

Shown after create or rotate. Imported peers stay in the file; they have no private key on the server, so no QR.

First run

Existing interface files are loaded as-is. Set an admin password before the UI is usable.

Workflow

Usage

  1. Open an interface

    See peers, last handshake, and transfer. Filter or sort when the list grows. Existing comments become display names.

  2. Add a peer

    Generate keys or paste an existing public key. The next free IPv4 is picked and the server file is written.

  3. Client .conf / QR

    Shown immediately when the private key is stored here. Per-peer DNS, AllowedIPs, and endpoint overrides do not change the interface defaults.

  4. Disable, restore, or restart

    Disable comments the peer out without deleting the block. Restore a backup to undo a write. Restart runs wg-quick down/up so PostUp/PostDown apply.

Files

/etc/wireguard vs state.json

Kept as-is in the .conf

  • [Interface] keys: Address, ListenPort, PrivateKey, PostUp / PostDown, MTU, Table, DNS — editable in the Server panel, not generated
  • Existing [Peer] public keys, AllowedIPs, PSK, keepalive, endpoint
  • Comment above a peer (# Alice or # Name = Alice) used as the display name

Stored in wg-admin state

  • Client-only settings: public endpoint, DNS, client AllowedIPs — in /var/lib/wg-admin/state.json, overridable per peer
  • A backup under /var/lib/wg-admin/backups/ before each write, restorable from the UI
  • Downloadable client files only for peers created or rotated in this UI — WireGuard never stores a client private key on the server
  • Disabled peers commented out with # wg-admin:disabled so wg-quick skips them too

Install

Host must already run WireGuard

Requires Python 3.11+, wireguard-tools (wg), and root — or equivalent access to /etc/wireguard and CAP_NET_ADMIN.

install.sh
git clone https://github.com/logimaxx/wg-admin.git
cd wg-admin
sudo ./install.sh

Then open http://127.0.0.1:8080 and set an admin password. Every *.conf already in /etc/wireguard is listed and managed in place.

Defaults in /etc/wg-admin.env

WG_ADMIN_HOST=127.0.0.1
WG_ADMIN_PORT=8080
WG_ADMIN_CONFIG_DIR=/etc/wireguard
WG_ADMIN_STATE_DIR=/var/lib/wg-admin

Bind is localhost

Default WG_ADMIN_HOST=127.0.0.1. Put Caddy or nginx with TLS in front if remote access is needed. Uninstall leaves WireGuard configs untouched:

sudo ./uninstall.sh