# WGRplane - WireGuard Remote Plane Control **WGRplane** adalah aplikasi WireGuard Control Plane berbasis Go-native dengan frontend Vue 3. Single binary untuk backend, SPA untuk frontend, dilengkapi dynamic policy firewall dan glassmorphism UI. --- ## Fitur Utama - **Arsitektur Go-Native**: Single Go binary (`main.go`) menangani semua API, database, webhook, scheduler, dan nftables. Tidak ada Python/Flask. - **Peer CRUD Lengkap**: Tambah, edit, hapus peer. Generate QR code untuk import ke mobile client. Export file konfigurasi `.conf`. - **Hybrid Mode**: Mode `forward` (nftables lokal) atau `standalone` (webhook ke server remote). - **2-Column Policy UI**: Kolom "Allow Access" (firewall whitelist CIDR) dan "Allow Internet" (MASQUERADE toggle) per peer. - **Real-time Monitoring**: WebSocket broadcast statistik peer dan trafik setiap 5 detik. - **Automated Scheduling**: Cron job harian untuk hapus peer expired, restriksi peer over-limit, dan reset data usage bulanan. - **Security**: Autentikasi API Key (`wg-rplane-datadunia`), JWT Bearer token, dan TOTP (2FA). - **Webhook Engine**: Integrasi dengan server remote (Mikrotik, dll). Retry dengan exponential backoff, custom headers, Go template. - **Plugin System**: Notifikasi Telegram, Slack, dan Traffic Logger. - **i18n & Themes**: Multi-bahasa (English, Indonesian, Chinese). Dark/Light/Auto mode. - **Glassmorphism UI**: Desain futuristik dengan frosted glass cards, buttons, dan inputs. --- ## Arsitektur ``` wg0.conf (dengan/tanpa #Access) ↓ ┌─────────────────────────────────────────────┐ │ WGRplane (Go Binary :10087) │ │ ┌───────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Gorilla │ │ GORM │ │ nftables │ │ │ │ Mux Router│ │ SQLite │ │ Engine │ │ │ └───────────┘ └──────────┘ └──────────┘ │ │ ┌───────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Webhook │ │ Scheduler│ │ WebSocket│ │ │ │ Engine │ │ Cron │ │ Hub │ │ │ └───────────┘ └──────────┘ └──────────┘ │ │ ┌───────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Auth │ │ SMTP │ │ Plugins │ │ │ │ JWT/TOTP │ │ Email │ │ TG/Slack │ │ │ └───────────┘ └──────────┘ └──────────┘ │ └─────────────────────────────────────────────┘ ↓ HTTP/WebSocket ┌─────────────────────────────────────────────┐ │ Frontend (Vue 3 + TypeScript + Tailwind) │ │ Glassmorphism UI, i18n, Dark/Light mode │ └─────────────────────────────────────────────┘ ``` ### Data Flow Policy Firewall ``` 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 | Komponen | Teknologi | |-----------|------------| | **Backend** | Go, Gorilla Mux, GORM (SQLite via glebarez/sqlite) | | **Frontend** | Vue 3, TypeScript, Vite, TailwindCSS 4, vue-i18n 9 | | **Auth** | JWT (golang-jwt/v5), TOTP (pquerna/otp), API Key | | **WebSockets** | gorilla/websocket | | **Webhooks** | Go net/http dengan retry + exponential backoff | | **Scheduling** | robfig/cron v3 | | **QR Code** | skip2/go-qrcode | | **Email** | jordan-wright/email (SMTP) | | **Firewall** | Bash, iptables, ipset, nftables, inotify-tools, jq | | **Container** | Docker (multi-stage build), docker-compose | --- ## Port & Autentikasi | Service | Port | Autentikasi | |---------|------|---------------| | WGRplane (Go API + Frontend) | **10087** | API Key (`wg-rplane-datadunia`) atau JWT Bearer + TOTP opsional | ### Metode Autentikasi | Metode | Header | Catatan | |--------|--------|---------| | API Key | `wg-rplane-datadunia: ` | Diatur via env var `WG_API_KEY`. Default: `test-api-key`. | | JWT | `Authorization: Bearer ` | Expired 15 menit. Secret via env var `JWT_SECRET`. | | TOTP | `X-TOTP: ` | Wajib jika user mengaktifkan TOTP. | --- ## API Endpoints Semua endpoint dilayani di port `10087`. ### Servers | Endpoint | Method | Deskripsi | |----------|--------|-------------| | `/api/servers` | `GET` | Daftar semua server WireGuard. | | `/api/servers` | `POST` | Buat server baru. Body: `{name, mode, publicKey, endpoint}`. | | `/api/servers/{id}` | `GET` | Ambil satu server berdasarkan ID. | | `/api/servers/{id}` | `PUT` | Update server (name, mode, publicKey, endpoint). | | `/api/servers/{id}` | `DELETE` | Hapus server beserta peer dan webhook-nya. | ### Peers | Endpoint | Method | Deskripsi | |----------|--------|-------------| | `/api/servers/{id}/peers` | `GET` | Daftar semua peer untuk satu server. | | `/api/servers/{id}/peers` | `POST` | Buat peer baru. Body: `{publicKey, ip, allowAccess, allowInternet}`. Mode `forward` langsung apply nftables, mode `standalone` trigger webhook. | | `/api/peers/{id}` | `PUT` | Update peer. Hitung diff dan apply perubahan nftables incremental. | | `/api/peers/{id}` | `DELETE` | Hapus peer. Bersihkan rule nftables dan trigger webhook. | | `/api/peers/{id}/config` | `GET` | Download file konfigurasi WireGuard `.conf`. | | `/api/peers/{id}/qrcode` | `GET` | Generate QR code PNG untuk import ke mobile client. | ### Webhooks | Endpoint | Method | Deskripsi | |----------|--------|-------------| | `/api/servers/{id}/webhooks` | `GET` | Daftar webhook untuk satu server. | | `/api/servers/{id}/webhooks` | `POST` | Buat webhook. Body: `{name, url, template, customBody, customHeaders, subscribedActions, isEnabled, verifySSL}`. | | `/api/webhooks/{id}` | `DELETE` | Hapus webhook. | ### SMTP Settings | Endpoint | Method | Deskripsi | |----------|--------|-------------| | `/api/settings/smtp` | `GET` | Ambil konfigurasi SMTP saat ini. | | `/api/settings/smtp` | `POST` | Simpan/update pengaturan SMTP untuk notifikasi email. | ### Statistics | Endpoint | Method | Deskripsi | |----------|--------|-------------| | `/api/stats` | `GET` | Statistik global: total server, peer, webhook. | | `/api/servers/{id}/stats` | `GET` | Statistik per server: jumlah peer, webhook, detail server. | ### WebSocket | Endpoint | Protokol | Deskripsi | |----------|----------|-------------| | `/ws/stats` | WebSocket | Broadcast statistik real-time (interval 5 detik). | ### TOTP Setup | Endpoint | Method | Deskripsi | |----------|--------|-------------| | `/auth/setup-totp?user=` | `GET` | Generate TOTP secret dan provisioning URI untuk user. | ### Swagger Documentation | Endpoint | Deskripsi | |----------|-----------| | `/swagger/` | Swagger UI untuk dokumentasi API interaktif. | --- ## Hybrid Mode Backend Go mendukung dua mode server: - **`forward`** -- Instance WGRplane langsung apply rule nftables di mesin lokal. Policy peer enforced langsung via perintah `nft`. - **`standalone`** -- Instance bertindak sebagai control plane yang trigger webhook ke server WireGuard remote. Policy enforcement terjadi di sisi remote. ### 2-Column Policy Setiap peer memiliki dua kolom policy independen: | Kolom | Fungsi | |-------|--------| | **AllowAccess** | Daftar CIDR yang bisa dijangkau peer (target internal). | | **AllowInternet** | Boolean flag. Jika `true`, peer mendapat akses internet tanpa batas (MASQUERADE). | Peer yang tidak punya rule apapun terisolasi dari peer lain dan dari internet secara default. --- ## Instalasi ### Opsi 1: Docker Compose (Direkomendasikan) ```bash # Clone repository git clone https://git.datadunia.com/hainzero/WGRplane.git cd 03.wireguard-policy # Start WGRplane dan WireGuard docker compose up -d # Akses dashboard # http://localhost:10087 ``` Stack compose menjalankan: - **WGRplane** di port `10087` (Go API + Vue frontend) - **WireGuard** container dengan host networking untuk akses kernel module ### Opsi 2: Install Script ```bash # Jalankan installer otomatis (Ubuntu/Debian/CentOS) sudo ./install.sh install # Uninstall sudo ./install.sh uninstall ``` Install script menangani instalasi Docker, cloning repository, pembuatan `.env`, dan startup service. ### Opsi 3: Manual Build ```bash # Build binary Go cd app go build -o ../wgrplane . cd .. # Build frontend cd app/frontend npm install && npm run build cd ../.. # Jalankan ./wgrplane # Server start di :10087 ``` ### Opsi 4: Systemd Service ```bash # Install service file sudo cp wgrplane.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable wgrplane.service sudo systemctl start wgrplane.service # Lihat log journalctl -u wgrplane.service -f ``` --- ## Konfigurasi ### Environment Variables | Variable | Default | Deskripsi | |----------|---------|-----------| | `WG_API_KEY` | `test-api-key` | API key untuk autentikasi header-based. | | `JWT_SECRET` | `secret` | Secret untuk signing JWT token. | | `APP_FRONTEND_DIR` | `/var/www/frontend` | Path ke asset frontend yang sudah di-build. | | `WG_RPLANE_MODE` | `forward` | Mode server default (`forward` atau `standalone`). | ### Database WGRplane menggunakan SQLite secara default (`wgrplane.db`). Model auto-migrate saat startup: - **Server** -- Entry server WireGuard dengan mode dan endpoint. - **Peer** -- Entry peer dengan IP, rule akses, limit data, expiry. - **Webhook** -- Konfigurasi webhook dengan template dan filter aksi. - **SMTPSettings** -- Konfigurasi server SMTP untuk notifikasi email. --- ## Scheduler Backend Go menjalankan tiga cron job: | Jadwal | Job | Aksi | |--------|-----|------| | Setiap hari 02:00 | `deleteExpiredPeers` | Hapus peer yang sudah melewati `ExpiresAt`. | | Setiap hari 03:00 | `restrictOverLimitPeers` | Disable peer yang melebihi `DataLimitGB`. | | Tanggal 1 setiap bulan | `resetMonthlyUsage` | Reset `CurrentDataUsageBytes` ke nol untuk semua peer. | --- ## Webhook Payload Webhook trigger pada event lifecycle peer (`peer_created`, `peer_updated`, `peer_deleted`, `policy_changed`). Engine mendukung tiga mode template: `default` (JSON mentah), `mikrotik` (format RouterOS), dan `custom` (Go template). ### Fitur Webhook - **Retry dengan backoff**: Delivery gagal retry hingga 3 kali dengan exponential backoff (2s, 4s, 8s). - **Verifikasi SSL**: Bisa di-toggle per-webhook via `verifySSL`. - **Custom headers**: Inject header per-webhook via `customHeaders` JSON. - **Global webhooks**: Set `isGlobal: true` untuk trigger di semua server. - **Filter aksi**: Subscribe ke event spesifik via array `subscribedActions`. --- ## UI Frontend Frontend adalah Vue 3 + TypeScript SPA dengan desain glassmorphism. ### Design System - **Glassmorphism**: Frosted glass cards, buttons, dan inputs dengan efek backdrop blur. - **TailwindCSS 4**: Utility-first styling dengan dukungan dark mode penuh via `dark:` variants. - **Responsive**: Layout mobile-first yang adaptif di semua ukuran layar. ### Fitur UI | Fitur | Deskripsi | |-------|-----------| | **Multi-bahasa (i18n)** | English, Indonesian, dan Chinese via vue-i18n 9. Locale auto-detect dari browser. | | **Theme Switching** | Dark / Light / Auto (ikuti preferensi sistem) via `@vueuse/core`. | | **Real-time Stats** | Koneksi WebSocket broadcast jumlah peer dan data trafik setiap 5 detik. | | **Charts** | Visualisasi trafik via Chart.js + vue-chartjs. | | **Toast Notifications** | Alert non-intrusif via vue-sonner. | | **QR Code Import** | Generate QR code yang bisa di-scan untuk setup mobile WireGuard client. | ### Struktur Frontend ``` app/frontend/src/ ├── App.vue # Root component dengan provider theme/i18n ├── main.ts # Bootstrap app (Vue, Router, i18n) ├── router/ # Definisi Vue Router ├── i18n/ # File locale (en.json, id.json, zh.json) ├── components/ # Komponen Glass UI (Card, Button, Input, Toggle) ├── composables/ # Vue composables (useTheme, useWebSocket) ├── views/ # Page components (Dashboard, Servers, Peers, Settings, Webhooks) └── types/ # Definisi tipe TypeScript ``` --- ## Policy Firewall (`#Access`) Engine policy berbasis shell enforcing rule firewall per-peer langsung dari `wg0.conf`. ### Cara Kerja 1. Tambahkan komentar `#Access` di bawah setiap blok `[Peer]` di `wg0.conf`. 2. Watcher daemon (`wg-sync-watch.sh`) mendeteksi perubahan file via `inotifywait`. 3. `wg-sync-policy.sh` parse config dan tulis `policy.json` secara atomik. 4. `wg-policy-engine.sh` baca JSON dan apply rule iptables/ipset. ### Contoh `wg0.conf` ```ini [Interface] Address = 10.0.0.1/24 ListenPort = 51820 PrivateKey = 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 = AllowedIPs = 10.0.0.2/32 #Access 192.168.1.10/32, 192.168.12.0/24 [Peer] PublicKey = AllowedIPs = 10.0.0.3/32 #Access 10.0.0.1/32 [Peer] PublicKey = AllowedIPs = 10.0.0.4/32 #Access # Access kosong = internet-only, isolasi client berlaku ``` ### Mengapa `#Access` Bukan `AllowedIPs`? WireGuard menggunakan `AllowedIPs` untuk Cryptokey Routing. Memasukkan IP destinasi di `AllowedIPs` server akan menyebabkan WireGuard meroute traffic untuk IP tersebut ke dalam tunnel client. Komentar `#Access` memisahkan konfigurasi firewall dari routing secara bersih. ### CLI: `wg-policy-ctl` ```bash wg-policy-ctl status # Health check, status lock, jumlah rule wg-policy-ctl policy # Lihat raw policy.json wg-policy-ctl rules # Inspect rule iptables aktif wg-policy-ctl ipset # Lihat mapping ipset wg-policy-ctl reload # Force re-sync dan re-apply wg-policy-ctl log # Lihat log packet dropped wg-policy-ctl stats # Statistik koneksi wg-policy-ctl validate # Validasi schema policy.json ``` ### Prerequisites | Package | Diperlukan | Install | |---------|------------|---------| | `jq` | Ya | `apt install jq` | | `inotify-tools` | Ya (watcher daemon) | `apt install inotify-tools` | | `ipset` | Opsional | `apt install ipset` | Tanpa `ipset`, engine fallback ke entry iptables per-rule. Ini bekerja untuk deployment kecil. Untuk jumlah peer besar, `ipset` memberikan performa lookup O(1). --- ## Plugins Sistem plugin menyediakan interface notifikasi sederhana. Plugin bawaan: - **TelegramNotifier** -- Kirim pesan Telegram saat event. - **SlackNotifier** -- Kirim pesan Slack saat event. - **TrafficLogger** -- Log event traffic untuk debugging. Plugin dimuat saat startup via `PluginManager.LoadPlugins()` dan menerima event melalui `Trigger(event, payload)`. --- ## Struktur Proyek ``` 03.wireguard-policy/ ├── app/ # Go backend + Vue frontend │ ├── main.go # Bootstrap server, routing, init DB │ ├── handlers.go # REST API route handlers │ ├── models.go # GORM models (Server, Peer, Webhook, SMTP) │ ├── auth.go # JWT, TOTP, API key auth middleware │ ├── nftables.go # nftables rule management (mode forward) │ ├── webhook.go # Webhook engine dengan retry/backoff │ ├── scheduler.go # Cron jobs (expiry, data limit, reset) │ ├── stats.go # WebSocket Hub untuk real-time stats │ ├── email.go # Notifikasi email SMTP │ ├── 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) │ ├── docs/ # Swagger documentation │ └── frontend/ # Vue 3 SPA (TypeScript, TailwindCSS) ├── wg-sync-policy.sh # Parse wg0.conf → policy.json ├── wg-policy-engine.sh # Apply policy.json → iptables/ipset ├── wg-sync-watch.sh # inotifywait watcher daemon ├── wg-policy-ctl # CLI wrapper untuk manajemen ├── wg-policy-cleanup.sh # Cleanup script untuk PostDown ├── wg-policy.service # Systemd unit untuk watcher daemon ├── wgrplane.service # Systemd unit untuk Go backend ├── install.sh # Automated installer (Docker + services) ├── Dockerfile # Multi-stage Docker build ├── docker-compose.yml # Docker Compose stack ├── build.sh / build.bat # Script rebuild installer └── README.md # Dokumentasi ini ``` --- ## Testing ### Manual QA ```bash # Test auth (tanpa header) curl http://localhost:10087/api/servers # Expected: 401 Unauthorized # Test auth (header salah) curl -H "wg-rplane-datadunia: wrong" http://localhost:10087/api/servers # Expected: 401 Unauthorized # Test auth (header benar) curl -H "wg-rplane-datadunia: test-api-key" http://localhost:10087/api/servers # Expected: 200 OK, daftar server # Test buat server curl -X POST \ -H "Content-Type: application/json" \ -H "wg-rplane-datadunia: test-api-key" \ -d '{"name":"wg-01","mode":"forward","publicKey":"","endpoint":"vpn.example.com:51820"}' \ http://localhost:10087/api/servers # Test buat peer curl -X POST \ -H "Content-Type: application/json" \ -H "wg-rplane-datadunia: test-api-key" \ -d '{"publicKey":"","ip":"10.0.0.2","allowAccess":["192.168.1.0/24"],"allowInternet":true}' \ http://localhost:10087/api/servers/1/peers # Test QR code curl -H "wg-rplane-datadunia: test-api-key" http://localhost:10087/api/peers/1/qrcode --output peer-qr.png # Verifikasi rule iptables wg-policy-ctl rules ``` --- ## Dokumentasi Tambahan - **Plan File**: `plan.md` (detail rencana implementasi) - **AGENTS.md**: Panduan untuk AI agent dalam mengembangkan proyek ini - **Parent Repo**: `https://git.datadunia.com/hainzero/WGRplane.git` (submodule di `/app`) --- ## Lisensi Proyek ini membangun konsep dari WGDashboard (donaldzou/WGDashboard) dengan modifikasi untuk integrasi policy.json API dan dynamic firewall enforcement.