2026-10-21 13:34:25 +01:00
2026-10-16 06:29:21 +01:00
2026-10-21 13:34:25 +01:00
2026-09-12 13:56:36 +01:00
2026-10-21 09:13:59 +01:00
2026-10-21 09:13:59 +01:00
2026-09-12 13:56:36 +01:00
2026-10-21 09:13:59 +01:00
2026-10-21 09:13:59 +01:00
2026-09-12 13:56:36 +01:00

Wireguard UI

An admin dashboard for Wireguard — manage hosts, clients, tunnels, and IP rules through a web interface.

Features

  • Host Management — Create and configure WireGuard hosts with public keys, IP addresses, and listen ports
  • Client Management — Add clients per host with WireGuard configs, allowed IPs, and notes
  • Client Rules — Define IP table rules per client (rule type, destination, ports, protocol)
  • Media Management — Upload and manage media assets (images, documents, etc.) with tagging, thumbnails, and RAG ingestion
  • User Management — Multi-user support with role-based access (user types)
  • Persistent Storage — SQLite database with automatic schema generation
  • WebSocket Support — Real-time updates via WebSocket connections
  • Responsive UI — Tailwind CSS v4 with twui design system components

Prerequisites

  • Bun 1.3.1 or later (install)
  • SQLite (via @moduletrace/bun-sqlite)
  • git
  • zip and unzip
  • Linux (Debian, Ubuntu, Fedora, Arch, Alpine, or similar)
  • Root access (for installation script and system service setup)

Installation

Run the install script on a fresh machine:

curl -fsSL https://url.tben.me/wg-ui | sudo bash

Or clone the repo and run the script manually:

git clone https://git.tben.me/Moduletrace/wireguard-ui.git
cd wireguard-ui
bash src/scripts/install-wg-ui.sh

The install script will:

  1. Install system dependencies (git, curl, ca-certificates, openssl)
  2. Install Bun 1.3.14 to /opt/bun
  3. Set up library directories under /var/lib/wgui (keys, clients, hosts, iptables, scripts)
  4. Clone or update the repo to /var/lib/wgui/webapp
  5. Install app dependencies (bun install)
  6. Generate .env with encryption secrets
  7. Run WireGuard setup (if available)
  8. Install Caddy (/opt/caddy)
  9. Install the wg-quick helper script
  10. Set up systemd/OpenRC services for wgui, wgui-caddy, and certificate renewal

The installer never modifies your firewall — it will print the commands to temporarily allow the dashboard port so you can reach the first login, and then point you to Setup → Firewall for reviewing and removing rules.

Firewall

Firewall rules are managed per host, automatically:

  1. Bootstrap (manual, temporary) — allow the dashboard port so you can reach the web UI once:
    ufw allow 10752/tcp          # ufw (Debian/Ubuntu)
    firewall-cmd --permanent --add-port=10752/tcp && firewall-cmd --reload   # firewalld (RHEL/Fedora)
    
  2. Host creation — every host setup automatically allows its entire wireguard subnet (e.g. 10.5.0.1 → 10.5.0.0/24 from anywhere) and the host's wireguard listen port (e.g. 51821/udp) in ufw or firewalld. Detailed per-client traffic rules are enforced by the existing iptables chain scripts, not the host firewall.
  3. Host deletion — the host's subnet and listen-port rules are removed automatically.
  4. Cleanup — once everything is reachable via the tunnel, remove the temporary bootstrap rule and review all rules under Setup → Firewall:
    ufw delete allow 10752/tcp
    firewall-cmd --permanent --remove-port=10752/tcp && firewall-cmd --reload
    
    Rules that no longer match any host (temporary/orphaned) are flagged with copyable removal commands on the setup page.

TLS for Tunnel Services

Client routes expose internal services to WireGuard clients over HTTPS. The data plane is a dedicated Caddy service (wgui-caddy) on 8443; wg-ui owns the route and certificate records and regenerates the Caddyfile. Caddy never binds ports 80 or 443, and the host's existing proxy is left alone.

  1. If Caddy isn't installed yet, open Setup → TLS ingress and click Install Caddy (or use the Caddy action on Setup → Maintenance). The installer sets up the binary, the wgui-caddy service and certificate support.

  2. Open a route form from Routes (or a host's Routes panel) and set the ACME email and staging toggle. No DNS provider token is needed: certificates use manual DNS-01.

    Let's Encrypt requires a public domain you control; internal-only names such as home.arpa or .local need a private CA instead.

  3. Add an A/AAAA record for each route hostname pointing at the host's WireGuard IP. Caddy also restricts each route to the subnet of the host that owns it.

  4. Open the route page and click Issue (or Renew). The dashboard shows the exact _acme-challenge.<hostname> TXT record. Add it at Cloudflare, wait for propagation, then click Validate.

  5. Clients use https://<hostname>:8443/. Portless URLs require the host's existing 443 proxy to forward to 127.0.0.1:8443; wg-ui does not take over 443. Caddy allows localhost so that proxy can reach it, which means the proxy itself must enforce who may use those portless URLs.

Manual DNS-01 certificates are renewed from the route page because validation needs your registrar. The route list shows expiry warnings. A successful issuance reloads Caddy without restarting wg-ui. Check journalctl -u wgui-caddy for reload failures.

Manual (Development)

git clone https://git.tben.me/Moduletrace/wireguard-ui.git
cd wireguard-ui
bun install
NODE_ENV=development bun run dev

The dev server runs on port 10752 by default.

Configuration

Environment Variables

The .env file (gitignored) controls runtime behavior. It is auto-generated during installation if missing:

Variable Description Default
NODE_ENV Environment (development/production) production
ENCRYPTION_KEY Encryption key for sensitive data Auto-generated
ENCRYPTION_SALT Encryption salt for sensitive data Auto-generated
DATA_DIR Application data directory $INSTALL_DIR/.data
CADDY_HTTPS_PORT Caddy ingress HTTPS port (never 80/443) 8443
CADDY_HTTP_PORT Caddy plain HTTP port (never 80) 8081
CADDY_INGRESS_ENABLED Set to 0 to skip Caddy config sync 1
ACME_STAGING Set to 1 to use the Let's Encrypt staging CA 0

Database Configuration

Edit bun-sqlite.config.ts to change database settings:

const config: BunSQLiteConfig = {
    db_name: "wgui", // Database file name
    db_dir: "./db", // Database directory
    typedef_file_path: "./db/types/db.ts", // Generated types
    db_schema_file_name: "schema.ts", // Schema definition
};

Server Port

The server port is defined in src/data/site-data.ts:

export const SiteData = {
    ServerPort: 10752,
    // ...
} as const;

Available Scripts

Command Description
bun run dev Start development server (requires root)
bun run start Start production server
bun run db:schema Generate/update database schema and types
bun run db:admin Open database admin interface

Project Structure

wireguard-ui/
├── src/
│   ├── pages/              # File-system based routes (__root.tsx, index.tsx, etc.)
│   │   ├── (sections)/     # Page sections
│   │   ├── (partials)/     # Page-local components
│   │   ├── (data)/         # Page-local data
│   │   ├── (functions)/    # Page-local functions
│   │   ├── (utils)/        # Page-local utilities
│   │   └── (hooks)/        # Page-local hooks
│   ├── components/
│   │   ├── twui/           # Local design system (publishable package)
│   │   ├── ui/             # shadcn/ui components
│   │   ├── shadcnblocks/   # shadcnblocks registry components
│   │   └── general/        # Shared page components (chat, date-picker, logo, etc.)
│   ├── hooks/              # Shared React hooks
│   ├── functions/
│   │   ├── backend/        # Server-only: DB queries, email, media upload, RAG
│   │   ├── frontend/       # Client-safe: CRUD handlers, fetch handlers
│   │   └── general/        # Platform-agnostic: join builders
│   ├── utils/              # Utility modules (auth, crypto, CSRF, hashing, etc.)
│   ├── dict/               # Constants and dictionaries (user types, gates, etc.)
│   ├── data/               # Static data (app constants, location data, etc.)
│   ├── types/              # Type definitions
│   ├── scripts/            # Install and setup scripts
│   └── server.ts           # Entry point — starts Bun.serve with WebSocket support
├── db/
│   ├── schema.ts           # Database schema definition
│   └── types/db.ts         # Generated database types
├── public/                 # Static assets served by the server
├── assets/                 # Project assets
├── bun-sqlite.config.ts    # Database configuration
├── bunext.config.ts        # Bunext configuration
├── package.json            # Dependencies and scripts
├── tsconfig.json           # TypeScript configuration
└── .env                    # Environment variables (gitignored)

Database Schema

The database consists of the following tables:

Table Description
users User accounts (name, email, username, password)
user_types User type assignments per user
media Media assets (images, documents, etc.)
media_paradigms Media paradigm classifications per media item
clients WireGuard clients per host
hosts WireGuard host configurations
client_rules IP table rules for each client
client_routes HTTPS routes exposed to WireGuard clients
tls_certificates Certificates used by the Caddy ingress
variables Application-wide key-value variables

Generate types from the schema:

bun run db:schema

Admin Route Hierarchy

Route Pattern Access Features
/admin Admin Dashboard overview
/admin/hosts Admin Host management (add, edit, per-host detail)
/admin/routes Admin Global HTTPS route list with host and certificate status
/admin/hosts/[host_id]/routes Admin HTTPS routes and upstreams exposed to tunnel clients
/admin/hosts/[host_id]/routes/[route_id] Admin Route details, TLS settings and certificate issue/renew
/admin/clients Admin Client management (add, edit, client rules per host)
/admin/settings Admin Account settings
/admin/setup Super admin System setup (hosts, WireGuard tools, update, restart)
/admin/setup/tls Super admin Caddy ingress installation and status

Development

Development Mode

Set NODE_ENV=development and run:

NODE_ENV=development bun run dev

In development mode, the install script skips cloning and system service setup — the server is assumed to already be running.

Path Alias

@/* resolves from the repository root. Examples:

import { Button } from "@/src/components/ui/button";
import type { BUN_SQLITE_WGUI_USERS } from "@/db/types/db";

Type-Checking

Run type checks with:

bunx tsc --noEmit

Testing

Run individual test files:

bun test path/to/test.file.test.ts

Repository

S
Description
A web-based admin dashboard for wireguard
Readme
2 MiB
Languages
TypeScript 83.9%
JavaScript 13.2%
Shell 1.9%
CSS 1%