2026-04-29 07:52:29 +07:00
2026-04-29 07:52:29 +07:00
2026-04-29 07:52:29 +07:00

WGRplane

WireGuard Control Plane with Dynamic Policy Firewall.

WGRplane is a Go-native WireGuard management dashboard paired with a shell-based dynamic iptables/ipset policy engine. It gives you full peer lifecycle management, per-peer firewall policies, webhook integrations, and a glassmorphism-styled Vue 3 frontend.


Overview

WGRplane operates in two complementary layers:

Layer What it does
WGRplane (Go + Vue 3) Web dashboard and REST API for managing WireGuard servers, peers, webhooks, SMTP, and scheduling.
Policy Firewall (Shell) Dynamic iptables/ipset engine that reads #Access comments from wg0.conf to enforce per-peer egress rules.

Hybrid Mode

The Go backend supports two server modes:

  • forward -- The WGRplane instance directly applies nftables rules on the local machine. Peer access policies are enforced immediately via nft commands.
  • standalone -- The instance acts as a control plane that triggers webhooks to remote WireGuard servers. Policy enforcement happens on the remote side.

2-Column Policy

Each peer has two independent policy columns:

Column Purpose
AllowAccess List of CIDRs the peer can reach (internal targets).
AllowInternet Boolean flag. When true, the peer gets unrestricted internet egress.

Peers with neither rule are isolated from each other and from the internet by default.


Architecture

graph TB
    subgraph "WGRplane Dashboard"
        A[Vue 3 Frontend] -->|HTTP/WebSocket| B[Go REST API :10087]
    end

    subgraph "Go Backend"
        B --> C[(SQLite DB)]
        B --> D[Webhook Engine]
        B --> E[Scheduler Cron]
        B --> F[nftables Engine]
        B --> G[SMTP / Email]
        B --> H[Plugin Manager]
    end

    subgraph "Policy Firewall"
        I[wg0.conf #Access] -->|inotifywait| J[wg-sync-watch.sh]
        J --> K[wg-sync-policy.sh]
        K -->|atomic write| L[policy.json]
        L --> M[wg-policy-engine.sh]
        M --> N[iptables / ipset]
    end

    D -.->|peer_created/updated/deleted| O[External Webhooks]
    F -.->|forward mode| N
    E -.->|daily/monthly| P[Peer Lifecycle]

Data Flow

wg0.conf (#Access comments)
    ↓  inotifywait detects change
wg-sync-watch.sh (debounced trigger)
    ↓
wg-sync-policy.sh (parses wg0.conf → policy.json, atomic write)
    ↓
wg-policy-engine.sh (reads policy.json → iptables/ipset rules)
    ↓
Active firewall rules (WG_POLICY chain)

Tech Stack

Component Technology
Backend Go 1.25, Gorilla Mux, GORM (SQLite)
Frontend Vue 3, TypeScript, Vite, TailwindCSS 4, vue-i18n 9
Auth JWT (golang-jwt), TOTP (pquerna/otp), API Key
Webhooks Go net/http with retry + exponential backoff
Scheduling robfig/cron v3
Firewall Bash, iptables, ipset, nftables, inotify-tools, jq
Container Docker (multi-stage build), docker-compose

Quick Start

# Clone the repository
git clone https://git.datadunia.com/hainzero/WGRplane.git
cd 03.wireguard-policy

# Start both WGRplane and WireGuard
docker compose up -d

# Access the dashboard
# http://localhost:10087

The compose stack runs:

  • WGRplane on port 10087 (Go API + Vue frontend)
  • WireGuard container with host networking for kernel module access

Option 2: Install Script

# Run the automated installer (Ubuntu/Debian/CentOS)
sudo ./install.sh install

# Uninstall
sudo ./install.sh uninstall

The install script handles Docker installation, repository cloning, .env creation, and service startup.

Option 3: Manual Build

# Build the Go binary
cd app
go build -o ../wgrplane .
cd ..

# Build the frontend
cd app/frontend
npm install && npm run build
cd ../..

# Run
./wgrplane
# Server starts on :10087

Option 4: Systemd Service

# Install the service file
sudo cp wgrplane.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable wgrplane.service
sudo systemctl start wgrplane.service

# View logs
journalctl -u wgrplane.service -f

API Documentation

All API endpoints are served on port 10087. Authentication is via API key header (wg-rplane-datadunia) or JWT Bearer token with optional TOTP.

Authentication

Method Header Notes
API Key wg-rplane-datadunia: <KEY> Set via WG_API_KEY env var. Default: test-api-key.
JWT Authorization: Bearer <TOKEN> 15-minute expiry. Set secret via JWT_SECRET env var.
TOTP X-TOTP: <CODE> Required if user has TOTP enabled.

Servers

Endpoint Method Description
/api/servers GET List all registered WireGuard servers.
/api/servers POST Create a new server entry. Body: {name, mode, publicKey, endpoint}.
/api/servers/{id} GET Get a single server by ID.
/api/servers/{id} PUT Update server fields (name, mode, publicKey, endpoint).
/api/servers/{id} DELETE Delete a server and cascade-remove its peers and webhooks.

Peers

Endpoint Method Description
/api/servers/{id}/peers GET List all peers for a server.
/api/servers/{id}/peers POST Create a new peer. Body: {publicKey, ip, allowAccess, allowInternet}. Applies nftables rules in forward mode or triggers webhooks in standalone mode.
/api/peers/{id} PUT Update a peer. Computes diffs and applies incremental nftables changes.
/api/peers/{id} DELETE Delete a peer. Cleans up nftables rules and triggers webhooks.
/api/peers/{id}/config GET Download the peer's WireGuard .conf file.
/api/peers/{id}/qrcode GET Get a QR code PNG image of the peer config (for mobile import).

Webhooks

Endpoint Method Description
/api/servers/{id}/webhooks GET List webhooks for a server.
/api/servers/{id}/webhooks POST Create a webhook. Body: {name, url, template, customBody, customHeaders, subscribedActions, isEnabled, verifySSL}.
/api/webhooks/{id} DELETE Delete a webhook.

SMTP Settings

Endpoint Method Description
/api/settings/smtp GET Get current SMTP configuration.
/api/settings/smtp POST Save SMTP settings for email notifications.

Statistics

Endpoint Method Description
/api/stats GET Global stats: total servers, peers, webhooks.
/api/servers/{id}/stats GET Per-server stats: peer count, webhook count, server details.

WebSocket

Endpoint Protocol Description
/ws/stats WebSocket Real-time stats broadcast (5-second interval). Connects to the Hub for live peer/traffic updates.

Webhook Payload Spec

Webhooks are triggered on peer lifecycle events (peer_created, peer_updated, peer_deleted, policy_changed). The engine supports three template modes: default (raw JSON), mikrotik (RouterOS-formatted), and custom (Go template).

Default Payload

{
  "event": "peer_created",
  "timestamp": "2026-05-03T10:30:00Z",
  "server": {
    "id": 1,
    "name": "wg-server-01",
    "mode": "forward",
    "publicKey": "abc123...",
    "endpoint": "vpn.example.com:51820"
  },
  "peer": {
    "id": 2,
    "publicKey": "xyz789...",
    "ip": "10.0.0.2",
    "allowAccess": ["192.168.1.0/24", "10.10.0.0/16"],
    "allowInternet": true,
    "enabled": true,
    "dataLimitGB": 0,
    "expiresAt": "0001-01-01T00:00:00Z"
  },
  "policy": {
    "action": "created",
    "changes": ["peer_created"]
  }
}

Mikrotik Template

{
  "action": "created",
  "peer": {
    "public_key": "xyz789...",
    "ip": "10.0.0.2",
    "allow_access": "[\"192.168.1.0/24\"]",
    "allow_internet": true
  },
  "server": {
    "name": "wg-server-01",
    "mode": "forward"
  }
}

Webhook Features

  • Retry with backoff: Failed deliveries retry up to 3 times with exponential backoff (2s, 4s, 8s).
  • SSL verification: Toggleable per-webhook via verifySSL.
  • Custom headers: Per-webhook header injection via customHeaders JSON.
  • Global webhooks: Set isGlobal: true to fire across all servers.
  • Action filtering: Subscribe to specific events via subscribedActions array.

UI Features

The frontend is a Vue 3 + TypeScript SPA with a glassmorphism design language.

Design System

  • Glassmorphism: Frosted glass cards, buttons, and inputs with backdrop blur effects.
  • TailwindCSS 4: Utility-first styling with full dark mode support via dark: variants.
  • Responsive: Mobile-first layout that adapts to all screen sizes.

Features

Feature Description
Multi-language (i18n) English, Indonesian, and Chinese via vue-i18n 9. Locale auto-detected from browser.
Theme Switching Dark / Light / Auto (follows system preference) via @vueuse/core.
Real-time Stats WebSocket connection broadcasts live peer counts and traffic data every 5 seconds.
Charts Traffic visualization via Chart.js + vue-chartjs.
Toast Notifications Non-intrusive alerts via vue-sonner.
QR Code Import Generate scannable QR codes for quick mobile WireGuard client setup.

Frontend Structure

app/frontend/src/
├── App.vue              # Root component with theme/i18n providers
├── main.ts              # App bootstrap (Vue, Router, i18n)
├── router/              # Vue Router definitions
├── i18n/                # Locale files (en.json, id.json, zh.json)
├── components/          # Glass UI components (Card, Button, Input, Toggle)
├── composables/         # Vue composables (useTheme, etc.)
├── views/               # Page components (Dashboard, Servers, Peers, Settings)
└── types/               # TypeScript type definitions

Policy Firewall (#Access)

The shell-based policy engine enforces per-peer firewall rules directly from wg0.conf.

How It Works

  1. Add #Access comments under each [Peer] block in wg0.conf.
  2. The watcher daemon (wg-sync-watch.sh) detects file changes via inotifywait.
  3. wg-sync-policy.sh parses the config and writes policy.json atomically.
  4. wg-policy-engine.sh reads the JSON and applies iptables/ipset rules.

Example wg0.conf

[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <SERVER_PRIVATE_KEY>

PostUp = /usr/local/bin/wg-sync-policy.sh; /usr/local/bin/wg-policy-engine.sh
PostDown = /usr/local/bin/wg-policy-cleanup.sh

[Peer]
PublicKey = <CLIENT_1_PUBKEY>
AllowedIPs = 10.0.0.2/32
#Access 192.168.1.10/32, 192.168.12.0/24

[Peer]
PublicKey = <CLIENT_2_PUBKEY>
AllowedIPs = 10.0.0.3/32
#Access 10.0.0.1/32

[Peer]
PublicKey = <CLIENT_3_PUBKEY>
AllowedIPs = 10.0.0.4/32
#Access
# Empty Access = internet-only, client isolation applies

Why #Access Instead of AllowedIPs?

WireGuard uses AllowedIPs for Cryptokey Routing. Putting destination IPs in the server's AllowedIPs would cause WireGuard to route traffic for those IPs into the client tunnel. The #Access comment cleanly separates firewall policy from routing configuration.

CLI: wg-policy-ctl

wg-policy-ctl status     # Health check, lock status, rule counts
wg-policy-ctl policy     # View raw policy.json
wg-policy-ctl rules      # Inspect active iptables rules
wg-policy-ctl ipset      # View ipset mappings
wg-policy-ctl reload     # Force re-sync and re-apply
wg-policy-ctl log        # View dropped packet logs
wg-policy-ctl stats      # Connection statistics
wg-policy-ctl validate   # Validate policy.json schema

Prerequisites

Package Required Install
jq Yes apt install jq
inotify-tools Yes (watcher daemon) apt install inotify-tools
ipset Optional apt install ipset

Without ipset, the engine falls back to per-rule iptables entries. This works for small deployments. For large peer counts, ipset provides O(1) lookup performance.


Scheduler

The Go backend runs three background cron jobs:

Schedule Job Action
Daily 2:00 AM deleteExpiredPeers Removes peers past their ExpiresAt date.
Daily 3:00 AM restrictOverLimitPeers Disables peers that exceeded DataLimitGB.
1st of month resetMonthlyUsage Resets CurrentDataUsageBytes to zero for all peers.

Plugins

The plugin system provides a simple notification interface. Built-in plugins include:

  • TelegramNotifier -- Sends Telegram messages on events.
  • SlackNotifier -- Sends Slack messages on events.
  • TrafficLogger -- Logs traffic events for debugging.

Plugins are loaded at startup via PluginManager.LoadPlugins() and receive events through Trigger(event, payload).


Configuration

Environment Variables

Variable Default Description
WG_API_KEY test-api-key API key for header-based authentication.
JWT_SECRET secret Secret for JWT token signing.
APP_FRONTEND_DIR /var/www/frontend Path to built frontend assets.
WG_RPLANE_MODE forward Default server mode (forward or standalone).

Database

WGRplane uses SQLite by default (wgrplane.db). Models auto-migrate on startup:

  • Server -- WireGuard server entries with mode and endpoint.
  • Peer -- Peer entries with IP, access rules, data limits, expiry.
  • Webhook -- Webhook configurations with templates and action filters.
  • SMTPSettings -- SMTP server configuration for email notifications.

Project Structure

03.wireguard-policy/
├── app/                          # Go backend + Vue frontend
│   ├── handlers.go               # REST API route handlers
│   ├── main.go                   # Server bootstrap, routes
│   ├── models.go                 # GORM models (Server, Peer, Webhook, SMTP)
│   ├── auth.go                   # JWT, TOTP, API key auth middleware
│   ├── nftables.go               # nftables rule management (forward mode)
│   ├── webhook.go                # Webhook engine with retry/backoff
│   ├── scheduler.go              # Cron jobs (expiry, data limit, reset)
│   ├── stats.go                  # WebSocket Hub for real-time stats
│   ├── email.go                  # SMTP email notifications
│   ├── plugins.go                # Plugin system (Telegram, Slack, Logger)
│   ├── validation.go             # Input validators (IP, CIDR, PublicKey)
│   ├── wg.go                     # WireGuard key generation, config export
│   ├── i18n.go                   # Backend i18n (en/id/zh)
│   ├── frontend/                 # Vue 3 SPA (TypeScript, TailwindCSS)
│   └── active.{en,id,zh}.json    # Translation files
├── wg-sync-policy.sh             # Parses wg0.conf → policy.json
├── wg-policy-engine.sh           # Applies policy.json → iptables/ipset
├── wg-sync-watch.sh              # inotifywait watcher daemon
├── wg-policy-ctl                 # CLI wrapper for management
├── wg-policy-cleanup.sh          # Cleanup script for PostDown
├── wg-policy.service             # Systemd unit for watcher daemon
├── wgrplane.service              # Systemd unit for Go backend
├── install.sh                    # Automated installer (Docker + services)
├── Dockerfile                    # Multi-stage Docker build
├── docker-compose.yml            # Docker Compose stack
├── build.sh / build.bat          # Installer rebuild scripts
└── README.md                     # This file

License

This project builds upon concepts from WGDashboard (donaldzou/WGDashboard) with modifications for policy.json API integration and dynamic firewall enforcement.

S
Description
No description provided
Readme 1.9 MiB
v1.0.0 Latest
2026-05-08 05:51:48 +07:00
Languages
Shell 87.9%
Batchfile 12.1%