Commit 85cc2200 authored by Hendrik Garske's avatar Hendrik Garske

feat: Vollständige WireGuard Easy Funktionalität implementiert

parent 01c6d240
...@@ -14,8 +14,12 @@ WG Easy ist eine moderne Webanwendung zur Verwaltung von WireGuard VPN-Servern u ...@@ -14,8 +14,12 @@ WG Easy ist eine moderne Webanwendung zur Verwaltung von WireGuard VPN-Servern u
## ✨ Features ## ✨ Features
- 🔐 **Client-Verwaltung**: Erstellen und verwalten Sie VPN-Clients - 🔐 **Client-Verwaltung**: Erstellen, löschen und verwalten Sie VPN-Clients
- 📊 **Dashboard**: Übersicht über aktive Verbindungen und Traffic - 📊 **Dashboard**: Übersicht über aktive Verbindungen und Traffic
- 📥 **Konfigurations-Download**: WireGuard .conf Dateien herunterladen
- 📱 **QR-Code**: QR-Codes für einfache Client-Einrichtung
- 🔌 **Client-Aktivierung**: Clients aktivieren/deaktivieren
- 📈 **Live-Statistiken**: Echtzeit-Traffic-Statistiken
- 🎨 **Modernes Design**: CoreX Design System - 🎨 **Modernes Design**: CoreX Design System
- 🌓 **Dark Mode**: Automatischer Dark/Light Mode - 🌓 **Dark Mode**: Automatischer Dark/Light Mode
- 📱 **Responsive**: Optimiert für alle Geräte - 📱 **Responsive**: Optimiert für alle Geräte
...@@ -37,6 +41,7 @@ WG Easy ist eine moderne Webanwendung zur Verwaltung von WireGuard VPN-Servern u ...@@ -37,6 +41,7 @@ WG Easy ist eine moderne Webanwendung zur Verwaltung von WireGuard VPN-Servern u
- **npm** oder **yarn** oder **pnpm** - **npm** oder **yarn** oder **pnpm**
- **Git** (für Clone) - **Git** (für Clone)
- **Docker & Docker Compose** (optional) - **Docker & Docker Compose** (optional)
- **wg-easy Backend**: WireGuard Easy Docker Container (siehe Setup unten)
## 🚀 Installation ## 🚀 Installation
...@@ -53,7 +58,38 @@ cd wg-easy ...@@ -53,7 +58,38 @@ cd wg-easy
npm install npm install
``` ```
### 3. Development Server starten ### 3. WireGuard Easy Backend starten
```bash
docker run -d \
--name=wg-easy \
-e WG_HOST=YOUR_SERVER_IP \
-e PASSWORD=YOUR_PASSWORD \
-v ~/.wg-easy:/etc/wireguard \
-p 51820:51820/udp \
-p 51821:51821/tcp \
--cap-add=NET_ADMIN \
--cap-add=SYS_MODULE \
--sysctl="net.ipv4.conf.all.src_valid_mark=1" \
--sysctl="net.ipv4.ip_forward=1" \
--restart unless-stopped \
weejewel/wg-easy
```
### 4. Umgebungsvariablen konfigurieren (Optional)
Erstellen Sie eine `.env.local` Datei:
```env
WG_API_URL=http://localhost:51821
WG_PASSWORD=YOUR_PASSWORD
```
**Standardwerte:**
- `WG_API_URL`: `http://localhost:51821`
- `WG_PASSWORD`: leer (falls kein Passwort gesetzt)
### 5. Development Server starten
```bash ```bash
npm run dev npm run dev
......
import { NextRequest, NextResponse } from "next/server"
import { wgApi } from "@/lib/wg-api"
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const { id } = await params
const config = await wgApi.getClientConfig(id)
return new NextResponse(config, {
headers: {
'Content-Type': 'text/plain',
'Content-Disposition': `attachment; filename="wg-${id}.conf"`,
},
})
} catch (error) {
console.error("Error fetching client config:", error)
const errorMessage = error instanceof Error ? error.message : "Failed to fetch config"
return NextResponse.json(
{ error: errorMessage },
{ status: 500 }
)
}
}
import { NextRequest, NextResponse } from "next/server"
import { wgApi } from "@/lib/wg-api"
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const { id } = await params
const qrCode = await wgApi.getClientQR(id)
return new NextResponse(qrCode, {
headers: {
'Content-Type': 'image/svg+xml',
},
})
} catch (error) {
console.error("Error fetching QR code:", error)
const errorMessage = error instanceof Error ? error.message : "Failed to fetch QR code"
return NextResponse.json(
{ error: errorMessage },
{ status: 500 }
)
}
}
import { NextRequest, NextResponse } from "next/server"
import { wgApi } from "@/lib/wg-api"
export async function DELETE(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const { id } = await params
await wgApi.deleteClient(id)
return NextResponse.json({ success: true })
} catch (error) {
console.error("Error deleting client:", error)
const errorMessage = error instanceof Error ? error.message : "Failed to delete client"
return NextResponse.json(
{ error: errorMessage },
{ status: 500 }
)
}
}
export async function PUT(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const { id } = await params
const body = await request.json()
const { enabled } = body
if (enabled === true) {
await wgApi.enableClient(id)
} else if (enabled === false) {
await wgApi.disableClient(id)
} else {
return NextResponse.json(
{ error: "enabled field is required (true/false)" },
{ status: 400 }
)
}
return NextResponse.json({ success: true })
} catch (error) {
console.error("Error updating client:", error)
const errorMessage = error instanceof Error ? error.message : "Failed to update client"
return NextResponse.json(
{ error: errorMessage },
{ status: 500 }
)
}
}
import { NextRequest, NextResponse } from "next/server"
import { wgApi } from "@/lib/wg-api"
export async function GET() {
try {
const clients = await wgApi.getClients()
return NextResponse.json(clients)
} catch (error) {
console.error("Error fetching clients:", error)
const errorMessage = error instanceof Error ? error.message : "Failed to fetch clients"
return NextResponse.json(
{ error: errorMessage },
{ status: 500 }
)
}
}
export async function POST(request: NextRequest) {
try {
const body = await request.json()
const { name, allowedIPs } = body
if (!name || typeof name !== 'string' || name.trim() === '') {
return NextResponse.json(
{ error: "Client name is required" },
{ status: 400 }
)
}
const client = await wgApi.createClient({
name: name.trim(),
allowedIPs: allowedIPs || undefined,
})
return NextResponse.json(client, { status: 201 })
} catch (error) {
console.error("Error creating client:", error)
const errorMessage = error instanceof Error ? error.message : "Failed to create client"
return NextResponse.json(
{ error: errorMessage },
{ status: 500 }
)
}
}
import { NextResponse } from "next/server"
import { wgApi } from "@/lib/wg-api"
export async function GET() {
try {
const stats = await wgApi.getStats()
return NextResponse.json(stats)
} catch (error) {
console.error("Error fetching stats:", error)
const errorMessage = error instanceof Error ? error.message : "Failed to fetch stats"
return NextResponse.json(
{ error: errorMessage },
{ status: 500 }
)
}
}
This diff is collapsed.
// WireGuard Easy API Client
const WG_API_URL = process.env.WG_API_URL || 'http://localhost:51821'
const WG_PASSWORD = process.env.WG_PASSWORD || ''
interface WgClient {
id: string
name: string
enabled: boolean
address: string
publicKey: string
createdAt: string
updatedAt: string
latestHandshakeAt: string
transferRx: number
transferTx: number
persistentKeepalive: string
}
interface WgServer {
address: string
listenPort: number
publicKey: string
endpoint: string
dns: string
allowedIPs: string
createdAt: string
}
interface WgStats {
clients: WgClient[]
server: WgServer
}
interface CreateClientRequest {
name: string
allowedIPs?: string
}
interface CreateClientResponse {
id: string
name: string
config: string
qrCode: string
}
export class WgApiClient {
private baseUrl: string
private password: string
constructor(baseUrl: string = WG_API_URL, password: string = WG_PASSWORD) {
this.baseUrl = baseUrl.replace(/\/$/, '')
this.password = password
}
private async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
const url = `${this.baseUrl}${endpoint}`
const headers = {
'Content-Type': 'application/json',
...options.headers,
}
// Add basic auth if password is set
if (this.password) {
headers['Authorization'] = `Basic ${Buffer.from(`:${this.password}`).toString('base64')}`
}
const response = await fetch(url, {
...options,
headers,
})
if (!response.ok) {
const errorText = await response.text()
throw new Error(`WG API Error: ${response.status} ${errorText}`)
}
return response.json()
}
async getStats(): Promise<WgStats> {
return this.request<WgStats>('/api/sessions')
}
async getClients(): Promise<WgClient[]> {
const stats = await this.getStats()
return stats.clients || []
}
async getServer(): Promise<WgServer> {
const stats = await this.getStats()
return stats.server
}
async createClient(data: CreateClientRequest): Promise<CreateClientResponse> {
return this.request<CreateClientResponse>('/api/users', {
method: 'POST',
body: JSON.stringify(data),
})
}
async deleteClient(id: string): Promise<void> {
await this.request(`/api/users/${id}`, {
method: 'DELETE',
})
}
async enableClient(id: string): Promise<void> {
await this.request(`/api/users/${id}/enable`, {
method: 'PUT',
})
}
async disableClient(id: string): Promise<void> {
await this.request(`/api/users/${id}/disable`, {
method: 'PUT',
})
}
async getClientConfig(id: string): Promise<string> {
const response = await fetch(`${this.baseUrl}/api/users/${id}/configuration`, {
headers: this.password ? {
'Authorization': `Basic ${Buffer.from(`:${this.password}`).toString('base64')}`
} : {},
})
if (!response.ok) {
throw new Error(`Failed to get config: ${response.status}`)
}
return response.text()
}
async getClientQR(id: string): Promise<string> {
const response = await fetch(`${this.baseUrl}/api/users/${id}/qr-code`, {
headers: this.password ? {
'Authorization': `Basic ${Buffer.from(`:${this.password}`).toString('base64')}`
} : {},
})
if (!response.ok) {
throw new Error(`Failed to get QR code: ${response.status}`)
}
return response.text()
}
}
export const wgApi = new WgApiClient()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment